• Reviews
  • Alerts
  • Mobile apps

App Store review alerts: how to get new App Store and Google Play reviews in Slack

Set up App Store review alerts for iOS and Google Play with the official APIs, their limits, and a Node.js script that posts new reviews to Slack.

Author
Extenify Team
Published
Reading time
12 min read
Hand holding a smartphone with a purple lock screen showing the time 15:56, against a plain grey background

App Store review alerts are the cheapest early-warning system a mobile team can have. A broken login, a crash on one device family or a confusing paywall shows up in written reviews hours or days before it moves your average rating, and long before anyone files a support ticket. The trouble is that neither App Store Connect nor the Google Play Console is built to put each new review in front of the people who can fix the problem.

This guide shows how to build App Store review alerts yourself with the official APIs from Apple and Google: what each API returns and where it stops, a small Node.js script that sends new reviews to a Slack channel, and the routing rules that keep the channel useful instead of noisy. It also covers what to do about ratings without text, which neither API lists.

Key takeaways

  • Apple's App Store Connect API lists written customer reviews for your app with rating, title, body, territory and date. Its webhooks cover builds and app versions, not reviews, so you have to poll.
  • Google Play's reviews API returns only reviews with text, created or modified within the last week, at up to 100 per page and 200 GET requests per hour.
  • Neither API lists star-only ratings. Track the average and count from the public listing or Google's ratings reports instead.
  • Store review IDs you have already posted, seed them on the first run, and never treat a failed request as "no new reviews."
  • Route one- and two-star reviews to the people who own the fix, and alert on review spikes, not just single reviews.

What each store gives you

There are four official ways to read reviews programmatically. They differ in coverage, freshness and effort.

Source What it returns Limits Auth
App Store Connect API, GET /v1/apps/{id}/customerReviews Your app's written reviews: rating, title, body, reviewer nickname, territory, created date Sort by createdDate or rating, filter by rating and territory API key and signed JWT
App Store customer reviews RSS feed The most recent reviews for any app, one country at a time 50 reviews per page, 10 pages per country in our tests None
Google Play Developer API, reviews.list Your app's reviews with text, including star rating, app version, device and language Last 7 days only, text reviews only, 200 GET requests per hour Service account
Play Console reviews export Monthly CSV files of all your reviews in Google Cloud Storage Not real time; Google says data is "posted within 3 to 7 days" Cloud Storage access

Two of these deserve a closer look before you build anything.

Apple has no review webhook. App Store Connect added webhooks, but the event types Apple documents (in its WebhookEventType reference) cover app version state, builds, TestFlight feedback, background assets and alternative distribution. There is no customer review event, so alerts mean polling.

Google only looks back one week. Google's reply to reviews guide is explicit: "The API shows only the reviews that include comments" and "You can retrieve only the reviews that users have created or modified within the last week." If your poller is down for eight days, the gap is permanent unless you backfill from the Play Console's CSV export. It is also why reviews.list can come back empty for an app with years of reviews: nothing was written or edited in the last week.

Step 1: Read Google Play reviews with a service account

You no longer need to link a Google Cloud project to your Play developer account. Per Google's getting started guide, create a service account in Google Cloud, enable the Google Play Android Developer API, then invite the service account's email address on the Users and permissions page of the Play Console and grant it access to the app's reviews.

Then page through reviews.list:

import { GoogleAuth } from 'google-auth-library';

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

export async function playReviews(packageName) {
  const reviews = [];
  let token;
  do {
    const url = new URL(
      `https://androidpublisher.googleapis.com/androidpublisher/v3/applications/${packageName}/reviews`,
    );
    url.searchParams.set('maxResults', '100');
    if (token) url.searchParams.set('token', token);

    const { data } = await play.request({ url: url.toString() });
    for (const review of data.reviews ?? []) {
      const comment = review.comments?.[0]?.userComment;
      if (!comment) continue;
      reviews.push({
        store: 'Google Play',
        // An edited review keeps its id, so include the edit time in the key.
        key: `${review.reviewId}:${comment.lastModified.seconds}`,
        rating: comment.starRating,
        text: comment.text.trim(),
        version: comment.appVersionName ?? 'unknown',
        locale: comment.reviewerLanguage ?? 'unknown',
      });
    }
    token = data.tokenPagination?.nextPageToken;
  } while (token);
  return reviews;
}

Notes on the fields, from the Review resource:

  • starRating is 1 to 5, and appVersionName tells you which build the review is about. That is the single most useful field after a release.
  • lastModified changes when a user edits a review. Keying on review ID plus edit time means a five-star review that turns into a one-star review after your update gets posted again, which is exactly the case you want to see.
  • translationLanguage is an optional query parameter that translates reviews, useful when your team reads one language and your users write in twenty.
  • Google allows 100 results per page and 200 GET requests per hour per app. Polling every 15 minutes uses a handful of requests per hour.

Step 2: Read App Store reviews with the App Store Connect API

