Skip to Content
Working with the codebaseAge rating & content rights

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.

declarations.config.json
{ "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 asc installed
  • 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.

AnswerWhat you are saying
DOES_NOT_USE_THIRD_PARTY_CONTENTNothing in the app is licensed from someone else
USES_THIRD_PARTY_CONTENTThere 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:

AnswerWhy
user-generated-contentA model that can return unfiltered text is user-generated content as far as Apple is concerned
messaging-and-chatThe 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.mjs

It 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:

declarations.config.json
"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 --push

Verify

asc age-rating view --app "$ASC_APP_ID" --output table

Age-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.

play.config.json
"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.

Last updated on