Do it yourself
$109 per platform, one-time
The WebViewGold license: a finished Xcode or Android Studio project. Paste your URL, set name and icon, switch on features, build and submit. Free updates forever.
See plans on the main pageClaude Code + privacy
If users can create an account in your app, Apple and Google both require that they can delete it from inside the app, and Google also wants a web page for deletion requests. Claude Code can build the feature in an afternoon, but only after it knows where every piece of user data lives. This guide starts with that data map, then builds deletion, a download-my-data export and the cleanup inside the WebViewGold app.
From $109 one-time per platform, or let our team do it all from $698.
Apple, guideline 5.1.1(v): if your app supports account creation, users must be able to initiate account deletion within the app. Apple's guidance asks for deletion of the account record and the associated personal data, not a deactivation switch; you may keep data you are legally required to keep, and you should tell users how long deletion takes. If you offer Sign in with Apple, revoke the user's tokens through Apple's REST API when the account is deleted. Subscriptions bought through Apple are not cancelled by deleting the account, so tell users how to cancel.
Google Play: apps that let users create accounts must offer deletion inside the app and a web link where users can request deletion without reinstalling the app. You enter that link in the Data safety form, and the deletion must cover the data associated with the account, apart from what you disclose as retained. The Google Play account deletion guide covers the console side.
Data export: neither store requires it, but privacy laws such as the GDPR give users a right of access and portability, and a Download my data button answers those requests without a support ticket. It is also a good test of your data map: if the agent cannot export it, it probably cannot delete it either.
| Area | Claude Code | You |
|---|---|---|
| Data map | Searches code, migrations, SDK imports and webhooks in plan mode and drafts DATA_MAP.md | Add what the code cannot show (spreadsheets, support inbox, manual exports) and confirm retention periods |
| Code | Settings UI, export and delete routes, cleanup helpers, migrations, tests, /delete-account page | Review, set environment variables on the host, deploy |
| Store consoles | Drafts the privacy policy changes and the Data safety answers | Enter the deletion URL in the Play Console, update App Privacy in App Store Connect |
| WebViewGold | Nothing required; can set the downloader options if the projects are in the repository | One rebuild if you change downloader settings |
Plan mode lets Claude Code read and search the repository without editing anything. Save the result as DATA_MAP.md and correct it before you continue; this file is what makes the deletion complete.
Plan mode only, do not change any files. We need in-app account deletion (Apple guideline 5.1.1(v) and the Google Play account deletion policy) and a download-my-data export. First build a complete data map. Search the codebase, the migrations, environment variable names, SDK imports, cron jobs and webhook handlers, and list every place where data about a user lives: auth records, every table with a user_id, owner_id or email column and how it references the user, storage buckets and file paths, Stripe customers and subscriptions, RevenueCat customers, OneSignal subscription IDs, Sign in with Apple tokens, analytics and error tracking, email and newsletter tools, logs and backups. For each entry give: where it lives, which identifier links it to the user, how to delete it (foreign key cascade, API call, or retention with a reason), and whether it belongs in the export. Mark everything you are unsure about. Present the result as a markdown table I can save as DATA_MAP.md.

