# Apify Store Opportunity Radar: Gaps, Prices & Alerts (`clearfeedlabs/apify-store-market-intel`) Actor

Prioritize Actor ideas using public Store aggregate metrics: explainable category scores, compatible prices, your own weekly snapshots, and watchlist alerts. Not a listing mirror or a revenue forecast.

- **URL**: https://apify.com/clearfeedlabs/apify-store-market-intel.md
- **Developed by:** [Clearfeed Labs](https://apify.com/clearfeedlabs) (community)
- **Categories:** Developer tools, Business
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $100.00 / 1,000 opportunity reports

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

### What Apify Store Opportunity Radar does

**Apify Store Opportunity Radar** helps you shortlist Actor categories and monitor competitors from **public Store metrics**. A run reads the public Store listing, keeps aggregate numbers and derived scores, and writes a compact report. It does not copy descriptions, READMEs, images, or full listings.

The slug stays `apify-store-market-intel`. Scores are triage heuristics. They are not a demand forecast, a revenue estimate, or a promise of earnings.

### Who it is for

Use it to:

1. Shortlist categories that deserve a closer look before you build.
2. Compare prices only when the charge unit is the same.
3. Keep your own weekly snapshot and, on a later comparable scan, read watchlist changes for Actor ids observed both times.
4. Export a short JSON or markdown brief into product planning.

Public user counts are Apify-reported users of each Actor. They are not unique people across Actors, not paying customers, and not revenue.

### What a run returns

| Row | What it contains |
|---|---|
| `market-summary` | Actors observed, reported total, pages fetched, `coverage` (`observed-cohort` or `verified-complete`), sum of present 30-day user stats, result-unit median with its sample size, history outcome |
| `category-opportunity` | `demandScore`, `roomToWin`, `confidence`, `gapFlags`, growth only when both weeks are verified-complete, and the top Actors' metrics |
| `mover` | Week-over-week 30-day user increases for ids in both comparable snapshots, otherwise 7-day momentum |
| `price-change` | Model changes, or unit-price changes inside the same identified unit, for ids in both comparable snapshots. Cross-unit jumps are not listed as comparable price changes |
| `alert` | Watchlist price, user, rating, or reliability changes for Actor ids in both the verified-complete baselines or both observed cohorts. `dropped-from-store-listing` is stored only when both weeks are verified-complete |
| `watchlist-coverage` | `not-observed-this-scan` when an id is outside this observed cohort. Not a removal and not an alert charge |
| `category-deep-dive` | Leaderboard and result-unit quartiles. New entrants are listed only when both weeks are verified-complete |

Every run also stores `REPORT`, `REPORT_MD`, and `RUN_SUMMARY` in the run key-value store. You can download the dataset as JSON, CSV, or Excel.

The first saved cohort for an ISO week is kept. A later run that same week does not replace it. Price and user changes are compared only for Actor ids that appear in both scans.

### Weekly history and same-week rules

The public Store list documents `count` as the number of items in the response and `total` as the size of that query. On the current API, a 1,000-item window can report `count: 1000` while `items.length` is lower. Small pages sometimes match. `total` also differs between `sortBy=popularity` and `sortBy=relevance`. Item length is not treated as proof that the whole Store was seen.

Each run requests `GET /v2/store` with `sortBy=popularity`, `limit=1000`, and explicit offsets. There are two histories in the named store `apify-store-intel-history`, in **the account that runs the Actor**:

- **Verified-complete** baseline, only when every fetched page has `count` equal to `items.length`, the offset windows cover that response's `total`, and `maxPages` did not stop the crawl. Only this history can emit `dropped-from-store-listing`.
- **Observed cohort**, used whenever that rule is not met, including the current public 1,000-row pages. The record is `store-intel-sample-v1`. It stores the Actor ids actually returned, the sort, the offsets, and the shortfall. It does not replace a verified-complete baseline.

Weeks are ISO-8601 weeks in UTC (`YYYY-Www`). The key prefix is the Actor task id, or `notask`, plus `historyKey`. The sample claim also includes `maxPages`, so a 1-page cohort does not occupy a 30-page cohort. An ad-hoc run with no task id uses `notask`.

- The first snapshot of each kind in an ISO week is kept.
- A missing id on a cohort scan is `not-observed-this-scan`. It is not a removal, and it is not billed as an alert.
- Price, user, rating, and reliability alerts require the same Actor id in both comparable snapshots. Comparable cohorts use the same sort, page size, offsets, and `maxPages`.
- A missing stat stays null. It is not stored or scored as zero.
- A legacy snapshot from before this revision is not proof of a complete listing and does not raise alerts.
- On the Apify platform the named key-value store and the claim queue are opened with `forceCloud`, so they use the account Apify API client. If that client is missing, the run stops. It does not keep the weekly baseline on the container disk. Local runs keep using local storage. The store names are account-scoped. Task isolation stays in the key prefix `{taskId}__{historyKey}`.
- A complete listing claims that week by inserting one request-queue record whose `uniqueKey` is `store-intel-claim-v2:{scope}:{week}`. The queue accepts that key once. The losing run does not write a snapshot.
- The claim is not deleted, marked handled, or reclaimed. If the winning run crashes before the snapshot is stored, later runs fail instead of taking the slot. Use a new `historyKey` for a new baseline, or rerun only after the winning snapshot is present.
- Key-value storage holds the snapshot body. It is not used as a lock.

Schedule the same `historyKey` and `maxPages` weekly if you want the next scan to compare with this cohort. Actors that fall outside the fetched offsets are reported as not observed, not deleted.

### Pricing

This Actor does not charge the platform start event itself. Apify charges `apify-actor-start` automatically: **$0.00005 per event, one event up to and including 1 GB, then one more event per additional GB** (partial gigabytes round up). Published examples: 128 MB and 1 GB are one event ($0.00005); 4 GB is four events ($0.00020). The default memory in this source is 1024 MB. A task that selects more memory, up to the 4096 MB maximum set here, scales only the start fee.

| Event | Price | Charged when |
|---|---|---|
| Actor start | $0.00005 per GB, minimum one | Platform, at run start. Not charged again in code |
| `snapshot` | $0.02 | After the market-summary row, `REPORT`, and `REPORT_MD` are stored |
| `gap-report` | $0.10 | After category, mover, and price-change rows are stored, and only if `includeGapReport` is on |
| `alert` | $0.02 | Once per stored alert row. No row means no charge |
| `deep-dive` | $0.25 | Once per stored deep-dive row. At most five. An empty category is not charged |

A failed run that stops before the matching artifact is stored does not charge that event. An incomplete listing can still store an honest summary and, if you asked for it, a report marked incomplete. Those stored artifacts are charged. They do not update the weekly baseline, and they do not create dropped-from-listing alerts.

**Examples at 1 GB or less (one start event):**

- Snapshot and opportunity report: $0.00005 + $0.02 + $0.10 = **$0.12005**
- That run plus 3 stored alerts and 1 stored deep-dive: $0.12005 + $0.06 + $0.25 = **$0.43005**

**Same snapshot and report at 4 GB:** start is $0.00020, so the total is **$0.12020**. At 2 GB the start is $0.00010 and the total is **$0.12010**.

Alert and deep-dive totals are the sum of the rows this run stores. A run with no alert rows pays no alert events.

### How prices are compared

`pricePer1kUsd` is the FREE-tier list price of one **result-like** charge times 1,000. Result-like means `PRICE_PER_DATASET_ITEM`, or a pay-per-event primary event (or `apify-default-dataset-item` when nothing is marked primary) whose key and title identify a result or dataset item and do not mention another unit.

These units are **not** converted into a per-1,000 price: page, minute, report, start, gigabyte, hour, second, run, and month. Their unit price stays on `unitPriceUsd` and `pricePer1kUsd` is null. Unknown models and unidentified events are null too. The cheapest add-on is never used as the comparison price. Actor start is reported separately as `startUsd` and is not folded in. Rental (`FLAT_PRICE_PER_MONTH`) is a monthly price, not a per-1,000 price.

`overpriced-leaders` uses result-unit prices only, and only when the top 10 contain at least 5 positive result prices. A page-priced Actor is not ranked against a result median.

### How scores are calculated

`scoreVersion` is `2026-11-08`.

- **Demand** = `100 * log10(1 + knownUsers30d) / log10(1 + largestCategoryKnownUsers30d)`, rounded to one decimal. `knownUsers30d` sums 30-day user stats that are present. Missing stats are skipped, not zeroed. The same person using several Actors is counted in each of those Actors.
- **Leader flags** use the top 5 by 30-day users. `low-rated-leaders` requires at least 3 of them to have at least 3 reviews and an average rating under 4.2. `unreliable-leaders` requires a top-5 fail rate above 0.1 with at least 50 public runs in 30 days. `stale-leaders` requires at least 2 leaders whose fetched `modifiedAt` is older than 180 days. An unknown modified time is not stale, and a build count is not a modified time. `overpriced-leaders` is the result-unit rule above. `fragmented-market` means the top 3 hold under half of known users, with at least 5 Actors and enough known user stats. `fast-growing` means category known users rose more than 10% versus the previous complete snapshot.
- **Room to win** = `demandScore * weakness * (1 - top3Share * 0.6)`, rounded to one decimal. `weakness` starts at 0.2 and adds 0.2 for each leader flag, capped at 1. Missing ratings do not increase weakness. If concentration cannot be computed, `roomToWin` is null.
- **Confidence** is `low` when the listing is incomplete, or when there are fewer than 5 Actors, or when fewer than 70% of Actors have a 30-day user stat. It is `high` only when the listing is complete, there are at least 8 Actors, and at least 90% have that stat. Otherwise it is `medium` when the medium thresholds are met.

Growth compares the sum of present user stats for Actors in the category this week with the same kind of sum from the previous complete snapshot. If more than 10% of either side is missing a user stat, growth is null.

### How data is collected

- `GET https://api.apify.com/v2/store?limit=1000&offset=...` for the public listing.
- `GET https://api.apify.com/v2/acts/{id}` for `modifiedAt` on the bounded leader set only. The rest of that response is discarded.
- No other hosts, no proxies, and no redirects.
- At least 1.2 seconds between requests, including detail calls and retries. The User-Agent is `ClearfeedLabs-StoreIntel/0.2 (+https://apify.com/clearfeedlabs/apify-store-market-intel)`.
- HTTP 429 and 5xx wait for `Retry-After` when it is present, otherwise for a bounded exponential backoff, never more than 60 seconds, and at most 4 attempts. If the listing still fails, the run fails. It does not treat the failure as the end of the Store.
- If the Store's reported total changes between pages (an Actor was published or removed mid-scan), the whole listing is read again once. If it changes again, the run finishes with one free `run-status` row that says so. Nothing is charged and history is not updated.
- The public Store API currently stops returning Actors after about offset 15,000 while still reporting the full total. An empty page after the first one ends the scan as an observed cohort (`truncationReason: store-offset-limit`), the same as hitting `maxPages`. It is never counted as a complete listing.
- The run records the pages fetched, the Actors observed, the API total, the truncation reason, and the request counts. It does not claim a fixed Store size or a fixed request count.

### Input

See the input tab for every field. Sample inputs:

Snapshot only:

```json
{ "includeGapReport": false, "maxPages": 30 }
```

One category report:

```json
{ "categories": ["DEVELOPER_TOOLS"], "includeGapReport": true, "enableAlerts": false, "detailTopN": 5, "maxPages": 30 }
```

Watchlist from a later comparable scan:

```json
{ "enableAlerts": true, "watchlist": ["apify/website-content-crawler"], "alertUserChangePct": 20, "historyKey": "default" }
```

One deep-dive:

```json
{ "deepDiveCategories": ["DEVELOPER_TOOLS"], "deepDiveSize": 25, "includeGapReport": true }
```

The first watchlist run stores that week's snapshot and does not charge `alert`. On a later ISO week with the same `historyKey` and `maxPages`, alerts are for Actor ids present in both scans. A missing id is `not-observed-this-scan`, not a removal. `dropped-from-store-listing` is stored only when both weeks are verified-complete.

### Output

Illustrative rows from the local fixture, not a live Store census:

```json
{
  "rowType": "market-summary",
  "week": "2026-W45",
  "actorsObserved": 3,
  "reportedTotal": 3,
  "pagesFetched": 1,
  "listingComplete": true,
  "truncationReason": null,
  "users30dSum": 150,
  "users30dMissingActors": 0,
  "medianResultPricePer1kUsd": 2,
  "medianResultSampleSize": 1,
  "userCountMeaning": "Sum of Apify-reported public user counts for Actors with a present 30-day stat. Not unique people, not paying customers, and not revenue. Missing stats are excluded, not counted as zero.",
  "nonAffiliation": "Not affiliated with, endorsed by, or sponsored by Apify.",
  "source": "illustrative fixture, not a live Store census",
  "fixture": true
}
```

```json
{
  "rowType": "category-opportunity",
  "week": "2026-W45",
  "category": "DEVELOPER_TOOLS",
  "demandScore": 100,
  "roomToWin": 8,
  "confidence": "low",
  "gapFlags": [],
  "users30d": 150,
  "medianResultPricePer1kUsd": null,
  "resultPriceSampleSize": 1,
  "listingComplete": true
}
```

A page-priced Actor in that output has `priceUnit` `page`, `unitPriceUsd` set, and `pricePer1kUsd` null. It is not flagged overpriced against result prices.

### Other Store research Actors

Prices below were inspected on November 8, 2026 and can change. User counts are not proof of buyer demand.

| Actor | What to expect | Price read that day |
|---|---|---|
| [zinin/apify-market-gap-finder](https://apify.com/zinin/apify-market-gap-finder) | Bounded niche cohorts, ranked opportunities, comparator evidence, confidence, data gaps, and a manual-validation step | $0.10 per delivered report, plus $0.005 per GB start with a minimum of one start. The listing says invalid, insufficient-evidence, failed, and replay outcomes are not charged as that report |
| [conversational_kermis/apify-market-pricing-intelligence](https://apify.com/conversational_kermis/apify-market-pricing-intelligence) | Pricing recommendations, tier curves, competitor and rising-star notes, gaps, and scenarios | $0.01 per dataset result and $0.01 per strategic summary |

This Actor's distinct behavior is the account-owned weekly baseline, watchlist rows, and same-unit price handling described above. It does not claim a better model, unique coverage, or measured performance against those Actors.

### Disclaimer

Not affiliated with, endorsed by, or sponsored by Apify. Apify is a trademark of its owner. Metrics come from Apify's public Store API and can be delayed, rounded, incomplete, or changed.

Scores and flags are automated heuristics. Check the Actor's Store page before you act on a row. This is not financial, legal, or business advice. Do not use the output to copy another developer's Actor, content, or branding.

Questions and corrections belong on this Actor's Issues tab.

# Changelog

This Actor's version history is a separate document: https://apify.com/clearfeedlabs/apify-store-market-intel/changelog.md

# Actor input Schema

## `categories` (type: `array`):

Limit the opportunity report and movers to these Store categories. Empty means all categories observed in the crawl.

## `includeGapReport` (type: `boolean`):

Category scores, movers, and price changes. Charged as gap-report at $0.10 after those rows are stored. The platform also charges the mandatory Actor start event, and every run that stores a market summary charges snapshot at $0.02.

## `moversCount` (type: `integer`):

Fastest-growing Actors by week-over-week 30-day users once a previous complete snapshot exists. Before that, the list uses 7-day momentum.

## `detailTopN` (type: `integer`):

On every run, fetches modifiedAt for this many leaders in each reported category. A build count is not used as a modified time.

## `enableAlerts` (type: `boolean`):

Stores an alert row only when a previous complete snapshot exists. Dropped-from-listing alerts also require this run's listing to be complete. Incomplete crawls do not create dropped alerts.

## `watchlist` (type: `array`):

Actors as username/actor-name, for example apify/website-content-crawler. A tilde is accepted in place of the slash.

## `alertUserChangePct` (type: `integer`):

Alert when a watchlisted Actor's 30-day public users change by at least this percent and by at least 3 users. Missing user stats do not become zero.

## `deepDiveCategories` (type: `array`):

Up to 5 categories. A deep-dive is charged only after its leaderboard row is stored. A category with no observed Actors stores nothing and is not charged.

## `deepDiveSize` (type: `integer`):

How many top Actors to include in each deep-dive leaderboard. Modified times are fetched for at most 25 of them.

## `historyKey` (type: `string`):

Weekly baselines are stored in your account's named key-value store apify-store-intel-history. Runs of the same Actor task share a key. Two tasks do not share a baseline unless they are the same task. Ad-hoc runs with no task id use the notask scope.

## `maxPages` (type: `integer`):

Safety cap on Store listing pages. The run reports pages fetched, Actors observed, the API total, and whether the listing was complete. Hitting this cap does not count as a full listing and does not replace the weekly baseline. The public Store API currently returns Actors only up to about offset 15,000; the scan then ends as an observed cohort.

## Actor input object example

```json
{
  "categories": [
    "DEVELOPER_TOOLS"
  ],
  "includeGapReport": true,
  "moversCount": 20,
  "detailTopN": 5,
  "enableAlerts": false,
  "watchlist": [
    "apify/website-content-crawler"
  ],
  "alertUserChangePct": 20,
  "deepDiveCategories": [
    "DEVELOPER_TOOLS"
  ],
  "deepDiveSize": 25,
  "historyKey": "default",
  "maxPages": 30
}
```

# Actor output Schema

## `rows` (type: `string`):

No description

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

No description

## `brief` (type: `string`):

No description

## `summary` (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 = {
    "maxPages": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("clearfeedlabs/apify-store-market-intel").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 = { "maxPages": 5 }

# Run the Actor and wait for it to finish
run = client.actor("clearfeedlabs/apify-store-market-intel").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 '{
  "maxPages": 5
}' |
apify call clearfeedlabs/apify-store-market-intel --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,clearfeedlabs/apify-store-market-intel"
        }
    }
}
```

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/r8JcLXYekZk2bSZ5j/builds/XdDrCgMYJrqV9wobJ/openapi.json
