# App Store Monitor — Version, Price, Rating & Listing Changes (`insight.solutions/app-store-monitor`) Actor

Watch App Store and Google Play listings on a schedule and get one row per change: new versions with release notes, price and in-app purchase changes, rating moves past your threshold, title and description edits, developer, category, size, minimum OS and installs band. Or a full snapshot.

- **URL**: https://apify.com/insight.solutions/app-store-monitor.md
- **Developed by:** [Insight Solutions](https://apify.com/insight.solutions) (community)
- **Categories:** Marketing, Business, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 changes

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## App Store Monitor — Version, Price, Rating & Listing Changes

**Watch App Store and Google Play listings on a schedule and get back one row per change — not the listing again.** A competitor ships a version: one `version` row with the old and new version, the store's release date and the new release notes. Their price, in-app price range, rating, title, description, developer, category, size, minimum OS or install band moves: one row for that family, with before and after. You pay a small fee for each listing a monitor run reads — **$0.0006 per app checked**, changed or not — plus **$2.00 per 1,000 changes**. A quiet daily run of six apps bills $0.0046; an app that could not be read is free.

Give it App Store and Play URLs, IDs or package names. No API key, no login, no browser.

**Input** — a daily competitor watch:

```json
{
  "apps": [
    "https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580",
    "https://play.google.com/store/apps/details?id=com.spotify.music",
    "570060128",
    "com.duolingo"
  ],
  "mode": "monitor",
  "countries": ["us"]
}
```

One change, one row — Spotify's App Store listing between two real captures a week apart:

```json
{
  "ok": true,
  "rowType": "change",
  "store": "apple",
  "appId": "324684580",
  "country": "us",
  "title": "Spotify: Music and Podcasts",
  "family": "version",
  "field": "version",
  "fields": ["version", "updatedAt"],
  "before": "9.1.80",
  "after": "9.1.82",
  "changes": [
    { "field": "version", "before": "9.1.80", "after": "9.1.82" },
    { "field": "updatedAt", "before": "2026-09-07T12:04:45.000Z", "after": "2026-09-14T08:31:16.000Z" }
  ],
  "diffSummary": "version “9.1.80” → “9.1.82”; updatedAt 2026-09-07 → 2026-09-14",
  "releaseNotes": "We’re always making changes and improvements to Spotify. …",
  "version": "9.1.82",
  "rating": 4.77374,
  "price": 0,
  "previousSnapshotAt": "2026-09-10T06:00:00.000Z",
  "currentSnapshotAt": "2026-10-07T06:00:00.000Z",
  "releasesLast90Days": 2,
  "storeUrl": "https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580"
}
```

The same comparison on Google Play reported the new update date and a real in-app price change — `"inAppPriceRange"` from `"$6.99 - $203.88 per item"` to `"$4.99 - $203.88 per item"`. Every row carries the same 69 columns, so a CSV export has one header whatever a run produced.

**Output** — in monitor mode, one `change` row per family that changed, a `baseline` row the first time a listing is seen, and one free `summary` row per store per run. In snapshot mode, one `app` row per listing with everything the store publishes. Anything that could not be read is a free diagnostic row (`ok: false`, `errorType`, `error`), never a charge.

**Price** — in monitor mode, $0.60 per 1,000 app checks (every listing read, changed or not, the first sighting included) plus $2.00 per 1,000 changes; in snapshot mode, $1.00 per 1,000 full listings and no check fee; $0.001 per run. Six apps watched daily for a month is about $0.15. Apps that could not be read, summaries and diagnostics are free, and a run that could not read a single listing bills nothing. Pay-per-event, limited permissions — works over the Apify MCP server (`mcp.apify.com`) and with agentic (x402) payments.

**From code** — `client.actor("insight.solutions/app-store-monitor").call(run_input={"apps": ["324684580", "com.spotify.music"], "mode": "monitor"})` with `apify-client`, or `POST https://api.apify.com/v2/acts/insight.solutions~app-store-monitor/run-sync-get-dataset-items`.

***

### Try it in 30 seconds

Hit **Start** with the input already filled in. It reads six listings — Spotify, Duolingo and Notion on both stores — in **snapshot** mode, so the first run shows you every field straight away and costs about $0.007.

It also stores a baseline for each of them. Switch `mode` to `monitor`, keep the same `stateStoreName`, and put it on a daily schedule: from then on each run returns only what changed. A day on which nothing moved bills six app checks and the start fee — $0.0046.

***

### How the change detection works

Each run reads every listing, compares it with the snapshot the previous run left in a named key-value store, and writes **one row per change family** that moved:

| `family` | Fields compared | App Store | Google Play |
|---|---|---|---|
| `version` | `version`, `updatedAt` (the store's release date of the current version), `releaseNotes` | all three | `updatedAt` and `releaseNotes`; `version` when the app publishes one |
| `price` | `price`, `currency`, `formattedPrice`, `isFree`, `inAppPurchases`, `inAppPriceRange` | price fields | price fields, plus the in-app purchase flag and price range |
| `rating` | `rating`, `ratingCount`, `ratingCurrentVersion`, `ratingCountCurrentVersion` — past your thresholds | all four | `rating`, `ratingCount` |
| `listing` | `title`, `subtitle` (Play's short description), `description` | title, description | all three |
| `metadata` | `developer`, `developerId`, `category`, `genres`, `contentRating`, `minimumOs`, `sizeBytes`, `screenshotCount`, `languages`, `installsText`, `containsAds` | all but installs and ads | all but size, genres and languages |

A family with several changed fields is still **one row** — a new version with new release notes is one `version` row with both in `changes[]` — so you pay once per thing that happened, not once per field.

Four rules decide what counts, each one taken from real captures:

**Ratings move against a reference, not against yesterday.** A rating that slides 0.02 a day never moves 0.1 between two runs, and a monitor comparing run to run would stay silent through a fall from 4.7 to 4.2. Each rating field is compared with the value it had when it was last *reported*; the reference moves only when a row is written. `ratingDeltaThreshold` (default 0.1 stars) and `ratingCountDeltaPct` (default 5%) set the bar, and `0` reports every move.

**A field that disappears is not a change.** Google Play stopped printing a version string for Spotify between two captures ("Varies with device"). A value that goes from known to unknown is never reported, and the last known value is kept, so when the field comes back it is compared with what it was.

**Lists are sets.** The two real Spotify App Store captures list the same content advisories in a different order. `genres` and `languages` are compared by membership, never by position.

**A description edit is a summary, not the text twice.** Descriptions are compared line by line after normalising whitespace and blank lines (a re-save with different line endings is not an edit). The row carries lines added and removed, character counts either side and the first 200 characters of what changed — `before` is the removed text, `after` the added text — not two copies of a 4,000-character description.

**`watch` gates what is built.** A family you did not tick is never built, never counted and never billed as a change (the listing's app check is billed either way: it pays for the read). The snapshot still moves past it, so ticking it later reports what happens next rather than everything since.

***

### Snapshot mode and monitor mode

- **`snapshot`** fetches every listing and returns it whole: one paid `app` row per app per country. It also stores a baseline for any listing that has none yet, so a later monitor run has something to compare against. It **never moves an existing baseline** — a snapshot taken between two monitor runs must not swallow the change the next monitor run would have reported.
- **`monitor`** reads every listing — **one `app-check` each, changed or not** — and returns one paid `change` row per changed family on top. The first time a listing is seen it writes a `baseline` row (title, developer, version, rating, price and the store link) and stores the snapshot; that read is billed as its check. A listing that did not change returns no row of its own (the per-store `summary` row counts it) — or, with `emitUnchanged`, a paid `app` row with the full listing.

#### Where the state lives

The memory is a **named key-value store** (`stateStoreName`, default `app-store-monitor-state`): an Actor's default store is recreated for every run, including every run of a schedule, so only a named one can carry yesterday's listing.

- **Limited permissions.** The Actor creates the store on its first run and re-opens its own store afterwards, which limited-permission Actors are allowed to do. Do not point `stateStoreName` at a store you made by hand; the Actor cannot read it.
- **One record per app per country**: the compared fields (descriptions and release notes included, so the next run can diff them), the rating references, and up to 90 days of daily readings. Measured on Spotify: about 5 KB on the first day, about 11 KB with a full 90 days of history.
- **A run lock**, with an expiry derived from your own `maxRunSecs`. Two runs sharing a store would each compare against the same snapshots and double-report every change, so the second one stops with a free `state-locked` row. Give concurrent schedules different store names.
- **90 days' retention.** A listing you stop watching falls out of the store by itself.

#### The outage guard

If **every** listing of one store fails in the same run — every Play page blocked, every App Store ID "not found" — that is a store-side or proxy fault far more often than news. The run writes one free `outage-guard` row for that store, compares nothing from it, leaves every snapshot exactly as it was and charges nothing. The next run compares them as normal. A failed listing is never reported as a change in any case: it is a free diagnostic row, and its snapshot is untouched.

***

### Use cases

- **Competitor release tracking.** Know the day a competitor ships, with their release notes, and how often they ship (`releasesLast30Days`, `releasesLast90Days`).
- **ASO watch.** Title, subtitle and description edits as a line summary — see which keywords a competitor just added to their description.
- **Pricing intelligence.** Upfront price changes, a free app going paid, in-app purchases appearing, and Play's in-app price range moving.
- **Reputation tracking.** Rating moves past a threshold you choose, per country, with the rating-count trend (`ratingCountDelta30d`).
- **Portfolio hygiene.** Watch your own apps: a developer name, category, content rating or minimum-OS change you did not expect, in every storefront you sell in.

***

### Input reference

| Key | Type | Default | What it does |
|---|---|---|---|
| `apps` | string\[] | — | App Store URLs (with or without the app name), numeric App Store IDs, Google Play URLs, Android package names. App Store bundle IDs as `ios:com.example.app`. Duplicates are read and billed once. |
| `mode` | enum | `monitor` | `monitor` (only what changed) or `snapshot` (every listing, whole). The Store form prefills `snapshot`. |
| `countries` | string\[] | `["us"]` | Two-letter storefront codes. Each app is read in each country, with its own history. Up to 50. |
| `language` | string | `en` | Google Play's page language (`hl`). App Store listings come in the storefront's own language. |
| `watch` | string\[] | all five | `version`, `price`, `rating`, `listing`, `metadata`. Applied before anything is billed. |
| `ratingDeltaThreshold` | number | `0.1` | Stars a rating must move from its last reported value. |
| `ratingCountDeltaPct` | number | `5` | Percent a rating count must move from its last reported value. |
| `emitUnchanged` | boolean | `false` | Monitor mode: also return a paid `app` row for each compared listing with no change. |
| `includeDescription` | boolean | `true` | Full description on `app` rows. `descriptionLength` is always there. |
| `includeReleaseNotes` | boolean | `true` | Release notes on `app` rows and, in full, on `version` change rows. |
| `includeScreenshots` | boolean | `false` | Screenshot URLs on `app` rows. `screenshotCount` is always there. |
| `webhookUrl` | string (secret) | — | Monitor mode: POST a JSON digest of the change rows when a run finds at least one. 10 s timeout, one retry, 64 KB cap, same-host redirects only. Only its host is ever logged. |
| `stateStoreName` | string | `app-store-monitor-state` | The named key-value store holding the snapshots. One per watchlist. |
| `maxApps` | integer | `500` | Apps past this are not read and not charged; one free row lists them. |
| `maxConcurrency` | integer | `4` | Requests in flight. Each worker keeps its own proxy session and spaces its requests 300–600 ms apart. |
| `maxRunSecs` | integer | `240` | Wall-clock budget. Listings not reached get a free `timeout` row and keep their snapshots. |
| `proxyConfiguration` | object | `{ "useApifyProxy": true }` | Apify datacenter proxy by default. |

### Output reference

`rowType` is `app`, `change`, `baseline`, `summary` or `diagnostic`. Every row carries every column; a column that does not apply is `null`.

**Identity** — `ok`, `rowType`, `mode`, `input`, `store` (`apple` or `google`), `appId` (App Store ID or package name), `bundleId`, `country`, `language`, `source`, `sourceUrl`.

**The listing** (in full on `app` rows) — `title`, `subtitle`, `developer`, `developerId`, `developerUrl`, `category`, `genres`, `price`, `currency`, `formattedPrice`, `isFree`, `inAppPurchases`, `inAppPriceRange`, `containsAds`, `rating`, `ratingCount`, `ratingCurrentVersion`, `ratingCountCurrentVersion`, `version`, `releasedAt`, `updatedAt`, `releaseNotes`, `description`, `descriptionLength`, `minimumOs`, `sizeBytes`, `installsText`, `contentRating`, `languages`, `screenshotCount`, `screenshotUrls`, `iconUrl`, `storeUrl`, `snapshotHash` (a fingerprint of everything compared except the rating block).

**What each store publishes.** The App Store's public lookup has **no subtitle, no in-app purchase flag and no ads flag**, so those are `null` on every App Store row. Google Play publishes **no file size, no language list and no per-version rating**, and for many apps no version string. `null` means "the store does not say", never zero or false.

**The change** (on `change` rows) — `family`, `field` (the first field that changed), `fields` (all of them), `before`, `after` (that first field's values), `changes` (`{field, before, after}` for each), `diffSummary` (one human line per field, with deltas and percentages), plus `title`, `developer`, `version`, `updatedAt`, `rating`, `price`, `currency` and `storeUrl` as they are now.

**History** (on `app`, `change` and `baseline` rows) — `firstSeenAt`, `previousSnapshotAt` (the age of the comparison), `currentSnapshotAt`, `historyDays`, `releasesLast30Days`, `releasesLast90Days` (distinct store release dates among this monitor's readings, the current version included), `ratingCountDelta30d`. These describe what *this monitor* has seen, which is why `historyDays` is there: a short watch is distinguishable from a quiet app.

**On `summary` rows** — per store: `appsRequested`, `appsChecked` (in monitor mode, the number of app checks billed for that store), `appsChanged`, `appsUnchanged`, `appsBaselined`, `appsFailed`, `changeCount`.

**On `diagnostic` rows** — `error` in plain language, and `errorType`: `not-found`, `blocked`, `timeout`, `unavailable`, `upstream-format`, `invalid-input`, `outage-guard`, `charge-limit`, `state-locked`, `state-read-failed`, `state-write-failed`, `webhook-failed` or `run-failed`. **None of them is ever charged for.**

Five dataset views are set up for you: **Changes**, **Listings**, **Releases**, **Run summaries** and **Problems**.

***

### Pricing

Pay per event:

| Event | FREE | BRONZE | SILVER | GOLD |
|---|---|---|---|---|
| Run started (`actor-start`) | $0.001 | $0.001 | $0.001 | $0.001 |
| **Change (`change`)** | **$0.002** | **$0.002** | **$0.0016** | **$0.0012** |
| App checked (`app-check`) — monitor mode | $0.0006 | $0.0006 | $0.00048 | $0.00036 |
| App snapshot (`app`) | $0.001 | $0.001 | $0.0008 | $0.0006 |

**$2.00 per 1,000 changes, on top of $0.60 per 1,000 app checks.** A monitor has to read every listing on every run to find the few that changed, and the check fee pays for that read — so a quiet watchlist costs a little, not nothing. Snapshot mode bills the full listing row instead and never a check. The start fee is billed once per run, together with the first event it bills.

| Run (FREE tier) | Bills |
|---|---|
| The prefill: snapshot of 6 listings | **$0.007** |
| First monitor run, 6 apps (6 baselines = 6 checks) | **$0.0046** |
| Daily monitor run, 6 apps, nothing moved (6 checks) | **$0.0046** |
| Daily monitor run, 6 apps, one competitor shipped (6 checks + version and size rows) | **$0.0086** |
| 6 apps daily for a month, a handful of changes (≈ 180 checks + 6 changes) | **≈ $0.15** |
| 50 apps × 2 countries daily for a month, ~8 changes a day | **≈ $2.31** |
| A run whose every app was not found or blocked | **$0** |

#### What you are never charged for

| Situation | Billed? |
|---|---|
| A listing seen for the first time (`baseline` row) | Its app check only — the row adds nothing |
| A listing that did not change | Its app check only — plus an `app` row if you turn on `emitUnchanged` |
| A snapshot-mode run | Never an app check — one `app` row per listing |
| An app that is not found, blocked, timed out or unreadable | No |
| A store held back by the outage guard | No |
| A listing the run never reached — `maxRunSecs` or your cost limit | No, and its snapshot is untouched |
| `summary` rows and every diagnostic row | No |
| A webhook that could not be delivered | No — a free `webhook-failed` row |
| A run that could not read a single listing | Nothing at all, start fee included. Like every run with usable input — a quiet one says "0 changes across 6 apps · 6 checked" — it finishes **SUCCEEDED**. It finishes **FAILED** only when there was nothing usable to attempt (no entry is an app), the state store is locked by another run, or the Actor itself hit an error |
| A change already delivered | No — the snapshot moves past exactly what was delivered |

***

### Limits, and the ones that might bite

- **The App Store lookup is not the App Store page.** It has no subtitle, no in-app purchase list and no "Contains ads" badge. Those columns are null on App Store rows rather than guessed.
- **Google Play often has no version string.** For apps that ship different builds per device, Play shows "Varies with device". On those, a new release shows up as a new `updatedAt` (and usually new release notes) — still a `version` row.
- **`containsAds` and `inAppPurchases` on Play come from the badges Play prints.** No badge means `false`. If Play rearranges its page, those are among the first fields that could read wrong — see the last point.
- **Size moves with nearly every App Store release.** A new version usually means a `version` row *and* a `metadata` row for `sizeBytes`. Untick `metadata` if you only care about releases.
- **A bare reverse-DNS string is read as an Android package.** `com.spotify.client` (iPhone) and `com.spotify.music` (Android) look alike; write an App Store bundle ID as `ios:com.spotify.client`.
- **The storefront in a URL is ignored.** `countries` decides where each app is read, so the same app pasted from two countries is one entry.
- **A rating that swings back and forth by more than your threshold is reported each time it does.** Each report moves the reference, so a rating going 4.5 → 4.6 → 4.5 with a 0.1 threshold is two rows. Raise `ratingDeltaThreshold` if your watchlist is noisy.
- **The upstream format may change.** Apple's lookup is a long-standing public JSON endpoint; Google Play is an HTML page whose data blocks are read by position, and Google owes nobody a stable layout. The parsers are written against real captures and pinned by tests, but a change upstream can turn readings into `upstream-format` diagnostic rows. Those are free and say what happened.

***

### Use it from an AI agent, or from code

One JSON object in, one flat array out. The Actor runs with **limited permissions**, uses **pay-per-event** pricing and never enters Standby, so it works over the Apify MCP server and with x402 agentic payments. The **Integrations** tab pushes results to Slack, a webhook, Zapier, Make, Google Sheets or BigQuery — or set `webhookUrl` for a single digest per run.

```bash
curl -X POST "https://api.apify.com/v2/acts/insight.solutions~app-store-monitor/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"apps":["324684580","com.spotify.music"],"mode":"snapshot","countries":["us","gb"]}'
```

```python
## pip install apify-client
from apify_client import ApifyClient

client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("insight.solutions/app-store-monitor").call(run_input={
    "apps": ["324684580", "com.spotify.music", "570060128", "com.duolingo"],
    "mode": "monitor",
    "watch": ["version", "price", "rating", "listing"],
    "stateStoreName": "my-competitor-apps",
})

for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row["rowType"] == "change":
        print(row["store"], row["title"], row["family"], row["diffSummary"], sep=" | ")
```

Keep one `stateStoreName` per watchlist and put the task on a daily schedule. The first run records baselines; every run after it returns only what moved.

***

### FAQ

**Do I need an API key or a developer account?**
No. Apple's public lookup (`itunes.apple.com/lookup`) and Google Play's public app pages are what any browser reads. No login, no cookies, no account.

**Why did my first monitor run return no change rows?**
There was nothing to compare against yet. Each listing got a `baseline` row and was billed as one app check — reading it the first time is the same work as every later check — so six apps cost $0.0046. The next run reports changes. If you want the full listings now, run once in `snapshot` mode instead.

**Why does a monitor run that found nothing cost anything?**
Because finding nothing still means reading every listing — one App Store record or one 1.2 MB Play page per app per country. That read is the `app-check` fee, $0.0006 per listing; the change fee is only for what moved. Six apps checked daily for a month is 180 checks ($0.108) plus 30 start fees ($0.03).

**Why is `subtitle` null on App Store rows?**
Apple's public lookup does not include the subtitle. Rather than guess, the column is null. On Google Play it holds the short description.

**A competitor's rating dropped 0.05 — why no row?**
The default threshold is 0.1 stars. The drop is remembered against the last reported value, so when it reaches 0.1 in total you get one row with the full move. Set `ratingDeltaThreshold` to `0` to see every move.

**Can I watch the same app in several countries?**
Yes. Put the codes in `countries`; each app-and-country pair is its own listing, with its own history and its own rows.

**Will a snapshot run mess up my monitor?**
No. Snapshot mode only stores a baseline for listings that have none; it never moves one that a monitor run is using.

**Is the webhook URL safe to paste?**
It is stored as a secret input, sent only to the host you gave, never followed to another host, and only its host ever appears in a log line or a row.

***

### Legal and data-protection notes

- **Public store data only.** Listing fields Apple and Google publish to any visitor: names, versions, prices, ratings as aggregates, descriptions, categories.
- **No reviewer data of any kind.** No reviews, no review text, no reviewer names, no review IDs. Ratings are the store's own averages and counts.
- **The developer is the publisher of record**, exactly as the store prints it on every listing — a company or an independent publisher name. Contact details Play shows for the developer (support email, address) are not collected.
- **No cookies that identify anyone, no login, no account.** Requests are paced — 300–600 ms between requests of one worker — and a refused request is retried once from a fresh exit and then left alone.
- You are responsible for how you use the data, including any contractual or competition-law limits that apply to you.

***

### Our other Actors

Every Insight Solutions Actor is pay-per-result with no browser, no login and no API key, and every one of them returns free diagnostic rows instead of billing for failures. Prices are per 1,000 results.

**Video, audio & social**

- [YouTube Transcript API](https://apify.com/insight.solutions/youtube-transcript-api) — captions as timed segments, text, SRT or VTT, with language fallback and translation.
- [YouTube Comments API](https://apify.com/insight.solutions/youtube-comments-api) — comments and replies with likes, pinned and hearted flags, newest or top sort.
- [YouTube Channel API](https://apify.com/insight.solutions/youtube-channel-api) — a channel's videos, Shorts and live streams, plus YouTube search.
- [Podcast Search, Episodes & Charts API](https://apify.com/insight.solutions/podcast-api) — Apple Podcasts search, charts and full episode feeds.
- [Bluesky Scraper](https://apify.com/insight.solutions/bluesky-scraper) — profiles, posts, followers and follows from the public AT Protocol API.
- [Telegram Channel Scraper](https://apify.com/insight.solutions/telegram-channel-scraper) — posts, views and channel stats from public Telegram channels.
- [Substack Scraper](https://apify.com/insight.solutions/substack-scraper) — posts with full free text, comments and publication profiles.
- [Hacker News API](https://apify.com/insight.solutions/hacker-news-api) — stories, comments, users, front page and a structured "Who is hiring?" parser from the official HN APIs.
- [GitHub Repos, Trending & Releases API](https://apify.com/insight.solutions/github-repos-api) — repository facts, trending lists, releases and search, no token needed for small runs.
- [Discourse Forum API](https://apify.com/insight.solutions/discourse-forum-api) — topics, posts and categories from any Discourse community via its own JSON endpoints, usernames only.

**News, documents & the web**

- [Google News Search, Topics & Real Article URLs](https://apify.com/insight.solutions/google-news-api) — news search and topic feeds with the publisher's real URL decoded.
- [Website to Markdown — Content Extractor for LLMs & RAG](https://apify.com/insight.solutions/website-content-extractor) — any site as clean Markdown, text and heading-aware chunks.
- [WordPress Posts & Pages API](https://apify.com/insight.solutions/wordpress-posts-api) — posts and pages from any WordPress site as clean text or Markdown, with categories, tags and images.
- [Website Metadata API](https://apify.com/insight.solutions/website-metadata-api) — any URL's meta tags, Open Graph, Twitter cards, hreflang, feeds, JSON-LD and microdata, with normalised Product, Article, Event and FAQ entities.
- [Subdomain Finder API](https://apify.com/insight.solutions/subdomain-finder-api) — every subdomain of a domain from certificate-transparency logs, resolved over DNS, with an optional live HTTP check.
- [Internet Archive API](https://apify.com/insight.solutions/internet-archive-api) — archive.org search, item metadata, files and reviews.
- [Wayback Machine Toolkit](https://apify.com/insight.solutions/wayback-toolkit) — archived URL inventories, snapshots and text diffs between dates.
- [Website Technology Detector](https://apify.com/insight.solutions/website-tech-detector) — the tech stack behind any site, with the evidence for each detection.
- [Domain Intelligence API](https://apify.com/insight.solutions/domain-intelligence-api) — DNS, RDAP registration, TLS certificate and HTTP facts in one row per domain.
- [SEO Page Audit](https://apify.com/insight.solutions/seo-page-audit) — sitemap crawl with on-page checks, structured data and broken-link reports.
- [Keyword Suggestions API](https://apify.com/insight.solutions/keyword-suggestions-api) — Google, YouTube, Bing, Amazon and eBay autocomplete with alphabet and question expansions.
- [Website Contact Extractor](https://apify.com/insight.solutions/website-contact-extractor) — emails, phone numbers and social profiles from any list of websites.
- [Web Search Results API](https://apify.com/insight.solutions/web-search-api) — Bing and DuckDuckGo organic results with snippets, no key, no browser.
- [Company Enrichment API](https://apify.com/insight.solutions/company-enrichment-api) — a domain in, a company profile out: firmographics, contacts, tech stack, DNS and hiring signal.
- [Company Dossier API](https://apify.com/insight.solutions/company-dossier-api) — one company in, twelve sections out: profile, tech, contacts, DNS, open roles, news, SEC filings, federal awards, recalls, YC batch and apps.
- [Press Releases API](https://apify.com/insight.solutions/press-releases-api) — GlobeNewswire and PR Newswire releases plus any newsroom feed, by keyword, company, ticker or subject.
- [Federal Register API](https://apify.com/insight.solutions/federal-register-api) — rules, proposed rules, notices and the Public Inspection desk with dockets, comment deadlines and CFR references.
- [Academic Papers Search API](https://apify.com/insight.solutions/academic-papers-api) — OpenAlex, Crossref, arXiv and PubMed in one row per paper: abstract, citations, open-access PDF, authors and venue.
- [RSS & Atom Feed Monitor](https://apify.com/insight.solutions/rss-feed-monitor) — any RSS, Atom or JSON feed (or an OPML file) in, only the new items out, with keyword filters and a webhook.
- [Website Change Monitor](https://apify.com/insight.solutions/website-change-monitor) — watch any pages, diff the text between runs, get change rows with added/removed lines, keyword alerts and a webhook.
- [Wikipedia & Wikidata API](https://apify.com/insight.solutions/wikipedia-api) — article text, search, daily pageviews and Wikidata entity facts, any language edition.

**Business, finance & jobs**

- [Congress & Insider Trades API](https://apify.com/insight.solutions/congress-insider-trades-api) — STOCK Act periodic transaction reports and SEC Form 4 insider trades in one schema.
- [Federal Contracts, Grants & Lobbying API](https://apify.com/insight.solutions/federal-contracts-grants-api) — SAM.gov opportunities, USAspending awards, Grants.gov notices and Senate lobbying filings in one schema.
- [SEC EDGAR API](https://apify.com/insight.solutions/sec-edgar-api) — filings, XBRL financials and full-text search by ticker or CIK.
- [Clinical Trials & FDA API](https://apify.com/insight.solutions/clinical-trials-fda-api) — ClinicalTrials.gov studies plus openFDA recalls, labels, approvals, 510(k)s and adverse-event reports.
- [Product & Vehicle Recalls API](https://apify.com/insight.solutions/product-recalls-api) — CPSC, NHTSA, FDA and USDA recalls, vehicle complaints and ratings, plus a VIN decoder.
- [Y Combinator Companies, Batches & Founders](https://apify.com/insight.solutions/yc-companies-directory) — the YC directory with founders and social links, filterable by batch, industry and hiring status.
- [Career Site Jobs API](https://apify.com/insight.solutions/ats-jobs-api) — jobs straight from Greenhouse, Lever, Ashby, Workable and 10+ other ATS career sites.
- [Workday Jobs API](https://apify.com/insight.solutions/workday-jobs-api) — every posting on any Workday career site, with facets, search, posted dates and full descriptions.
- [New Job Postings Monitor](https://apify.com/insight.solutions/job-postings-monitor) — new, closed and changed postings on the career sites you watch.
- [Hiring Signals API — Open Roles & Hiring Surge by Company](https://apify.com/insight.solutions/hiring-signals-api) — one row per company per run: open roles, what opened and closed, department and seniority breakdowns, and a hiring-surge flag.
- [Remote Jobs API](https://apify.com/insight.solutions/remote-jobs-api) — RemoteOK, Remotive, We Work Remotely, Himalayas, Jobicy and more in one schema, deduplicated.
- [Shopify Products API](https://apify.com/insight.solutions/shopify-products-api) — any Shopify store's catalogue, variants, prices and stock signals.
- [WooCommerce Products API](https://apify.com/insight.solutions/woocommerce-products-api) — any WooCommerce store's catalogue, prices, variants and stock through its public Store API.
- [Shopify App Store API](https://apify.com/insight.solutions/shopify-app-store-api) — Shopify App Store listings by category, collection or developer: pricing plans, ratings and merchant reviews.
- [Luma Events API](https://apify.com/insight.solutions/luma-events-api) — upcoming Luma events by city, category or calendar: dates, venue, price, capacity and organiser calendar, no host names.
- [Shopify Store Monitor](https://apify.com/insight.solutions/shopify-store-monitor) — price drops, sales, restocks, sell-outs and new products on any Shopify store, one row per change.
- [Public Tenders API](https://apify.com/insight.solutions/public-tenders-api) — EU TED, UK Find a Tender and Contracts Finder notices by keyword, CPV code, country, stage and deadline.
- [Nonprofit & IRS 990 Lookup API](https://apify.com/insight.solutions/nonprofit-990-api) — search US nonprofits and get EIN, NTEE code and multi-year Form 990 financials.
- [OpenStreetMap Places API](https://apify.com/insight.solutions/osm-places-api) — businesses and points of interest by category and area from OpenStreetMap: name, address, coordinates, website, phone, opening hours.

**Apps & games**

- [App Store & Google Play Reviews API](https://apify.com/insight.solutions/app-reviews-api) — reviews from both stores with ratings, versions and developer replies.
- [App Store Top Charts & App Search API](https://apify.com/insight.solutions/app-charts-api) — Apple top charts by country and genre, plus app search and details.
- [App Store Keyword Rank Tracker](https://apify.com/insight.solutions/app-store-keyword-rank-tracker) — where any app ranks for any keyword on the App Store and Google Play, with rank changes and ASO suggestions.
- [Steam Reviews API](https://apify.com/insight.solutions/steam-reviews-api) — Steam reviews with playtime, helpfulness and game details.
- [Steam Game Data API](https://apify.com/insight.solutions/steam-store-stats-api) — prices, tags, review scores, live player counts and top charts.
- [Sports Scores & Schedules API](https://apify.com/insight.solutions/sports-scores-api) — scores, schedules, standings, teams and headlines for the NFL, NBA, MLB, NHL, soccer and more, no key.

# Actor input Schema

## `apps` (type: `array`):

One app per entry. An App Store URL (`https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580`, with or without the name in it), a numeric App Store ID (`324684580`), a Google Play URL (`https://play.google.com/store/apps/details?id=com.spotify.music`) or an Android package name (`com.spotify.music`) all work. An App Store **bundle ID** looks exactly like an Android package, so write it with a prefix: `ios:com.spotify.client`. The country in a URL is ignored — `countries` decides which storefronts are read. The same app written twice is read and billed once.

## `mode` (type: `string`):

`snapshot` returns every listing whole — one paid `app` row per app per country, no check fee — and stores a baseline for any listing that has none yet, so a later monitor run has something to compare against. `monitor` reads every listing — one paid `app-check` each, changed or not, the first sighting included — compares it with the previous run and returns one paid `change` row per family that changed. A listing seen for the first time gets a `baseline` row; an unchanged one gets no row of its own. Schedule monitor mode daily.

## `countries` (type: `array`):

Two-letter storefront codes. Each app is read in each country and gets its own row and its own history: price, rating, title and even availability differ between storefronts. `gb`, not `uk`. Up to 50.

## `language` (type: `string`):

The language Google Play pages are requested in (`hl`), for example `en`, `de` or `pt-BR`. App Store listings always come in the storefront's own language.

## `watch` (type: `array`):

Which change families are worth a row. Applied **before** anything is billed: a family you did not tick is never charged for, and the snapshot still moves past it, so ticking it later reports what happens next rather than everything since.

## `ratingDeltaThreshold` (type: `number`):

Report a rating change when the average rating has moved at least this many stars since it was last reported. Compared with the last *reported* value, not yesterday's, so a slow slide is still caught once it adds up. `0` reports every move.

## `ratingCountDeltaPct` (type: `number`):

Report a rating-count change when the number of ratings has moved at least this many percent since it was last reported. `0` reports every move — on a popular app, that is every run.

## `emitUnchanged` (type: `boolean`):

Also write a full `app` row for every listing that was compared and had no change, billed as an app row on top of its app check. Off by default: a monitor's job is to stay quiet when nothing moved.

## `includeDescription` (type: `boolean`):

Put the whole store description on `app` rows. `descriptionLength` is always there. Change rows never carry the description twice: they carry the lines added and removed and the first 200 changed characters.

## `includeReleaseNotes` (type: `boolean`):

Put the current version's release notes ("What's new") on `app` rows and, in full, on `version` change rows.

## `includeScreenshots` (type: `boolean`):

Put every screenshot URL on `app` rows. `screenshotCount` is always there; the URLs are 40 per app on some Play listings, so they are off by default.

## `webhookUrl` (type: `string`):

When a monitor run finds at least one change, POST one JSON digest of the change rows to this URL. Ten-second timeout, one retry, 64 KB cap, and a redirect to another host is never followed. Treated as a secret: only its host is ever logged. A failed POST is a free `webhook-failed` row and never fails the run. Leave empty for no webhook.

## `stateStoreName` (type: `string`):

Name of the key-value store that holds each listing's last snapshot — one record per app per country. The Actor creates it on its first run and reads it back on every run after; that memory is what makes this a monitor. Keep one store per watchlist: two schedules sharing a store would compare against the same snapshots, so the second stops with a clear message instead of double-reporting. Snapshots not seen for 90 days expire.

## `maxApps` (type: `integer`):

Apps past this many are not read and not charged; one free row lists them.

## `maxConcurrency` (type: `integer`):

How many lookups and Play pages are in flight at once. Each parallel worker keeps its own proxy session, and its successive requests are spaced 300–600 ms apart.

## `maxRunSecs` (type: `integer`):

Wall-clock budget for the whole run. When it is reached the Actor stops fetching, keeps and bills what it already delivered, and writes a free `timeout` row for each listing it never reached — those keep their snapshots.

## `proxyConfiguration` (type: `object`):

Apple's lookup and Google Play's app pages both answer through Apify's datacenter proxy, so that is the default and its cost is inside the event prices. Switch to the RESIDENTIAL group if a store starts refusing it; a refused listing is a free `blocked` row after one retry from a fresh exit.

## Actor input object example

```json
{
  "apps": [
    "324684580",
    "com.spotify.music",
    "ios:com.spotify.client"
  ],
  "mode": "snapshot",
  "countries": [
    "us"
  ],
  "language": "en",
  "watch": [
    "version",
    "price",
    "rating",
    "listing",
    "metadata"
  ],
  "ratingDeltaThreshold": 0.1,
  "ratingCountDeltaPct": 5,
  "emitUnchanged": false,
  "includeDescription": true,
  "includeReleaseNotes": true,
  "includeScreenshots": false,
  "stateStoreName": "app-store-monitor-state",
  "maxApps": 500,
  "maxConcurrency": 4,
  "maxRunSecs": 240,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

Change rows (monitor mode) or whole listings (snapshot mode), with one summary row per store per run and free diagnostic rows saying why anything could not be read. Delivered as JSON items in the default dataset.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "apps": [
        "https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580",
        "https://play.google.com/store/apps/details?id=com.spotify.music",
        "570060128",
        "com.duolingo",
        "1232780281",
        "notion.id"
    ],
    "mode": "snapshot",
    "countries": [
        "us"
    ],
    "language": "en",
    "watch": [
        "version",
        "price",
        "rating",
        "listing",
        "metadata"
    ],
    "ratingDeltaThreshold": 0.1,
    "ratingCountDeltaPct": 5,
    "emitUnchanged": false,
    "includeDescription": true,
    "includeReleaseNotes": true,
    "includeScreenshots": false,
    "stateStoreName": "app-store-monitor-state",
    "maxApps": 500,
    "maxConcurrency": 4,
    "maxRunSecs": 240,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("insight.solutions/app-store-monitor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "apps": [
        "https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580",
        "https://play.google.com/store/apps/details?id=com.spotify.music",
        "570060128",
        "com.duolingo",
        "1232780281",
        "notion.id",
    ],
    "mode": "snapshot",
    "countries": ["us"],
    "language": "en",
    "watch": [
        "version",
        "price",
        "rating",
        "listing",
        "metadata",
    ],
    "ratingDeltaThreshold": 0.1,
    "ratingCountDeltaPct": 5,
    "emitUnchanged": False,
    "includeDescription": True,
    "includeReleaseNotes": True,
    "includeScreenshots": False,
    "stateStoreName": "app-store-monitor-state",
    "maxApps": 500,
    "maxConcurrency": 4,
    "maxRunSecs": 240,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("insight.solutions/app-store-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "apps": [
    "https://apps.apple.com/us/app/spotify-music-and-podcasts/id324684580",
    "https://play.google.com/store/apps/details?id=com.spotify.music",
    "570060128",
    "com.duolingo",
    "1232780281",
    "notion.id"
  ],
  "mode": "snapshot",
  "countries": [
    "us"
  ],
  "language": "en",
  "watch": [
    "version",
    "price",
    "rating",
    "listing",
    "metadata"
  ],
  "ratingDeltaThreshold": 0.1,
  "ratingCountDeltaPct": 5,
  "emitUnchanged": false,
  "includeDescription": true,
  "includeReleaseNotes": true,
  "includeScreenshots": false,
  "stateStoreName": "app-store-monitor-state",
  "maxApps": 500,
  "maxConcurrency": 4,
  "maxRunSecs": 240,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call insight.solutions/app-store-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,insight.solutions/app-store-monitor"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/nfxhLrsiiyc06QIyc/builds/p9VXsWPnMuifaOeLc/openapi.json
