# Conflicts: # CHANGELOG.md # docs/pitfalls.md # skills/store-pitfalls/SKILL.md # tests/console-fill.test.ts
8.2 KiB
8.2 KiB
| name | description |
|---|---|
| store-declarations | Answer the store compliance forms for a mobile app or game - Google Play Data safety (API CSV), App content declarations (ads, app access, content rating IARC, target audience, advertising ID, government/financial/health/news), App Store App Privacy nutrition labels, age rating, export compliance. Use when the user fills in data safety, privacy labels, content rating, target audience, ads or advertising ID declarations, or gets Data safety CSV import errors. |
Store declarations
storebound scan proposes the Data safety and App Privacy answers from the detected SDKs and code (each item "detected (file:line)" or "ask owner") as a diff against dataSafety / appPrivacy; --write adds only the detected ones after the owner agrees.
Templates: store/declarations.md (Play App content + IARC answers), store/app-privacy.md (Apple labels), both
from storebound init --profile app|game|subscription-app (default app). They are honest starting points for a
typical app of that kind, not your answers: edit every line to match what your app really does. Data safety answers live in dataSafety of storebound.config.ts.
CLI: storebound (or bunx storebound in a project that has it, or bun <toolchain>/cli/index.ts).
Order
- Inventory first. List every SDK and server call: what leaves the device, who receives it, can the user turn
it off. The privacy policy (
privacy-policyskill) must say the same; update it before the forms. - Play Data safety (API). Fill
dataSafety(types not listed = not collected;shared= third party that is not your service provider, e.g. ad networks; analytics vendors acting as processors are "collected" only).storebound play data-safety --dry --csv store/data-safety.csvto review, thenstorebound play data-safety. Play cannot read the form back: storebound keeps the hash of the last upload in.storebound/data-safety.sha256and skips an unchanged CSV. After a hand edit in Play Console,--forcesends the config's answers again. Then check the summary in Play Console > Policy and programs > App content > Data safety. - Play App content (UI). Policy and programs > App content, each card with
store/declarations.md: privacy policy, app access, ads, content rating (IARC questionnaire), target audience and content, news, COVID-19, data safety, government apps, financial features, health, advertising ID. - Apple age rating (API).
storebound apple appinfo(all NONE except your overrides, e.g.advertising: true). - Apple App Privacy (UI only). App Store Connect > the app > App Privacy > Get Started / Edit, from
store/app-privacy.md; per data type: purposes > linked to identity > used for tracking. Then Publish.- Purposes follow Apple's definitions (developer.apple.com/app-store/app-privacy-details/), one per Play purpose:
Play
advertising(ads from an ad SDK) is Third-Party Advertising only, never also Developer's Advertising or Marketing (that one is first-party ads or marketing to your own users: the owner's answer);analyticsis Analytics (not Product Personalization);personalizationis Product Personalization; functionality, fraud, account andcommunicationsare App Functionality (marketing messages: ask the owner). - The owner's answers go into
appPrivacy.types, keyed by Apple's type id (USER_ID, DEVICE_ID, GAMEPLAY_CONTENT, ADVERTISING_DATA, CUSTOMER_SUPPORT, ENVIRONMENT_SCANNING, HANDS, HEAD ... all 35 incli/lib/app-privacy.ts):
Purposes: THIRD_PARTY_ADVERTISING, DEVELOPERS_ADVERTISING, ANALYTICS, PRODUCT_PERSONALIZATION, APP_FUNCTIONALITY, OTHER_PURPOSES. A set field wins over what storebound derives fromappPrivacy: { tracking: true, types: { DEVICE_ID: { collected: true, linked: false, tracking: true, purposes: ['THIRD_PARTY_ADVERTISING', 'ANALYTICS'] }, ADVERTISING_DATA: { collected: true, linked: false, tracking: true, purposes: ['THIRD_PARTY_ADVERTISING'] }, GAMEPLAY_CONTENT: { collected: false }, } },dataSafety; types with no Play equivalent (Advertising Data, Gameplay Content, Customer Support, Environment Scanning, Hands, Head) are answered only here.scan --writeproposescollected+purposesfor detected types the block does not answer yet;linkedandtrackingare never proposed (ask the owner).storebound checkcompares the block with the iOS project: tracking true <->NSUserTrackingUsageDescriptionandNSPrivacyTrackingtrue; the app'sNSPrivacyCollectedDataTypes<-> the types marked collected (mismatches both ways).
- Purposes follow Apple's definitions (developer.apple.com/app-store/app-privacy-details/), one per Play purpose:
Play
- Export compliance.
export-complianceskill (ITSAppUsesNonExemptEncryptionin Info.plist,apple encryption). - Privacy manifest (iOS).
privacy-manifestskill; keep it consistent with App Privacy.
Typical answers per profile (starting points, edit to match your app)
- app (utility / productivity, optional account, analytics, no ads): Data safety: email + user ids (account,
collected, functionality + account management), app interactions and diagnostics (analytics SDK as your processor:
collected, not shared), crash logs. Encrypted in transit: yes. Deletion: yes (in the app and on the web, see
account-deletion). Account creation: the methods you offer (e.g.PSL_ACM_USER_ID_PASSWORD,PSL_ACM_OAUTH). Ads: No. Advertising ID: No (unless an SDK reads it). App access: sign-in needed, demo account given (review-access). IARC category: not a game (utility, productivity, communication or social, reference ...). Apple: Contact Info > Email Address and Identifiers > User ID are linked to the user (account), not used for tracking. - subscription-app: as
app, plus Purchases > Purchase History (linked, App Functionality) and PlayPSL_PURCHASE_HISTORY(collected, functionality). IARC: digital purchases Yes. App Review: subscriptions and their disclosure (store-subscriptions). - game (single-player free-to-play with ads + IAP, no accounts): approximate location (IP country; shared, analytics + ads + fraud), app interactions (shared, analytics + ads), other app activity (save backup, functionality), diagnostics (shared), device or other IDs (shared, ad id), purchase history (if your server checks receipts). Encrypted in transit: yes. Deletion: yes, by email. Account creation: none. IARC (for games): everything No except digital purchases Yes; target audience 13+; ads Yes; advertising ID yes (advertising, analytics, fraud prevention); sign-in details: no login needed.
Gotchas
- The Data safety CSV import replaces the whole form.
PSL_SUPPORTED_ACCOUNT_CREATION_METHODS(e.g.PSL_ACM_NONE) is required even though Google's older sample CSV omits it: without it the import fails with "Response missing". storebound always writes it.- "Optional" data is only allowed when the user can really choose for that data; otherwise required.
- Ads SDKs: read each network's own Play data safety guidance; adding a network can add data types.
- Target audience under 13 pulls the app into the Families policy (certified ad networks, no ad id): only if true.
- Apple: "linked to the user" is No when there are no accounts and nothing ties data to a name / email / phone; with accounts, what you store under the account is linked.
- Accounts: Play asks for a delete-account URL in Data safety and Apple wants deletion inside the app
(
account-deletionskill). - Accounts are not email. A guest / username account (a name picked on the device, a server token, no password, no
email) is User ID only (Play
PSL_USER_ACCOUNT, Apple Identifiers > User ID) and account creation "Username and other authentication" (PSL_ACM_USER_ID_OTHER_AUTH): setaccounts.signUp: ['username'].storebound scanmarks Email "detected" only for an email field, anemailproperty in a request or schema, an email validation or endpoint, an email sign-in call, an SDK that collects it (Google / Apple / Firebase sign-in) orsignUp: ['email-…']; built bundles (dist, build, the Capacitor webDir, minified files) only make it a question. - App Privacy saved but not published = not submitted.
- Keep store answers, the privacy policy and the in-app privacy settings consistent; reviewers compare them.