◉RORK LABJP
●EXPO — EAS Observe now records native crashes (Oct 7). On SDK 57, update to 57.0.21 or later●RORK — GPT-6.1 Sol (Sep 29) and Claude Sonnet 5.5 (Sep 28) are now in the model menu●RN 0.88 — React Native 0.88.x is scheduled for Oct 12, 2 days left●Q&A — People keep asking why AuthSession returns no result in Android standalone builds●WINDOWS — A walkthrough shows how to ship an iPhone app from Windows only, with no Mac●NEW — When only notifications fail in Expo Go: three checks to run first●EXPO — EAS Observe now records native crashes (Oct 7). On SDK 57, update to 57.0.21 or later●RORK — GPT-6.1 Sol (Sep 29) and Claude Sonnet 5.5 (Sep 28) are now in the model menu●RN 0.88 — React Native 0.88.x is scheduled for Oct 12, 2 days left●Q&A — People keep asking why AuthSession returns no result in Android standalone builds●WINDOWS — A walkthrough shows how to ship an iPhone app from Windows only, with no Mac●NEW — When only notifications fail in Expo Go: three checks to run first
Articles/App Dev
◇ App Dev/2026-09-07Intermediate

Sending user text to an external AI: what actually goes in Play's Data safety form

Classifying user input sent to an external AI as collected, shared, or ephemeral in Play's Data safety form, plus a redaction ordering bug found by running the code.

Google Play35Data safetyPrivacy10AI31Indie development3Android53

✦ Premium Article

I added a small text box to an app: write down what is bothering you, and an AI tidies it up and hands it back. The implementation took half a day. What stopped me was the step after that. I opened the Data safety section in Play Console and sat there, unsure which row this text box belonged to.

Nothing gets stored on my own server. The text goes to an external model, the reply is rendered, and that is the end of it. So "not collected" should be fine — that was my first instinct.

It was not enough. The classification does not hinge on whether I keep the data. It hinges on what the recipient does with it. I ship a handful of apps as an indie developer, and before I understood that, I pushed several updates where the form and the actual traffic had quietly drifted apart. Here is the order I now work through.

Whether it counts as "shared" depends on the recipient, not the sender

In Play's vocabulary, data leaving the device is collected, and data reaching a third party is shared. The part that trips people up is the second one.

Transmission alone does not settle it. What matters is whether the recipient uses the data for their own purposes, and how long they hold it. Ad targeting, cross-app profiling, benchmarking — if any of those apply on their side, it is sharing.

External AI providers sit right on that line. Most state that API traffic is not used for training, yet retaining logs for a fixed window to monitor abuse is common practice. "Not used for training" and "not retained" are two different claims.

My code decides what gets sent. The recipient's retention window decides how it gets declared. I reread that line every time I add a destination.

There is a harder part, too: your own fetch calls are not the only way out. Ad SDKs and crash reporters each make their own decisions. If an SDK in your app collects or shares data, that belongs in the form as well. I walked through auditing the SDK chain in auditing the Privacy Manifest of a Rork-generated Expo app all the way down the SDK chain.

Ephemeral does not mean you skip the question

Here is the second thing I had backwards.

Play recognises ephemeral processing: data sent off device, held only in memory, and kept no longer than needed to serve that request in real time. The canonical example is a weather app passing location to fetch a local forecast.

The crucial detail is that ephemerally processed data still gets answered in the form. What meeting the standard buys you is that the item is not surfaced on your store listing. It does not buy you a blank field.

Read it as "ephemeral, so I don't have to write it" and you ship a form that disagrees with your app's behaviour — a disagreement you will not notice until review points at it. For a while I skipped that same field on every update.

Ephemeral status is also fragile in a way that has nothing to do with policy. The moment you log a request and response to check an answer, the "not retained" premise is gone. A debugging line can change the classification.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦You will be able to inventory everything your app sends off device, including the traffic your own code never wrote
✦You will avoid the rejection loop that comes from assuming ephemeral processing means you can leave the answer blank
✦You will be able to decide whether user input sent to an external model counts as collected, shared, or ephemeral, based on the recipient's retention window
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
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 $15 for lifetime access
View Membership →

Related Articles

◇ App Dev2026-08-18
The three places I had to fix before a Rork project actually targeted API level 36
My app.json said targetSdkVersion 36. The value my build actually read was 35. Here is the script that reports the effective value, and how I split my apps between raising, leaving alone, and requesting an extension.
◇ App Dev2026-09-23
It Crashed, but the Reviews Say "It Freezes" — When an Android Crash Leaves a Blank Screen Behind
Your crash reports show exceptions, yet users only ever say the app freezes. Here is why expo-updates plus the New Architecture can leave an empty Android screen behind, and the order I now use: a way out first, a bad-exit marker second, root cause last.
◇ App Dev2026-09-16
The Token I Deleted Came Back After a Restart — Detecting Failed SecureStore Deletes
On Android, getItemAsync can report null right after sign-out while the value is still sitting on disk. Here is how I rewrote a sign-out path that was verifying deletion by reading instead of by the delete result.
📚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