Skip to content
← All posts

By Specita

Google Play service account JSON key: setup and safe use

How to create a Google Play service account JSON key, grant it Play Console access, limit its permissions, and fix the usual 401 and 403 errors.

A terracotta clay key tied with a thin ink thread to a paper envelope sealed with a terracotta clay seal.

A Google Play service account JSON key is the credential file that lets a script, CI job, or tool call the Google Play Developer API without a person signing in. You create the service account in Google Cloud, download its JSON key, then invite the account's email address in Play Console and grant it permissions. Without that last step, the key authenticates but can't reach your apps.

Treat the file like a password. Anyone who holds it can do whatever the account's permissions allow.

The steps below follow Google's documentation. We did not run them on a new account for this article, and console labels can change.

How to create the service account

Google's API getting started guide recommends a service account for server-to-server access. The setup runs across two consoles.

In Google Cloud:

  1. Select or create a project, and turn on the Google Play Android Developer API.
  2. Open IAM & Admin, then Service Accounts.
  3. Click Create service account and follow the steps.
  4. Open the new account, go to Keys, and add a JSON key. Your browser downloads the file, and this is your only copy.

In Play Console:

  1. Open Users and permissions.
  2. Click Invite new users.
  3. Enter the service account's email address, which ends in .iam.gserviceaccount.com.
  4. Choose which apps it can reach and what it can do, then send the invite.

If your organization blocks key creation, you may see an error when you try to add a key. An organization policy controls that, so ask your Google Cloud administrator.

Which permissions to grant

Give the account the least it needs, and scope it to specific apps where possible. Here's how to think about it by job:

JobWhat it needs
Upload to internal testing from CIPermission to release to testing tracks
Release to production from CIRelease to production permission. Think hard before you automate this
Read release status for a dashboardApp-specific read access to app information
Billing APIsView financial data and manage orders, as Google lists

Permission names change, so check Google's permission list when you set this up. Don't make a service account an admin because a tool's setup page suggests it might be easier. If a tool needs admin rights to read data, ask why.

Use one account per job. A CI uploader and a read-only reporting tool shouldn't share a key. When one of them is retired, you can remove it without breaking the other.

How to store a Google Play service account JSON key

The JSON file belongs in a secret store. It should never be in your repository, a chat thread, or a shared drive.

In GitHub Actions, store it as an encrypted secret and write it to a file only for the step that needs it:

- name: Write Play key
  run: echo '${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }}' > "$RUNNER_TEMP/play.json"

Check that your logs don't print it. For fastlane, point json_key at the path in your Appfile or action, and read the path from the environment.

Rotate on a schedule and whenever someone with access leaves. To rotate, add a new key in Google Cloud, update your secret, confirm a run works, and then delete the old key. Google Cloud allows more than one key on an account, so you can do this with no gap.

If a key leaks, delete it in Google Cloud right away, then look through recent activity for anything you don't recognize. Deleting the key stops it working, while removing the Play Console user removes the access.

How to fix common errors

ErrorUsual causeFix
401 or invalid credentialsWrong file, or the key was deletedCheck client_email in the JSON, and confirm that the key still exists
403 "The caller does not have permission"The email isn't invited in Play Console, or the app isn't includedOpen Users and permissions and check that account's apps
403 API not enabledThe API is off in the Google Cloud projectTurn on the Google Play Android Developer API
404 on a packageWrong package name, or the app has no release yetCheck the package name
"APK specifies a version code that has already been used"A repeat version codeIncrement it. The key is fine

New service accounts can take time to work after you grant access. If everything looks right and you still get a 403, wait and try again before you tear it down. Some developers report waits of hours for this to take effect. Google doesn't state a number on the pages we checked.

The client_email field in the JSON tells you exactly which account a file belongs to, which helps when you inherit a project with three similar files.

For agencies

Each client should own their own Google Cloud project, service account, and Play Console invite. If the service account lives in the agency's project, it's harder to hand over and easier to forget. At the end of a project, the client can then remove the agency's human users without breaking their pipeline, and the agency holds no leftover credentials.

Keep a short record for each client app: which accounts exist, what each one does, who owns the secret, and when it was last rotated. Store the record, and leave the key out of it.

Using the key with Specita

Specita connects to Google Play with a dedicated service account and read-only, app-specific permissions. It uses the Android Publisher and Play Developer Reporting scopes, and encrypts the JSON at rest. It then shows each track's release state in your product's release record. The Google Play setup guide lists the exact permissions.

To see what the release data means, read our guide to Google Play staged rollouts.

Google guidance checked on November 4, 2026.