Create a team API key in App Store Connect under Users and Access > Integrations, with the narrowest role that can see customer reviews. Download the .p8 private key once (Apple does not let you download it again), and note the key ID and issuer ID.

Every request needs a JWT signed with ES256. Apple's token guide requires the key ID in the header, your issuer ID as iss, appstoreconnect-v1 as the audience, and an expiry: "Tokens that expire more than 20 minutes into the future are not valid" for most resources.

import { SignJWT, importPKCS8 } from 'jose';

const key = await importPKCS8(process.env.ASC_PRIVATE_KEY, 'ES256');

async function appStoreToken() {
  const now = Math.floor(Date.now() / 1000);
  return new SignJWT({})
    .setProtectedHeader({ alg: 'ES256', kid: process.env.ASC_KEY_ID, typ: 'JWT' })
    .setIssuer(process.env.ASC_ISSUER_ID)
    .setIssuedAt(now)
    .setExpirationTime(now + 15 * 60)
    .setAudience('appstoreconnect-v1')
    .sign(key);
}

export async function appStoreReviews(appId) {
  const url = `https://api.appstoreconnect.apple.com/v1/apps/${appId}/customerReviews?sort=-createdDate&limit=100`;
  const res = await fetch(url, {
    headers: { Authorization: `Bearer ${await appStoreToken()}` },
  });
  if (!res.ok) throw new Error(`App Store Connect returned HTTP ${res.status}`);
  const { data } = await res.json();
  return data.map((review) => ({
    store: 'App Store',
    key: review.id,
    rating: review.attributes.rating,
    text: [review.attributes.title, review.attributes.body].filter(Boolean).join('\n'),
    version: 'n/a',
    locale: review.attributes.territory,
  }));
}

The customer reviews endpoint supports sort (createdDate, -createdDate, rating, -rating), filter[rating] (for example 1,2 for only the bad ones), filter[territory], and exists[publishedResponse] to find reviews you have not answered yet. Sorting newest first and reading the first page every poll is enough for most apps; follow the links.next URL only when you expect more than one page of new reviews between polls.

No API key? The public RSS feed

For a quick look at any app, including a competitor's, Apple still serves a public customer reviews feed per country:

https://itunes.apple.com/us/rss/customerreviews/page=1/id=<app-id>/sortby=mostrecent/json

When we tested it on October 4, 2026, each page held 50 reviews and page 11 returned nothing, so the feed covers at most the latest 500 reviews per country. Each entry includes the rating, title, text and app version. It is unofficial in the sense that Apple does not document it for developers, so use it for monitoring, not for anything you cannot afford to lose.

Step 3: Remember what you already posted

The script needs a memory, or every poll reposts the same reviews. A small JSON file is enough for one app; use your existing database for more.

import { readFile, writeFile } from 'node:fs/promises';

const STATE_FILE = 'seen-reviews.json';

async function loadSeen() {
  try {
    return new Set(JSON.parse(await readFile(STATE_FILE, 'utf8')));
  } catch {
    return null; // first run
  }
}

export async function newReviews(fetched) {
  const seen = await loadSeen();
  const firstRun = seen === null;
  const known = seen ?? new Set();
  const fresh = fetched.filter((review) => !known.has(review.key));
  for (const review of fresh) known.add(review.key);
  await writeFile(STATE_FILE, JSON.stringify([...known]));
  // Seed silently on the first run instead of flooding the channel.
  return firstRun ? [] : fresh;
}

Two rules matter more than the code:

  1. Seed on the first run. Otherwise the first poll posts every review from the last week (Google) or the first page (Apple) at once, and the team mutes the channel on day one.
  2. A failed fetch is not an empty result. If Apple returns a 401 because a token expired, or Google returns a 429 because you hit the quota, log it and alert on the failure itself. Never let an error look like "no new reviews," because a silent poller is worse than no poller.

Step 4: Post new reviews to Slack

A Slack incoming webhook is the simplest destination: create one for the channel, keep the URL secret, and POST JSON to it.

export async function postToSlack(review) {
  const text = [
    `*${review.rating}/5* on ${review.store} (${review.locale}, version ${review.version})`,
    `>${review.text.slice(0, 600).replace(/\n/g, '\n>')}`,
  ].join('\n');

  const res = await fetch(process.env.SLACK_WEBHOOK_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ text }),
  });
  if (!res.ok) throw new Error(`Slack webhook returned HTTP ${res.status}`);
}

Then wire the pieces together and run it on a schedule you already operate, such as every 15 minutes:

const fetched = [
  ...(await playReviews('com.example.app')),
  ...(await appStoreReviews('1234567890')),
];
for (const review of await newReviews(fetched)) {
  await postToSlack(review);
}

Write the rating as a number. Star glyphs look nice in a demo, but "2/5" is searchable in Slack and survives every client and screen reader.

Step 5: Route reviews so the alerts stay useful

One channel with every review works for a small app. Past a few dozen reviews a day, people stop reading it. Split by what someone has to do next:

