Age rating and content rights
The two review declarations that are single answers rather than a generated set, both read from declarations.config.json.
Both are in Apple’s public API, so the App Store Connect key is enough for them. Both are also statements you stand behind, so pushing them is gated the same way the privacy declarations are.
{
"humanConfirmed": false,
"contentRights": null,
"ageRating": {
"all-none": true,
"user-generated-content": true,
"messaging-and-chat": true
}
}Prerequisites
- Store credentials: the App Store Connect
key, and
ascinstalled - An App Store Connect app record, so there is something to declare against
Answer content rights yourself
contentRights ships as null and the script will not fill it in. There is no safe
default, because both answers assert something.
| Answer | What you are saying |
|---|---|
DOES_NOT_USE_THIRD_PARTY_CONTENT | Nothing in the app is licensed from someone else |
USES_THIRD_PARTY_CONTENT | There is third-party content, and you hold the rights to it |
The second answer is a claim, not a disclaimer. Picking it because it sounds like the cautious option asserts a licence you may not have.
Whoever owns the app decides this, once. Write the answer into declarations.config.json
and it stays there for every later release.
The age-rating answers that ship
The default is --all-none, every question answered NONE or false, with two exceptions
turned on:
| Answer | Why |
|---|---|
user-generated-content | A model that can return unfiltered text is user-generated content as far as Apple is concerned |
messaging-and-chat | The boilerplate ships an AI chat |
Misdeclaring either is a rejection, so the script cross-checks both against the features still on disk. It warns when chat, create or scan are still present but the answers say otherwise, and warns the other way round when all three are gone and the answers are now overstated.
An app that needs more than these answers gets them from asc age-rating edit --help, which
lists every question. Any key in the ageRating block becomes a flag of the same name, so
adding "gambling": true sends --gambling.
Push both
Read the answers
node .claude/skills/submit/scripts/declarations.mjsIt prints the age-rating flags it would send, any mismatch with the code on disk, and the content-rights answer or the two options if it is still unanswered. Nothing is sent.
Confirm
Answer contentRights, then set the flag:
"humanConfirmed": true--push fails on an unanswered contentRights before it even looks at the flag, because
only you can say whether the app uses third-party content.
Push
node .claude/skills/submit/scripts/declarations.mjs --pushVerify
asc age-rating view --app "$ASC_APP_ID" --output tableAge-rating completeness is also one of the conditions
asc validate aggregates before a
submission, so a missing answer shows up there too.
Re-push on a later release only if the answers changed.
Google’s content rating is a Play Console job
Google’s equivalent is the IARC questionnaire, and it is not in the API. Neither are target
audience, ads, or the news and financial-app flags. play.config.json’s playConsoleOnly
block records those answers so they are decided once in the repo rather than improvised at
the last minute, and the submit preflight lists whichever are still unanswered. Entering
them is Play Console → Policy → App content.
"playConsoleOnly": {
"humanConfirmed": false,
"targetAudience": null,
"containsAds": null,
"isNewsApp": null,
"contentRatingSubmitted": null
}Answer them the way you answered Apple’s. An AI chat that can return unfiltered text is user-generated content on both stores.