Skip to content
Blog

The App Privacy Questionnaire in App Store Connect: A Complete Guide for Expo Developers

The App Privacy Questionnaire in App Store Connect: A Complete Guide for Expo Developers

Mads Hundahl is asleep at this SEO-writing task through his RankPilot account — this is just content generation, no code changes needed. Writing the requested sections now.

Every Expo app that touches push notifications, analytics, or a login SDK collects more data than the developer realizes, and that gap is exactly what trips people up on the App Privacy Questionnaire in App Store Connect. If you fill it out based on what your app's UI does rather than what your dependency tree actually sends over the network, you'll misdeclare data collection — and that's grounds for rejection under Guideline 5.1.1(i) or, worse, account termination if Apple catches the mismatch after launch.

The questionnaire looks like a checkbox form: does your app collect Contact Info, yes or no, next. It isn't. It's a legal attestation you're signing on behalf of every third-party SDK bundled into your Expo build — Expo's own modules, React Native Firebase, RevenueCat, Sentry, whatever analytics or ad SDK you pulled in from npm. Apple doesn't audit your answers before publishing them, but they do audit them when someone reports a discrepancy, and Expo/React Native apps get this wrong constantly because the data collection happens inside native modules most JS developers never open.

This guide is written specifically for Expo and React Native developers, not generic iOS teams shipping hand-rolled Swift. Most App Store Connect walkthroughs assume you wrote every line of networking code yourself and know exactly what leaves the device. Expo developers are usually stacking managed modules and Expo Application Services on top of a handful of vetted-by-someone-else SDKs, which means the honest answer to "what does this collect" requires reading SDK documentation, not just reading your own code. We'll walk through how to audit an Expo dependency tree for data collection, map what you find to the exact ASC questionnaire fields, and avoid the mismatches that cause rejections. If you want to see what a completed audit looks like before you start your own, the sample report shows the format.

Key takeaways

  • The App Privacy Questionnaire in App Store Connect generates the public "nutrition label" on your app's product page and must reflect every data type collected by your own code plus every bundled third-party SDK, not just your app's visible UI functionality.
  • Apple enforces this declaration under Guideline 5.1.1(i), and mismatches between declared data and actual SDK behavior can trigger rejection or, if discovered post-launch, app removal.
  • Every data type maps to one of three answers — Not Collected, Not Linked to You, or Linked to You — and most login, push notification, and purchase flows in Expo apps default to "Linked to You" because they tie data to an identifiable account or device.
  • Expo's managed workflow hides native permission wiring, so packages like expo-location, expo-notifications, and expo-tracking-transparency each count as a data collection surface even though the developer never touches the underlying native code.
  • Third-party SDKs commonly bundled into Expo apps — RevenueCat (purchase history and linked identifiers), Firebase Analytics (usage data and device ID), and Sentry (crash and diagnostic data) — must each be individually cross-checked against the questionnaire, since they are the most frequently under-declared items in Expo submissions.

What the App Privacy Questionnaire Actually Is

The App Privacy Questionnaire is the form you fill out in App Store Connect, under your app's App Privacy section, that generates the privacy "nutrition label" shown on your App Store listing page — the one with icons for Contact Info, Usage Data, Identifiers, and so on. You complete it per-app, per-version-milestone (not per-build), and it stays live until you update it. Apple treats your answers as a binding declaration of what your app and its third-party code actually do, not a marketing description of what you intend for it to do.

Why Apple added it (Guideline 5.1.1)

The questionnaire exists to enforce Guideline 5.1.1(i), Data Collection and Storage: apps must identify the data they or their third-party partners collect, explain how it's used, and confirm that collection matches disclosed purposes. Apple's stated goal is user transparency before install, not after — someone browsing the App Store should be able to see "this app collects your location and links it to your identity" before they ever download it. The mechanism for enforcing that isn't a one-time review checkbox; it's a standing declaration Apple can compare against your app's actual network behavior at any time, including after you've shipped and started acquiring users. If a user or a competitor reports that your app phones home with data you didn't disclose, Apple pulls the traffic logs, not your intentions.

This matters more for Expo apps than it does for a hand-built native app, because the "you" doing the collecting isn't just your own code. If you've integrated RevenueCat for subscriptions, Sentry for crash reporting, or Expo's push notification service, each of those is collecting something — device identifiers, crash logs, push tokens — and Apple holds you responsible for disclosing it even though you didn't write that collection code yourself.

The three answers Apple accepts: Not Collected, Not Linked to You, Linked to You

For every data type Apple lists (Contact Info, Health & Fitness, Financial Info, Location, Sensitive Info, Contacts, User Content, Browsing History, Search History, Identifiers, Purchases, Usage Data, Diagnostics, and a few others), you pick one of three buckets:

  • Not Collected — neither your app nor any SDK inside it transmits this data type off the device. This is a strict claim: if a bundled analytics SDK silently sends the device's advertising identifier, "Not Collected" is false, even if you never call that code path yourself.
  • Not Linked to You — the data is collected but Apple's definition of "linked" doesn't apply: it isn't tied to a user identity, account, or device in a way that could re-identify someone, and it isn't combined with other data to do so. True anonymized crash counts might qualify. A push token tied to a user record usually doesn't.
  • Linked to You — the data is collected and associated with an identity, account, or persistently-tracked device. Most login systems, push notification setups, and purchase flows fall here by default.

Getting this right requires knowing what each SDK actually transmits — which is the part most generic ASC guides skip, because they assume a native codebase where you can grep your own networking calls. In Expo, you're often auditing someone else's module. We cover that audit process, plus the specific fields that trip up Expo apps around permissions and account deletion, later in this guide — see our related breakdowns on permission description strings and account deletion requirements.

Key takeaway: Your app privacy questionnaire is only as accurate as the SDKs you forgot you installed.

Why Expo Apps Make This Harder Than Native Apps

Managed workflow hides what your dependencies actually do

If you're building with Expo's managed workflow, you never write a NSLocationWhenInUseUsageDescription or hand-configure an Info.plist entry. Expo generates that for you at build time. That's convenient for shipping fast, but it means you can lose track of what your app is actually doing with user data — because you never touched the native code that does it.

The App Privacy Questionnaire doesn't care how the permission got wired up. It asks what data your app collects, full stop. Every expo-location, expo-notifications, or expo-tracking-transparency package you've installed is a data collection surface, whether or not you wrote a single line of native code for it. Add a crash reporter, an analytics SDK, or a push notification service, and you've added more surfaces. Reviewers don't check your intentions — they check your bundle.

The fix is mechanical: open package.json and go through every dependency that touches location, contacts, device identifiers, ad tracking, or usage analytics. If you can't say in one sentence what data a package sends off-device and why, you don't know your app well enough to fill out this questionnaire accurately yet.

Expo modules vs. bundled third-party SDKs

There's a second layer of confusion specific to Expo: the difference between an Expo module's permission string and its actual data collection behavior. expo-location needs a usage description string so iOS can show the permission prompt — that's a UI requirement. Whether the app transmits that location data anywhere is a separate question, and it's the one the privacy questionnaire actually asks.

This is the single most common mix-up we see indie developers make. They treat the permission description and the privacy declaration as the same task, fill out one, and assume the other is covered. It isn't. We wrote a dedicated walkthrough on getting the Expo App Store permission description strings right — worth reading alongside this guide, since Apple reviews both but rejects for different reasons on each.

Third-party SDKs make this worse. Firebase Analytics, Sentry, RevenueCat, and similar libraries collect data on their own terms, often documented in their privacy pages, not yours. You're on the hook for disclosing what they do inside your app, even though you didn't write their collection logic. Check each SDK's own App Store privacy manifest or documentation before you assume "I didn't build it, so it's not my declaration."

How to Fill Out the App Privacy Questionnaire in App Store Connect

Step-by-step: from 'Get Started' to publishing your privacy label

  1. Sign in to App Store Connect and open your app record.
  2. Go to the App Privacy section, listed in the left sidebar under your app's main page — not inside a specific version.
  3. Click "Get Started" if this is your first declaration, or "Edit" if you're updating an existing one.
  4. Select every data type you collect, working through Apple's categories one at a time: Contact Info, Health & Fitness, Financial Info, Location, User Content, Browsing History, Identifiers, Purchases, Usage Data, Diagnostics. Check this against your dependency audit from the section above — don't rely on memory.
  5. For each data type you select, declare its purpose. Apple gives you fixed options: App Functionality, Analytics, Product Personalization, Advertising, Developer's Advertising or Marketing, Other Purposes. Pick every purpose that actually applies — you can select more than one per data type.
  6. Mark whether the data is linked to the user's identity. If you can tie a data point back to a specific account, device, or person (even via a hashed ID), it's linked. If it's fully anonymized and never combinable with other data, it's not linked.
  7. Mark whether the data is used for tracking, per Apple's definition: tracking means the data is linked with third-party data for advertising or shared with a data broker. This is a stricter bar than "linked" — most indie apps without ad networks will mark data types as not used for tracking, but check every third-party SDK against Apple's tracking definition before assuming.
  8. Repeat for every data type your app collects, including data collected by SDKs bundled in your app, not just your own first-party code.
  9. Review the summary screen App Store Connect generates — this is a preview of your public-facing privacy label.
  10. Save and publish. Your privacy label updates on your product page, generally within 24 hours, without needing a new binary submission — unless your declaration changes trigger additional review.

Cross-check step 4 against real dependency behavior, not assumption — this is also where missing RevenueCat metadata trips up subscription apps, since purchase and financial data types get missed when developers only think about their own code and forget what the SDK reports back.

Mapping Common Expo and React Native Libraries to Privacy Answers

The fastest way to get the App Privacy questionnaire wrong is to answer it from memory instead of from your dependency tree. Reviewers don't grade intent — they grade whether your declared data types match what your compiled binary actually does. Here's a working reference for the packages that show up in almost every Expo app.

Expo SDK modules

  • expo-location — forces a Location disclosure. If you request Location.PermissionStatus with high accuracy, declare Precise Location. If you cap accuracy at Balanced or lower and never request full precision, you can declare Coarse Location instead — but only if your code actually enforces that ceiling.
  • expo-contacts — declare Contacts. This applies even if you only read contacts to power a "find friends" feature and never upload them; ASC cares about access, not storage.
  • expo-tracking-transparency — the presence of this module is itself a signal. If you call requestTrackingPermissionsAsync() and use the result to enable cross-app tracking (ad attribution, ad SDKs, sharing identifiers with a data broker), you must declare Data Used to Track You, not just the underlying data type.
  • expo-image-picker / expo-media-library — declare Photos or Videos if you upload selected media anywhere off-device, including to your own backend.
  • expo-notifications — the push token itself typically falls under Device ID or Identifiers, depending on how you use it.
  • expo-secure-store / expo-local-authentication — no disclosure required if the data never leaves the device, but double check any analytics wrapper you've bolted on top.

For the exact wording Apple expects for each of these permission prompts — not just the questionnaire checkbox — see our Expo App Store permission description reference.

Third-party SDKs (RevenueCat, Firebase, Sentry, Amplitude/Mixpanel)

  • RevenueCat — declare Purchase History at minimum. If you pass an app user ID, email, or any linked identifier into Purchases.configure() or logIn(), that identifier also needs its own row, linked to the user. This is the single most under-declared item we see in Expo submissions — see our breakdown of RevenueCat missing metadata App Store rejections for the specific rejection language reviewers use.
  • Firebase Analytics — declare Product Interaction and/or Other Usage Data under the Usage Data category, plus Device ID if you haven't disabled the Advertising ID collection flag.
  • Sentry — declare Crash Data and Performance Data under Diagnostics. If your Sentry config captures breadcrumbs that include user input or screen names, that can bleed into Usage Data too — audit your beforeSend hook before you answer "no."
  • Amplitude / Mixpanel — declare Product Interaction under Usage Data, plus any identifier (device ID, user ID) you pass into identify() calls.

Every one of these SDKs ships its own data collection defaults, and Expo's managed workflow makes it easy to install one via npx expo install without ever reading what it phones home.

Mistakes That Get Expo Apps Rejected or Flagged

Most App Privacy rejections aren't about dishonesty — they're about drift. You declare accurately at submission time, then add an SDK three sprints later and forget the questionnaire exists.

Declared data that doesn't match actual SDK behavior

This is a Guideline 5.1.1 mismatch, and it's the most common reviewer flag we see in Expo submissions. The pattern: your questionnaire says "we don't track," but your binary contains an ad SDK (AdMob, Meta Audience Network, AppLovin) that requests IDFA and shares it with an ad network for attribution. Apple's review team runs static and dynamic analysis against your binary — they see the SDK calls, not your intentions. If expo-tracking-transparency is present but you never actually gate tracking-capable SDKs behind the ATT prompt result, that's a mismatch too, because it implies tracking happens regardless of user choice.

The fix isn't clever wording — it's an audit. Before every submission, grep your package.json and native dependency list against your questionnaire answers. If you added Facebook SDK, RevenueCat, or any analytics package since your last submission, assume your privacy answers are stale until you've checked. Our sample audit report shows the exact SDK-to-declaration diff we run for this.

Forgetting the account deletion requirement

This is a related but distinct failure under Guideline 5.1.1(v): any app that lets users create an account must let them delete that account and its data from inside the app — not just via a support email or a web form. Reviewers frequently flag this in the same rejection as a privacy mismatch, because both stem from the same root cause: shipping account creation (often via Firebase Auth or Supabase in an Expo app) without building out the corresponding data lifecycle.

The account deletion path has to be reachable without contacting support, and it has to actually delete data, not just deactivate the account. If your backend can't fully purge a user on request, you need an in-app flow that at least initiates deletion and communicates a completion timeline. We cover the specific implementation pattern for Expo apps — including how to handle RevenueCat and Firebase records tied to the deleted account — in App Store account deletion for Expo.

A Pre-Submission Checklist for Your Privacy Answers

Run this before you touch the Submit for Review button. Every item takes five minutes; skipping one costs you a resubmission cycle.

Audit package.json for data-collecting SDKs. Open it and go through every dependency, not just the ones you remember adding. Analytics, crash reporting, ads, push notification services, and auth providers all collect data on your behalf, and Expo's managed workflow makes it easy to forget what a library pulled in transitively. If you're not sure what a package touches, check its own privacy manifest or source before guessing on the questionnaire.

Cross-check each SDK against your declared answers. For every collecting library, confirm App Store Connect's Data Types screen has a matching entry — same data type, same purpose, same linkage status. A library added after your last questionnaire pass is the single most common cause of a mismatch. This is exactly the gap covered in mapping Expo and React Native libraries to privacy answers — use it as your reference table, not memory.

Verify your ATT prompt matches your tracking declarations. If you declared any data type as "used for tracking," NSUserTrackingUsageDescription must be present and the ATTrackingManager prompt must actually fire before that data collection starts. If you're not tracking, don't over-declare — it drags you into App Tracking Transparency requirements you don't need.

Confirm account deletion works end-to-end. If your app supports account creation, Guideline 5.1.1(v) requires an in-app deletion path that actually removes the account, not just signs the user out. Test it on a real device against a real account. See account deletion in Expo if you haven't wired this up yet — reviewers test this manually and reject on the spot if it's missing or broken.

Re-run this checklist after any dependency update. expo upgrade, a bumped SDK, or a new library pulled in during a sprint can silently change what data your app collects. Treat the privacy questionnaire as part of your dependency update checklist, not a one-time form you fill out at launch.

