All posts
GuideJul 8, 2026 · 9 min

Google Play Service Account Setup for Replying to Reviews (the Permission Maze)

Create the Google Play service account, link it, grant 'Reply to reviews', mint an androidpublisher token — and fix the 401 that stops every first attempt.

RA

The Argus Team

Reply Argus

To reply to Google Play reviews through the API you need four things lined up at the same time: a service account with a downloaded JSON key, the `www.googleapis.com/auth/androidpublisher` scope on its access token, that service account's Google Cloud project linked to your Play Console, and — the step almost everyone skips — the service account invited into Play Console as a user with the 'Reply to reviews' permission. Get three of the four right and you still hit the same wall: a `401` that insists your developer account doesn't own the application.

That error is misleading, and it's why this earns the name 'the permission maze.' Linking a Cloud project to Play Console is not the same as granting a service account access to reply — two separate handshakes, two different consoles, and the API only works when both are done. Here's the full path: create the account, wire both linkages in order, mint a scoped token, and debug the 401 when it shows up anyway.

Why a service account instead of your normal Google login?

The reviews resource is a server-to-server API. There's no 'Sign in with Google' consent screen — your code runs unattended, so it authenticates as a service account: a non-human identity that owns a private key, mints its own access tokens, and acts on the app's behalf with nobody logged in. You create it once in Google Cloud, download a JSON key, and every review call carries a bearer token from that key.

Two independent linkages have to be true for that token to do anything. The Cloud project that owns the service account must be linked to your Play Console (the account-level handshake). Separately, the service account's email identity must be invited into Play Console with the reviews permission. Miss either and the token is valid but powerless — you authenticate cleanly, then get told you don't own the app.

  1. 1

    Step 1 — Create the service account in Google Cloud

    In Google Cloud Console, pick (or create) a project and go to IAM & Admin → Service Accounts → Create. Name it something like `play-reviews-bot`. You don't need any Cloud IAM roles here — Play Console handles the permission that matters. Note the generated email (play-reviews-bot@your-project.iam.gserviceaccount.com).

  2. 2

    Step 2 — Download a JSON key

    On the service account, open Keys → Add key → Create new key → JSON. The file downloads once and is never shown again. It's a live credential: anyone holding it can post replies as you, so keep it out of git and in a secret manager.

  3. 3

    Step 3 — Enable the Google Play Android Developer API

    In APIs & Services → Library, search 'Google Play Android Developer API' and click Enable on the same project. Skip this and every call fails with a 403 'API not enabled' — a different error than the 401 below, and a quick fix.

Linking the project and granting 'Reply to reviews' in Play Console

The Google Cloud side is done: the service account exists, it has a key, and the API is on. But nothing yet gives it access to your apps. That happens in Google Play Console under Setup → API access (owner or admin only), where the two handshakes get completed and the order matters.

  1. 1

    Step 4 — Link the Cloud project

    In Setup → API access, find your Google Cloud project and click Link. This account-level handshake lets that project's service accounts see your apps at all. If the project isn't listed, confirm you enabled the Developer API on it (Step 3) and are signed into the right Google account.

  2. 2

    Step 5 — Grant the service account access

    On the same page, your service account now appears under 'Service accounts'. Click Manage Play Console permissions (or invite its email under Users and permissions) — the same editor you'd use for a human teammate, and a grant separate from the Step 4 link that most people miss.

  3. 3

    Step 6 — Tick 'Reply to reviews'

    Grant account-wide access or scope it to specific apps under App permissions, then check 'Reply to reviews' (plus 'View app information' so list/get work). Save and invite. This is the exact capability reviews.reply checks — without it, replies 401 even when reads succeed.

  4. 4

    Step 7 — Wait for propagation, then call

    New access can take up to 24 hours to take effect, though it's usually minutes. A 401 right after saving is often just propagation — wait and retry before hunting for a bug.

Linking ≠ granting — the whole maze in one line

Step 4 (link the project) and Step 6 (grant 'Reply to reviews') feel like one action and are not. The link makes your apps *visible* to the service account; the permission makes them *writable*. You can link, see a green checkmark, mint a valid token — and still 401 because you never ticked the permission box. If you take one thing from this guide, take that.

The scope that has to be on the token

A service-account token has to be requested with the right OAuth scope. For everything under the Play Developer API, including reviews, that scope is `www.googleapis.com/auth/androidpublisher`. Without it, calls fail with an insufficient-scope error; with it you're cleared for list, get, and reply. Google's auth libraries handle the JWT-signing and token exchange — point them at the JSON key and the scope, and they hand back a bearer token good for about an hour.

Here's the minimal mint-and-reply in Node and Python. The reply body is capped at a hard 350 characters on Google Play — go over and `replyText` is rejected outright. The cap and the three review methods are covered in the [Google Play reviews API reference](/blog/google-play-reviews-api-reference); this is just the credential half.

javascript
// npm i google-auth-library
import { GoogleAuth } from 'google-auth-library';

const auth = new GoogleAuth({
  keyFile: './play-service-account.json',
  scopes: ['https://www.googleapis.com/auth/androidpublisher'],
});
const client = await auth.getClient();
const { token } = await client.getAccessToken();

const pkg = 'com.yourcompany.app';
const reviewId = 'gp:AOqpTO...';

