# Apple App Store Search & App Metadata Monitor (`maydit/apple-app-store-discovery-monitor`) Actor

Discover iPhone apps by keyword or app ID across storefront countries. Export prices, ratings, versions and metadata changes with source links and saved comparisons.

- **URL**: https://apify.com/maydit/apple-app-store-discovery-monitor.md
- **Developed by:** [Brandt May](https://apify.com/maydit) (community)
- **Categories:** Developer tools
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.20 / 1,000 saved observations

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

## Apple App Store Search & App Metadata Monitor

Turn a keyword or app watchlist into structured app-market observations. Discover competitors across storefronts, follow release and price changes, and feed app research into spreadsheets or AI workflows with clear source evidence.

**Start with a keyword.** The default run searches the US storefront for `budget` and returns up to 10 iPhone app observations. No Apple account, API key, proxy or setup step is required.

| Use case | Choose | What you receive |
|---|---|---|
| Find competing apps | Keyword search | Apple Search API results in returned order, with product metadata |
| Compare markets | Multiple countries | Country-specific metadata, prices and API discovery windows |
| Track selected products | Known app IDs | Prices, ratings, rating counts, versions and release dates for your watchlist |
| Send meaningful updates downstream | Saved comparisons | New/changed/unchanged status, previous values and numeric differences |

### Quick start

1. Pick **What to discover** and a two-letter storefront country such as `us`, `gb` or `de`.
2. Enter search keywords, or paste numeric app IDs or Apple app links.
3. Set your source window and maximum saved records. Run the Actor, then open the dataset or readable run report.

Each record includes a stable `recordId`, Apple app URL, source endpoint, country, source context and observation time. Download JSON or CSV, call through the Apify API, or schedule the same input for ongoing monitoring. Use a private saved task when your keyword/watchlist is commercially sensitive.

### Three ready-to-run inputs

#### Budget app competitor discovery

```json
{"mode":"search","queries":["budget"],"countries":["us"],"resultsPerSource":5,"maxResults":5}
```

#### UK fitness app competitor discovery

```json
{"mode":"search","queries":["fitness"],"countries":["gb"],"resultsPerSource":5,"maxResults":5}
```

#### ChatGPT and Spotify release watch

```json
{"mode":"lookup","countries":["us"],"appIds":["6448311069","324684580"],"maxResults":2}
```

### Output you can use

| Fields | Meaning |
|---|---|
| `appId`, `appName`, `title`, `bundleId`, `developerName`, `sellerName` | Source app and publisher metadata; title aliases appName for integrations |
| `country`, `sourceType`, `sourceKey`, `position`, `positionKind` | Storefront and exact keyword/lookup context; lookup positions are null |
| `price`, `currency` | Observed storefront price; a free download can still contain paid features |
| `averageUserRating`, `ratingCount` | Source-reported overall rating and rating count, not review text |
| `currentVersionRating`, `currentVersionRatingCount` | Current-version metrics where Apple provides them |
| `version`, `releaseDate`, `currentVersionReleaseDate`, `minimumOsVersion` | Published release and OS metadata |
| `genres`, `languages`, `contentAdvisoryRating`, `description` | Product context; description text is normalized and capped at 16,000 characters |
| `descriptionHash`, `descriptionTruncated` | SHA-256 of the full whitespace-normalized description and whether displayed text was truncated |
| `url`, `sourceUrl`, `observedAt` | App link and auditable collection evidence |
| `comparisonStatus`, `changedFields`, `previous`, `previousObservedAt` | Comparison with the last saved observation for the same app/context |
| `positionChange`, `priceChange`, `ratingCountChange`, `ratingChange` | Observed numeric differences; positive positionChange means movement toward position 1 in the API response |

Unreported source fields stay `null`. Zero is retained only when the source actually reports zero. Price differences require the same known currency; no currency conversion is attempted. There are no estimated downloads, revenue figures, AI scores or invented fallback apps.

### Understand the discovery window

Keyword positions describe the order of the **Apple Search API response**. They are not a claim about personalized search in the App Store app, a universal ASO ranking, official chart positions, or historical positions before this Actor observed them.

One row is one app in one source/country context. An app matching two keywords creates two useful contextual rows and two row charges. Repeated identical contexts are deduplicated. Search can return fewer apps than requested. The first-page search window is limited to 100 results per keyword/country and has no hidden pagination. This is bounded discovery, not an exhaustive App Store catalog.

Lookup mode requests all selected IDs, up to 100 per country. An app URL supplies its numeric ID; the selected countries determine the storefronts queried. Every emitted Apple URL must match both the requested storefront and app identity.

### Saved comparisons that respect incomplete runs

Enable `comparePrevious`, keep the same scope and choose a `snapshotName`. The first complete run establishes history; later runs report changes. Enable `onlyChanges` to save only new or changed rows.

History is scoped to mode, countries, keyword/app-ID selection and search-window size. It is committed only after all selected sources were parsed and every intended row was processed. A source failure, timeout, access refusal, charge limit or output cap that cuts a window leaves the previous baseline untouched. Concurrent writers are detected before commit; run the same named comparison serially.

An app missing from a later bounded search is not classified as removed or delisted. Lookup IDs not returned by Apple are listed in `SUMMARY`; they are not fabricated output rows. The last stored observation may predate the immediately preceding run if that run was incomplete or skipped unchanged records.

### Coverage and operating limits

- Up to six keyword-country combinations, or up to 100 known app IDs across three countries.
- Up to 100 apps per keyword, up to 1,000 saved rows, and a 30–120-second run budget.
- At most six main requests for search or three for ID lookup, plus one shared retry for a transient HTTP 502/503/504 response, request timeout, connection reset or temporary DNS failure. The same URL is retried only when at least 25 seconds remain; the overall deadline is never extended.
- Request starts, including the retry, are spaced at least 3.1 seconds apart within each run, below Apple's approximate 20-request/minute guidance. Avoid overlapping schedules; separate runs do not share a global throttle.
- Fixed documented public Search/Lookup API routes only. No login, authentication token, private endpoint, proxy rotation or retries around 401/403/429 access/rate refusals. Those responses stop subsequent requests. Use supported Apple storefront codes; unsupported codes can fail or return no usable observations.
- `SUMMARY.sourceAttempts` records each response status or transport error and whether the shared retry was used. Coverage distinguishes complete selected windows, partial work, empty matches, unchanged observations and limits. Platform success alone does not prove exhaustive coverage.

These are documented integration APIs, separate from webpage crawling. Source schemas and availability can change. Apple can omit or delay metadata. This Actor does not collect chart feeds, reviews, private analytics, paid content, purchase history, app binaries, installs or sales estimates.

### Pricing and cost control

The intended Store price is **$0.002 per saved app observation**, plus **$0.00005 per Actor start**. A five-row run is $0.01005 at those rates. The live Pricing tab is authoritative. Set the run's maximum charge and `maxResults` before running. Unchanged rows skipped with `onlyChanges`, source errors, coverage summaries and the HTML run report do not create dataset-item charges. Runtime/platform fees depend on your Apify plan.

### Sources and related tools

- [Apple Search and Lookup API documentation](https://performance-partners.apple.com/search-api)
- [Mayd It data tools](https://mayd-it.com/data-tools/) and [workflow recipes](https://mayd-it.com/data-tools/workflows/)
- For individual review records, use our separate [Apple App Store Review Monitor](https://apify.com/maydit/apple-app-store-review-monitor).

Need help? Open an issue on this Actor with the run ID, selected country/mode and expected result. Never include credentials. Apple and App Store names identify the data source; this Actor is independently operated by Mayd It.

# Actor input Schema

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

Search returns Apple API relevance order. Lookup returns known app metadata without a rank.

## `queries` (type: `array`):

Up to six phrases, each at most 100 characters. Used only in search mode; empty uses budget.

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

Up to three two-letter Apple storefront country codes. Examples: us, gb, ca, de, jp. At most six keyword-country combinations per run.

## `appIds` (type: `array`):

Up to 100 numeric IDs or https://apps.apple.com/.../id... links. Used only in lookup mode. Empty lookup uses ChatGPT and Spotify.

## `resultsPerSource` (type: `integer`):

A deliberate first-page window per keyword and country. Search may return fewer. No hidden pagination; lookup observes all selected IDs.

## `maxResults` (type: `integer`):

Total billable row cap. A row represents one app in one source/country context. A cap that cuts a selected window prevents any history commit.

## `comparePrevious` (type: `boolean`):

Save observations after every requested source window finishes. Compare price, rating, rating count, version and rank against the same named scope.

## `onlyChanges` (type: `boolean`):

Enables comparison and skips unchanged rows without dataset-item charges. First complete run establishes the baseline.

## `snapshotName` (type: `string`):

1–80 letters, numbers, underscores or hyphens. History is scoped to mode, countries, keyword/ID selection and search window.

## `maxRunSeconds` (type: `integer`):

Shared deadline. All Apple request starts are spaced by at least 3.1 seconds within this run; 403/429 stops subsequent requests.

## Actor input object example

```json
{
  "mode": "search",
  "queries": [
    "budget"
  ],
  "countries": [
    "us"
  ],
  "appIds": [],
  "resultsPerSource": 10,
  "maxResults": 30,
  "comparePrevious": false,
  "onlyChanges": false,
  "snapshotName": "default",
  "maxRunSeconds": 90
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

## `summary` (type: `string`):

No description

## `report` (type: `string`):

No description

# 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 = {
    "queries": [
        "budget"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("maydit/apple-app-store-discovery-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 = { "queries": ["budget"] }

# Run the Actor and wait for it to finish
run = client.actor("maydit/apple-app-store-discovery-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 '{
  "queries": [
    "budget"
  ]
}' |
apify call maydit/apple-app-store-discovery-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,maydit/apple-app-store-discovery-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/eubKiH3oaOZLf44FV/builds/WIfmHqWdDmXwZ6ovR/openapi.json
