When a delivery date is set, the screens and features are what everyone talks about. The part that costs the most time later is a quieter question: whose account is this app published under?
As an indie developer, I have only ever published my own apps from my own accounts, so I have never moved an app to someone else's name. I'm writing this with that limit in plain view. I read Apple's and Google's official help pages side by side and tested the one piece I could check on my own machine, a small audit script run against a sample project. Please read this as a way to decide early, not as a transfer diary.
The short answer first: build the client's app under the client's developer account from day one. It leaves the least to undo.
Three ways to hold the account
| Approach | Fits when | Where the work shows up |
|---|---|---|
| Build under the client's account from the start | They already have developer accounts, or can register with you | One-time invitation work at the beginning |
| Publish under yours, transfer later | Registration won't be ready in time and you want review to start | Checking transfer conditions and re-pointing linked settings |
| Keep publishing under yours | The contract includes ongoing operation | You need a written scope of responsibility and an exit plan |
If you choose the second route, learn what a transfer carries over and what it cuts before you quote the job. It makes the conversation with the client much easier.
Apple: conditions that stop a transfer
App Store Connect's help lists the criteria. These were the ones that looked easiest to trip on:
- The app needs at least one version already released on the App Store. An app that has never shipped cannot be transferred.
- It cannot be available for pre-order anywhere.
- It cannot be in states such as Waiting for Review, In Review, or Pending Developer Release.
- In-app purchase product IDs cannot collide with those of any app in the recipient's account.
- Both accounts must have accepted the latest agreements.
On the plus side, the help says the app stays on the App Store during the transfer and keeps its ratings and reviews and its Bundle ID. The Bundle ID cannot be changed once a build has been uploaded, so it is a decision for day one.
Some things need re-doing on the recipient's side: auto-renewable subscriptions need an app-specific shared secret handed over before the transfer starts, TestFlight testing must be turned off with builds and testers removed, and features such as Sign in with Apple, push notifications, Apple Pay, iCloud, and Game Center each have their own steps. Apple also notes the app is removed from your account after the transfer, so back up first.
Google Play: know what does not move
In Play Console, the sender submits a request and the recipient's owner approves it. Google's help says its support team responds within two business days.
Users, statistics, ratings and reviews, subscriptions, and previously submitted app content declarations carry over. These do not:
| Does not carry over | Do this beforehand |
|---|---|
| Sales, payout, and bulk export reports | Download them and keep your own copy |
| Orders created before the transfer | Refunds stay with the original account, so tell the client for how long |
| Closed-testing tester groups | The recipient recreates them; testers may need to opt in again |
| Analytics and Firebase links | List every linked service so you can re-point them afterwards |
The recipient's account must be fully registered, and a newly created one carries a registration fee. An app that only has in-app products is unpublished after the transfer until it is republished.
Find the settings that carry your name
Reading help pages doesn't tell you where your own identity sits inside a project. This script lists the usual places in an exported Expo project. I ran it against a sample project and it printed every field as expected.
// audit.mjs — usage: node audit.mjs <project-folder>
import { readFileSync, existsSync } from "node:fs";
import { join } from "node:path";
const dir = process.argv[2] ?? ".";
const read = (f) =>
existsSync(join(dir, f)) ? JSON.parse(readFileSync(join(dir, f), "utf8")) : null;
const app = read("app.json")?.expo ?? {};
const eas = read("eas.json") ?? {};
const submit = eas.submit?.production ?? {};
const rows = [
["Expo owner (EAS account name)", app.owner],
["EAS projectId", app.extra?.eas?.projectId],
["iOS Bundle ID (does not change on transfer)", app.ios?.bundleIdentifier],
["Android package (does not change on transfer)", app.android?.package],
["Apple ID (submit config)", submit.ios?.appleId],
["Apple Team ID (submit config)", submit.ios?.appleTeamId],
["ascAppId", submit.ios?.ascAppId],
["Play service account key", submit.android?.serviceAccountKeyPath],
["Firebase iOS config file", existsSync(join(dir, "GoogleService-Info.plist")) ? "present" : undefined],
["Firebase Android config file", existsSync(join(dir, "google-services.json")) ? "present" : undefined],
];
for (const [label, value] of rows) {
console.log(`${value ? "CHECK" : "none "} ${label}${value ? `: ${value}` : ""}`);
}I wrote it this way because owner in app.json and the submit block in eas.json are where your own name slips in unnoticed. The Bundle ID and package name stay the same through a transfer, so they belong on a "confirm, don't change" list. Firebase config files do not swap themselves; the recipient issues new ones from their own project.
Every CHECK line becomes one item in your handover note.
Four questions to ask before quoting
- Does the client already hold an Apple Developer Program account and a Google Play developer account?
- If not, will they register as an individual or an organization? The registered name is what the stores display.
- From what date do they handle revenue and billing?
- After launch, who holds account permissions when something breaks?
If those four are settled, "the client's account from the start" is usually enough.
What to do tomorrow
If you have a project in progress, run node audit.mjs . once in its folder and count the CHECK lines. That number is a fair estimate of the work a transfer would involve.
Both stores update these procedures from time to time, so read the current help pages before you actually transfer anything. I plan to reread them for every job, and that is the one habit I'd suggest keeping.