await fetch(
  `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${pkg}/reviews/${reviewId}:reply`,
  {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${token}`,
      'Content-Type': 'application/json',
    },
    // replyText: 350 chars max, hard limit
    body: JSON.stringify({ replyText: 'Fixed in 5.2 — thanks for flagging it.' }),
  }
);
Node: mint a scoped token, then post a reply. Python equivalent below the fold.
python
# pip install google-auth requests
from google.oauth2 import service_account
import google.auth.transport.requests
import requests

SCOPES = ['https://www.googleapis.com/auth/androidpublisher']
creds = service_account.Credentials.from_service_account_file(
    'play-service-account.json', scopes=SCOPES)
creds.refresh(google.auth.transport.requests.Request())

pkg, review_id = 'com.yourcompany.app', 'gp:AOqpTO...'
url = (f'https://androidpublisher.googleapis.com/androidpublisher/v3/'
       f'applications/{pkg}/reviews/{review_id}:reply')
requests.post(url,
    headers={'Authorization': f'Bearer {creds.token}'},
    json={'replyText': 'Fixed in 5.2 — thanks for flagging it.'})
Python: the same token mint with the androidpublisher scope.

This is the payoff — a live reply under the review within the day. And it moves your number: when Google announced recency-weighted ratings at I/O 2019, it reported that developers who reply see an average lift of 0.7 stars. Under the 350-character ceiling, that reply looks like this:

App keeps logging me out every few hours and I lose my place in the audiobook. Really frustrating on my commute. Pixel 7a.

Reply

Sorry about the forced logouts — that's a token-refresh bug on Android 14, and the fix is live in 5.2 (rolling out this week). Update from the Play Store and your session should hold; your listening position is saved server-side, so you won't lose your place. Reply here if it recurs and we'll pull your logs.

Fixing the 401: 'This developer account does not own the application'

This is the error that stops almost every first attempt, and it lies about its own cause. The token is valid; the message means the linkage between the service account and the app isn't complete, not that anything is wrong with your account. Walk this short list in order and one of them is your problem:

  • You linked the project but never granted the reviews permission. Step 4 without Step 6 — the number-one cause. The service account has to show under Users and permissions with 'Reply to reviews' actually ticked.
  • Access hasn't propagated. A 401 in the first minutes after saving is often just Google catching up (up to 24 hours). Wait and retry before assuming a config error.
  • Wrong package name in the URL. The `{packageName}` segment must exactly match an app the service account can access. A typo surfaces as this same ownership 401, not a clean 404.
  • The app is outside the service account's scope. If you used App permissions (not account-wide) in Step 6, the app you're calling has to be in that list, or it reads as 'does not own the application.'
  • The link points at the wrong Play Console. Confirm the project under Setup → API access belongs to the account that owns the app — not a second developer account you also manage.

Apple's side is an entirely different dance — an App Store Connect API key, a JWT you sign yourself, no service-account concept at all. If you build for both stores, the [App Store Connect reviews API reference](/blog/app-store-connect-reviews-api-reference) covers that half, and [the reply rules for every store](/blog/reply-rules-for-every-app-store) maps where the two diverge.

Treat the JSON key like a password, because it is one

The key file lets anyone post replies as you, no login. Never commit it (a shocking number end up on public GitHub), never ship it client-side, and keep it in a secret manager. If it leaks, revoke it in Cloud Console → Keys and generate a fresh one — the old key dies immediately. Rotating on a schedule is cheap insurance.

Skip the maze entirely

If the goal is to reply to reviews, not run OAuth plumbing, hand the handshake off. [ReplyArgus](/features) holds the service-account linkage, polls Google Play and the Apple App Store on a schedule, and drafts an on-brand reply for each review in the reviewer's own language — sized to Play's 350-character cap and grounded in your past approved replies. You approve; it posts. Or drive it from [Claude, ChatGPT, or Cursor over MCP](/agentic-tools): 'draft replies to my unanswered 1-stars.'

Frequently asked

Do I need a service account to reply to Google Play reviews via API?
Yes. The reviews API is server-to-server, so there's no interactive login — you authenticate as a service account created in Google Cloud, using a JSON key and a token scoped to `androidpublisher`. Your personal Google login can't call the reviews endpoints directly.
What permission does the service account need to post replies?
The 'Reply to reviews' permission, granted inside Play Console (Setup → API access → Manage Play Console permissions, or under Users and permissions). Add 'View app information' too so list and get calls work. Linking the Cloud project alone does not grant this — it's a separate step.
What OAuth scope does the token need?
`www.googleapis.com/auth/androidpublisher` — the single scope covering the entire Google Play Developer API, including reviews.list, reviews.get, and reviews.reply. Request a token without it and calls fail with an insufficient-scope error.
Why do I get '401 this developer account does not own the application'?
Almost always because the service account was linked but never granted 'Reply to reviews', or access hasn't propagated yet (up to 24 hours). Also check the package name is exact and the app is in the service account's scoped list. The token is valid — it's a permission gap.
Where do I download the JSON key, and how do I keep it safe?
In Cloud Console, open the service account → Keys → Add key → Create new key → JSON. It downloads once. Treat it as a live credential: keep it out of git, store it in a secret manager, never ship it client-side, and rotate it if it leaks.
How long after setup can I start replying?
Once the project is linked, the API enabled, and the 'Reply to reviews' permission granted, calls usually work within minutes — but Google says permission changes can take up to 24 hours to propagate. If your first call 401s immediately after setup, wait and retry before debugging.

The whole setup is two handshakes people mistake for one: link the Cloud project so your apps are visible, then grant 'Reply to reviews' so they're writable — with the `androidpublisher` scope on the token and the JSON key locked down. Nail those and the 401 evaporates. If you'd rather skip the plumbing and answer reviews across both stores before the moment passes, [start free with ReplyArgus](/signup) — no card, and it drafts your first reply in minutes, already fitted to Play's 350-character limit.

Try it

Let Argus draft your next reply.

Watch it answer a real review in your voice. 10-day trial, no card to begin.

See the features or pricing.

Keep reading