Rule Destination Why
Rating 1 or 2 The on-call or product channel Most likely to describe a bug
Text mentions "crash", "login", "can't", "refund" or "charged" The team that owns that flow Fast path to the right owner
Five or more new reviews since the last poll A spike alert with a count A release or outage, not a single opinion
Rating 4 or 5 A daily digest Good for morale and quotes, not urgent
Review on a version older than the current one Low priority Usually already fixed

The spike rule catches what individual alerts miss. One angry review is noise; eight in an hour on the version you shipped this morning is an incident. Reading review and rating trends covers how to sort the review stream into themes once it is flowing, and setting up store change alerts your team will actually read covers channel choice and digest timing.

To answer reviews from the same workflow, both stores have write endpoints: Google's reviews.reply accepts replies of "at most 350 characters," and Apple's POST /v1/customerReviewResponses creates or updates a response. Keep a human in the loop for anything below four stars.

What about ratings without text?

Many users tap a star and leave. Neither API lists those ratings one by one, but you can still track them in aggregate:

  • Google Play: the Play Console writes ratings reports to Cloud Storage at gs://[developer_bucket_id]/stats/ratings/ratings_[package_name]_yyyyMM_[dimension].csv, with daily average and total average rating, according to Google's reports documentation. The same page describes the monthly reviews CSVs you can use to backfill history.
  • App Store: the public iTunes lookup endpoint, https://itunes.apple.com/lookup?id=<app-id>&country=us, returns averageUserRating and userRatingCount for the listing in that country. Snapshot it daily and alert when the count jumps or the average drops.

A falling average with no new written reviews usually means star-only ratings, often from an in-app rating prompt shown at the wrong moment.

Review alerts for browser extensions

If you also ship a browser extension, the picture is patchier. The Chrome Web Store has no public reviews API. Firefox exposes ratings and review text for any add-on through the AMO API, covered in the Firefox add-on stats guide. Microsoft Edge shows reviews in Partner Center with no documented notifications, as explained in Edge add-on analytics. A homegrown script that covers all of them ends up as five integrations with five failure modes.

App Store review alerts checklist

  1. Create a Play service account and invite it in the Play Console with access to reviews.
  2. Create an App Store Connect team API key with the narrowest role that can read reviews.
  3. Sign App Store Connect tokens with ES256 and an expiry under 20 minutes.
  4. Poll on a schedule well inside Google's 200 requests per hour, and never miss more than a few days, because Google only returns the last week.
  5. Key Google Play reviews on review ID plus edit time, so edited reviews alert again.
  6. Seed the seen-review list on the first run.
  7. Alert on poller failures separately from reviews.
  8. Route one- and two-star reviews to owners, digest the rest, and alert on spikes.
  9. Track star-only ratings through Google's ratings reports and the public App Store listing.

Frequently asked questions

How do I get notified of new App Store reviews?

Poll the App Store Connect API's customer reviews endpoint for your app, sorted by -createdDate, remember which review IDs you have seen, and post new ones to Slack, email or another channel. Apple's webhooks do not include a review event, so there is no push option.

Why does the Google Play reviews API only return recent reviews?

By design. Google says you "can retrieve only the reviews that users have created or modified within the last week," and only reviews with comments. For older reviews, download the monthly reviews CSV files from the Play Console's Cloud Storage bucket.

Can I get App Store or Google Play ratings that have no written review?

Not individually. Track them in aggregate: Google's monthly ratings reports give daily and total averages, and the public App Store listing shows the average rating and rating count.

How many reviews can I read from the App Store RSS feed?

In our October 2026 test, 50 reviews per page and 10 pages per country, so up to the 500 most recent reviews in each storefront. It needs no authentication and works for any app.

Can I reply to reviews through the APIs?

Yes. Google Play replies go through reviews.reply with a 350-character limit and a quota of 2,000 POST requests per day. App Store responses go through POST /v1/customerReviewResponses in the App Store Connect API.

Summary

App Store review alerts take an afternoon to build: a service account for Google Play, a signed JWT for App Store Connect, a list of review IDs you have already posted, and a Slack webhook. The details decide whether the alerts stay useful. Google only looks back seven days and only at reviews with text, Apple has no review webhook, and star-only ratings never show up in either API. Seed on the first run, alert on your own failures, route low ratings to owners, and watch for spikes.

If you would rather not maintain pollers for every store, Extenify tracks ratings and reviews for Google Play and App Store apps and for Chrome, Edge and Firefox extensions in one dashboard, and its daily change alerts flag new reviews, review spikes and rating changes by email, Slack, Discord, Telegram or Microsoft Teams. It checks once a day rather than every few minutes, which suits trend watching better than incident response. Your first listing is free; the pricing page covers larger portfolios.

Image credits

Put every store in one dashboard tonight.

Sign in with Google, paste one store link, and your unified view is live in under a minute. Free forever for one extension, and you never touch your extension's code.

Track my extension, free