I am very happy I bought this app! Extremely easy and great documentation. Was in contact with the customer service, they replied very quickly and very friendly. They solved my question within a day. 10/10 would recommend.
| Data | How it is deleted | In the export? |
|---|---|---|
| Auth user | auth.admin.deleteUser, last step | ID, email, created date |
| Profile and content tables | Foreign keys to the user with ON DELETE CASCADE | Yes |
| Uploaded files | Storage API, per user folder (listing is not recursive) | Links or the files |
| Stripe customer and subscriptions | Cancel subscriptions; keep invoices as legally required and say so in /privacy | Plan and invoice list |
| App Store / Google Play subscription | Cannot be cancelled by you; show cancelinapppurchase:// inside the app | Plan name |
| RevenueCat customer | RevenueCat REST API customer deletion | No |
| OneSignal subscription IDs | Delete your stored rows; optionally the OneSignal user via their API | No |
| Sign in with Apple | Revoke the token at Apple's revoke endpoint | No |
| Analytics, error tracking, email tools | Vendor deletion API or documented retention | Usually no |
Switch back to the default permission mode so you can review each edit, or to accept-edits mode if you prefer to review the full diff at the end.
Implement account deletion and data export based on DATA_MAP.md. Our app also runs inside native iOS and Android apps built with WebViewGold (the user agent contains WebViewGoldApp). 1. Settings > Account: a Download my data button and a Delete account button. 2. Export: GET /api/account/export returns one JSON file for the signed-in user with every exportable entry from the map, sent with Content-Type application/json and Content-Disposition attachment; filename=my-data.json. Trigger it with a normal link to that URL, not with a Blob or createObjectURL download: inside the app, the WebViewGold downloader reacts to file extensions and Content-Disposition headers. If an export can be large, build it in a background job and email a signed link that expires after 24 hours. 3. Delete: a confirmation screen that explains what is deleted, what we keep for legal reasons (invoices) and that App Store or Google Play subscriptions are not cancelled automatically. Inside the app, show a Manage subscription link that navigates to cancelinapppurchase:// when the user has a store subscription. Require typing DELETE. 4. POST /api/account/delete: authenticate, then in this order cancel Stripe subscriptions, delete the RevenueCat customer, revoke Sign in with Apple tokens if we have them (Apple REST API, /auth/revoke), delete storage files, delete rows (prefer ON DELETE CASCADE; add a migration where it is missing), and delete the auth user last with the admin client. Server-side only; the service-role key must never reach the client bundle. Make the route idempotent so a retry after a partial failure completes the job. 5. After success: sign out and show /account-deleted. Inside the app, its Done button navigates to reset:// to clear the cookies and cache the wrapper keeps. 6. A public /delete-account page for people who no longer have the app: explains the in-app path and offers a request form or an email address, works without login and on a 320 px screen. 7. Update /privacy with the retention periods and the /delete-account URL. 8. Tests for the delete route: a user with data in every table ends with zero rows, and calling the route a second time still succeeds. Report the changed files, the migrations and every manual step I have to do.
Third parties first, while you still know the customer IDs; the auth user last, because most foreign keys hang off it. The helpers in account-cleanup wrap the Stripe, RevenueCat and Apple calls from your data map.
// app/api/account/delete/route.ts (server only)
import { NextResponse } from "next/server";
import { createClient as createAdmin } from "@supabase/supabase-js";
import { createClient } from "@/lib/supabase/server";
import { cancelStripeSubscriptions, deleteRevenueCatCustomer, revokeAppleTokens } from "@/lib/account-cleanup";
export async function POST(req: Request) {
const supabase = await createClient();
const { data: { user } } = await supabase.auth.getUser();
if (!user) return NextResponse.json({ error: "unauthorized" }, { status: 401 });
const { confirm } = await req.json();
if (confirm !== "DELETE") return NextResponse.json({ error: "confirmation missing" }, { status: 400 });
const admin = createAdmin(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY!);
// 1. Third parties, while the IDs still exist (each helper is a no-op if there is nothing to do)
await cancelStripeSubscriptions(user.id);
await deleteRevenueCatCustomer(user.id);
await revokeAppleTokens(user.id);
// 2. Files: list() is not recursive, nested folders need their own pass
const { data: files } = await admin.storage.from("uploads").list(user.id);
if (files && files.length > 0) {
await admin.storage.from("uploads").remove(files.map((f) => user.id + "/" + f.name));
}
// 3. Rows go with the user through ON DELETE CASCADE (see DATA_MAP.md)
// 4. The auth user, last
const { error } = await admin.auth.admin.deleteUser(user.id);
if (error) return NextResponse.json({ error: "delete failed, safe to retry" }, { status: 500 });
return NextResponse.json({ ok: true });
}Two small settings decide whether the file reaches the phone.
The route above returns JSON with a Content-Disposition attachment header. Link to it with a plain anchor; JavaScript-generated Blob downloads are not covered by the WebViewGold downloader docs.
Either enable autodownloader in Config.swift (downloads based on Content-Disposition headers) or serve the file under a URL ending in .json and add ".json" to extentionARY. See the iOS file downloader docs.
Enable AUTO_DOWNLOAD_FILES in Config.java or add the extension to downloadableExtension; requireStorage must stay true if you use downloads. See the Android file downloader docs.
These are native settings, so they need one new build. Everything else in this guide ships with your next web deploy. The Cloud Builder can produce that build without a local Xcode or Android Studio setup.
reset:// clears the wrapper's cookies and cache. Note what your build shows afterwards and make sure it is a clean start, not an error.No. Apple asks for deletion of the account and its associated personal data, and Google Play requires the data to be deleted, not just hidden. Deactivation can be an extra option, not the only one.
Yes, where you have a legal obligation or a legitimate reason, such as invoices for tax law. Disclose it in your privacy policy and in the Data safety form.
A short grace period is common. Start the deletion in the app, tell the user exactly when the data will be gone, and check Apple's current account deletion guidance for the wording reviewers expect.
You cannot cancel App Store or Google Play subscriptions on the user's behalf. Show a Manage subscription link (cancelinapppurchase:// inside the app) and say clearly that billing continues until they cancel.
A structured, machine-readable format such as JSON or CSV. One JSON file per account is the easiest to generate, test and explain.
Same result, different amount of work on your side. All three come with the approval guarantee and 24/7 human support.
$109 per platform, one-time
The WebViewGold license: a finished Xcode or Android Studio project. Paste your URL, set name and icon, switch on features, build and submit. Free updates forever.
See plans on the main page$349 per license, one-time add-on
No Mac, no Xcode, no Android Studio: configure in the browser, we build both apps in the cloud and hand them to App Store Connect and the Play Console.
How the Cloud Builder works Try the free demo$698 per platform $798
Send us your URL and icon. Our team configures, builds and delivers your app within 72 hours, white-label, with source projects. Both platforms for $1,158.
Full Service details Powered byWinter Sale prices valid until December 31, 2026.
App Store & Google Play approval guarantee – or your money back within 14 days
Rather hand it over? Full Service: we configure, build and deliver within 72 hours, from $698 per platform. Questions? Chat with us 24/7.
Refunds are granted under the conditions listed in our FAQ: a non-content rejection by Apple and/or Google, claimed within 14 days after purchase.