RORK LABJP
ACQUISITION — Rork makes its first acquisition, buying Paperline, a macOS app that generates native Swift apps with AIFUNDING — The $15M seed led by Left Lane Capital backs Rork's push to redefine how mobile apps are built and monetizedGROWTH — Rork Max reportedly hit $1.5M ARR within three days of launch and doubled annual revenue in two weeksENGINE — Rork Max runs on Claude Code and Claude Opus 4.6, the first web Swift builder aiming to replace XcodeSPLIT — Standard Rork uses React Native (Expo); Rork Max generates native Swift across the whole Apple ecosystemPRICING — Start free; paid plans begin at $25/month, with Rork Max at $200/monthACQUISITION — Rork makes its first acquisition, buying Paperline, a macOS app that generates native Swift apps with AIFUNDING — The $15M seed led by Left Lane Capital backs Rork's push to redefine how mobile apps are built and monetizedGROWTH — Rork Max reportedly hit $1.5M ARR within three days of launch and doubled annual revenue in two weeksENGINE — Rork Max runs on Claude Code and Claude Opus 4.6, the first web Swift builder aiming to replace XcodeSPLIT — Standard Rork uses React Native (Expo); Rork Max generates native Swift across the whole Apple ecosystemPRICING — Start free; paid plans begin at $25/month, with Rork Max at $200/month
Articles/App Dev
App Dev/2026-06-25Intermediate

The App Privacy Section That Grows the Moment You Add Ads and Subscriptions — Notes on What I Actually Checked

How I filled out App Store Connect's App Privacy section for a Rork (Expo) app with AdMob, RevenueCat, and Crashlytics — including the tracking-to-ATT chain, written up as field notes from running six apps.

App Store71Privacy6AdMob65RevenueCat27Expo102

The other day I tried to submit a new wallpaper app to App Store Connect. The build was fine, yet a red banner — "This app has no App Privacy information" — stopped me from going any further. The code was finished, but I was blocked at the very last step. When you ship apps as a solo developer, this declaration screen always makes you brace yourself a little.

The App Privacy section is where you, the developer, declare what kinds of data your app collects. The tricky part is that you are responsible not only for your own code, but also for whatever the third-party SDKs you embed — ads, billing, crash reporting — quietly collect in the background. For my first few apps I was bounced back here repeatedly, and ended up re-checking what each SDK gathers, one by one.

In this article I'll leave field notes on what I actually checked for a fairly standard setup: AdMob, RevenueCat, and Crashlytics. The exact answers shift with your configuration and SDK versions, so please verify against your own environment in the end.

App Privacy and the privacy manifest are two different things

These are easy to confuse, so let me separate them first. There are two similar-sounding things, and you need both.

NameWhat it isWhere you set it
Privacy manifest (PrivacyInfo.xcprivacy)A file embedded in the app binary. Declares collected data types and the reasons for using "Required Reason APIs" in a machine-readable formThe build (Expo config / bundled by each SDK)
App Privacy (nutrition label)The "data practices" list shown on your store product page. A developer self-declarationThe web form in App Store Connect

The former is a machine-facing declaration read by crawlers; the latter is a human-facing summary that users read on the product page. Even if your manifest is correct, you still have to fill in the web-side declaration yourself. Early on I assumed these two were the same thing, got my manifest in order, still couldn't submit, and spent a while not understanding why.

Adding ads, billing, and crash reporting expands what you must declare

For a wallpaper app that only displays images, the declaration stays minimal. But once you add three SDKs for monetization and operations, it tips firmly toward "data is collected." Here is roughly what I ended up checking for my setup.

SDK (purpose)Main data types collectedLinked to the userUsed for tracking
AdMob (ads)Identifiers (advertising ID / IDFA, etc.), Usage Data, DiagnosticsYes (for ad delivery)Yes (with personalized ads)
RevenueCat (billing)Purchases, Identifiers (user ID), Usage DataYesNo
Crashlytics (crash reporting)Diagnostics, Identifiers (installation ID)No (in most setups)No