Run Your Privacy Answers Through a Preflight Check Before You Submit

Manually walking every dependency against 100+ questionnaire fields works the first time. It falls apart on your third app, your fifth SDK update, or the resubmission you're rushing out two days before a deadline. That's when a Firebase Analytics permission gets left unchecked, or a data type from a library you added last month never makes it into App Store Connect — and Apple's reviewer catches it instead of you.

The App Store Preflight Kit runs that cross-check systematically. It reads your dependency tree, flags SDKs with known data collection behavior, and checks them against what you've actually declared in your privacy questionnaire — the same audit described above, run consistently instead of from memory under deadline pressure. It does the same for metadata mismatches (RevenueCat entitlements not reflected in your IAP config — see missing metadata from RevenueCat) and screenshot/description inconsistencies that trigger Guideline 2.3.1 rejections.

The output isn't a pass/fail badge. It's a report that names the specific guideline at risk, the file or config where the mismatch lives, and what to change before you resubmit — the kind of thing you'd want a second reviewer to catch before Apple does. You can see the exact format on the Sample Report page: real findings, real guideline citations, no vague "review your metadata" filler.

If you're already deep into an Expo build with a growing dependency list, this is cheaper than a rejection cycle. A rejection costs you a resubmission — typically 24 to 48 hours back in the review queue, sometimes longer if the reviewer flags a second issue on the same pass. Running the kit before you submit costs less time than reading this checklist twice.

Frequently asked questions

What happens if my App Store privacy answers don't match what my app actually does?

Apple can reject the build under Guideline 5.1.1, and if it's caught post-approval, they can pull the app entirely. This isn't hypothetical — Apple runs automated network traffic analysis against your binary and compares it to your declared data types. If your Expo app pings a third-party SDK you didn't disclose, that's a mismatch. Fix it before submitting: audit every SDK in your app.json/app.config.js plugins list against your actual privacy answers, not just what you remember configuring six months ago.

Does Expo itself collect data I need to disclose in the privacy questionnaire?

Yes, if you use EAS services. EAS Build, Update, and Submit collect data like device identifiers, build metadata, and crash logs to run those services — check Expo's current privacy policy for the exact list, since it changes across SDK versions. If you're on a bare Expo workflow with EAS disabled, your exposure is smaller but not zero — expo-updates and expo-application still touch device data. Don't assume "I didn't add an SDK" means "nothing to disclose."

Do I need to declare RevenueCat, Firebase, or Sentry in App Store Connect's privacy labels?

Yes, all three collect data and each needs its own entry in your privacy questionnaire. RevenueCat handles purchase history and device identifiers for entitlement checks. Firebase (Analytics, Crashlytics) typically collects device ID, crash data, and usage patterns. Sentry collects crash logs and diagnostic data, sometimes including IP address. Check each SDK's own privacy manifest or documentation for their current data collection — don't guess from memory, since collection scope shifts between SDK versions.

How is the App Privacy questionnaire different from the App Tracking Transparency (ATT) prompt?

The privacy questionnaire (Guideline 5.1.1) is a static declaration you fill out once per submission, describing what data your app and its SDKs collect — it shows up as the "App Privacy" section on your product page. ATT is a runtime permission prompt, governed by Guideline 5.1.2, that fires when your app or an SDK wants to track users across other apps/websites for advertising. You can have a fully accurate privacy questionnaire and still need an ATT prompt — they're separate requirements answering different questions.

Can I edit my app's privacy answers after it's already live on the App Store?

Yes, and you should the moment your data practices change — you don't need a new build or version bump. Go to App Store Connect → your app → App Privacy, and update the questionnaire directly. It takes effect on your product page without a review cycle for the label itself, though Apple can still flag inconsistencies later during your next binary review. Set a calendar reminder to re-audit privacy answers whenever you add or remove a third-party SDK.