The biggest fork in the road here is AdMob's "used for tracking." Once you enable personalized ads, you are using the advertising ID to track users, which puts you under "Used to Track You" in the declaration. In my setup, RevenueCat and Crashlytics collect data to operate my own service but do not track across third parties, so I leave them out of the tracking column.

Each SDK publishes a page summarizing exactly what data it collects. If you fill the form from guesswork without reading these, discrepancies surface later. Before every declaration, I reopen each vendor's latest data-collection document and only then fill in the form.

Checking "used for tracking" makes ATT mandatory

This is the chain that trips people up most at submission time. If you declare "identifiers used for tracking" in App Privacy but your app never shows the App Tracking Transparency (ATT) permission dialog, the review will bounce you — because the declaration and the implementation contradict each other.

With Expo, add expo-tracking-transparency and set the permission string.

{
  "expo": {
    "plugins": [
      [
        "expo-tracking-transparency",
        {
          "userTrackingPermission": "We use your activity to show ads that are relevant to you."
        }
      ]
    ]
  }
}

Then always request permission before loading personalized ads.

import { requestTrackingPermissionsAsync } from "expo-tracking-transparency";
 
const { status } = await requestTrackingPermissionsAsync();
// Only enable personalized ads when granted
const personalized = status === "granted";

If permission is denied, turn personalization off and fall back to non-personalized ads. "Declared it = implemented ATT = stop tracking when the user declines" — unless all three line up, a contradiction will eventually show somewhere. I once set the ATT string but forgot to actually call the dialog, noticed only after submitting, and had to swap it in a hurry.

How to decide the three axes (collected / linked / tracking)

App Privacy is, for each data type, a matter of deciding three things in order. When in doubt, asking yourself in this order keeps it tidy.

First, "is it collected at all?" Take inventory of what your own code collects plus what the embedded SDKs collect. The moment you add an ad SDK, identifiers and usage data fall onto the "collected" side.

Second, "is it linked to the user?" If you can identify an individual through an account or device ID, it is "linked." Purchase history is tied to the account, so I put RevenueCat-related data under "linked."

Third, "is it used to track across third parties?" This is the heaviest call, and it ties directly to ATT. Personalized ads qualify; plain operational analytics usually does not. Leaving this vague and "checking everything just in case" needlessly forces ATT and lowers your opt-in rate, so I find it more practical to narrow it down with a clear rationale.

Revisit the declaration whenever you update an SDK

The hard part of operations is that this isn't fill-once-and-forget. A major SDK update can quietly add new collected data types. Since I run six apps in parallel, I now always set aside time at the once-a-year SDK update to reconcile each vendor's data-collection document against my own declaration.

Lately I keep a single mapping table of my own — "data collected per SDK to App Privacy category" — and when I ship a new app I copy it and only fix the differences. That has cut mistakes far more than thinking it through from scratch every time.

Before you submit your next app, start by listing the SDKs you've embedded and opening each one's latest data-collection page. Those ten-odd minutes turn out to be the shortcut, rather than getting stuck at the declaration after the code is done. I hope this helps anyone stuck at the same spot.

Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

App Dev2026-03-15
Production AI Companion Apps: Streaming, Voice & Monetization
Build a production-grade AI companion with streaming responses, voice I/O, mood tracking, offline support, and subscription monetization. App Store submission guidelines included.
Dev Tools2026-06-16
I Initialized Ads Before Restoring Purchases, and Paying Users Saw a Banner Flash — Cold-Start Ordering for Rork (Expo) Apps
Consent, ATT, ad SDK init, purchase restore, and remote config all try to run in the same few hundred milliseconds at launch. Get the order wrong and a paying user sees a banner flash, or measurement fires before consent in the EEA. Here is how I fold a Rork-generated Expo app's startup into a single orchestrator and kill the races by design.
Dev Tools2026-06-15
The Day a Third Reason to Hide Ads Appeared — Folding Rork App Ad-Free Logic Into One Place
Ads show only on one screen for paying users, or ads never show for free users. The usual cause is that the condition for hiding ads is scattered across the code. Here is how I fold three reasons — subscription, lifetime purchase, and a timed reward unlock — into a single state and route every ad through one hook, written as an implementation note from running six apps as an indie developer.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →