# Apify Store Competitor Analyzer: Pricing, Users & Revenue (`neverempty/apify-store-competitor-analyzer`) Actor

For Apify developers and AI agents choosing what to build and price: every competitor for a Store search, category or Actor list, ranked by 30-day users, with runs, fail rate, rating, paid-plan price, start fee and revenue estimate. 'truth social' finds 422 Actors; 46 really match. Monitor mode.

- **URL**: https://apify.com/neverempty/apify-store-competitor-analyzer.md
- **Developed by:** [NeverEmpty](https://apify.com/neverempty) (community)
- **Categories:** Developer tools, AI, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.50 / 1,000 actor row returneds

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

## Apify Store Competitor Analyzer: Pricing, Users & Revenue

**For AI agents and Apify developers deciding what to build or how to price it:** give a search term, a Store category or a list of Actors, and get every competitor ranked by 30-day users, with runs, runs per user, fail rate, rating, age, the price on each plan (primary event per 1,000 and start fee, read from the tiered price table), scheduled price changes and a revenue estimate on the paid plan, plus one summary row per term with the leader's share and the paid-plan price band. Monitor mode returns only new competitors, price changes and big user swings.

It reads only Apify's own public API (`/v2/store`, `/v2/acts/<id>`) and, if you ask for them, the public written reviews. No login, no proxy and no Apify token of yours are needed.

### Input and output at a glance

```json
{ "searchTerms": ["truth social"], "maxActorsPerQuery": 3 }
```

One row per Actor (shortened, real values from 2026-09-25):

```json
{
  "status": "ok",
  "query": "truth social",
  "rankByUsers30Days": 1,
  "storeSearchPosition": 1,
  "fullName": "muhammetakkurtt/truth-social-scraper",
  "users30Days": 113,
  "runs30Days": 32441,
  "runsPerUser30Days": 287.1,
  "failRate30DaysPct": 0,
  "rating": 4.42,
  "ratingActorStats": 1.85,
  "reviewCount": 11,
  "ageDays": 723,
  "pricingModel": "PAY_PER_EVENT",
  "primaryEventName": "post",
  "primaryPricePer1kUsdFreePlan": 5,
  "primaryPricePer1kUsdPaidPlan": 4,
  "startFeeUsd": { "FREE": 0.01, "BRONZE": 0.005, "SILVER": 0.004, "GOLD": 0.003, "PLATINUM": 0.003, "DIAMOND": 0.003 },
  "estimatedCreatorRevenue30dUsd": 233.58,
  "estimateBasis": "Estimated, not measured: 30-day runs x (start fee + 1 primary-event item) at the BRONZE price ..."
}
```

And one free summary row per search term:

```json
{
  "status": "summary",
  "query": "truth social",
  "storeResultsRead": 422,
  "matchedActors": 46,
  "users30DaysTotal": 276,
  "leaderFullName": "muhammetakkurtt/truth-social-scraper",
  "leaderSharePct": 40.9,
  "shareDenominator": "all matched Actors, including those published by Apify itself",
  "paidPlanPricePer1kUsdBand": { "actors": 8, "min": 0.55, "p25": 1.75, "median": 2, "p75": 4.25, "max": 5 },
  "paidPlanStartFeeUsdBand": { "actors": 8, "min": 0.0001, "p25": 0.005, "median": 0.005, "p75": 0.0063, "max": 0.05 }
}
```

### Why the numbers are different from a plain Store scraper

These are the mistakes we made ourselves while measuring the Store by hand; this Actor avoids each of them.

- **Most prices are not in `eventPriceUsd`.** They sit in `eventTieredPricingUsd`, one price per plan. Reading only `eventPriceUsd` makes most paid Actors look free. Every row gives the primary event per 1,000 and the start fee on all six plans.
- **The free-plan price is not what paying customers pay.** Many Actors charge free-plan users 2x to 100x the paid-plan price. Free-plan users earn the developer nothing, so the revenue estimate uses the **BRONZE** (lowest paid plan) price, and `freePlanPriceMultiple` shows the gap.
- **Start fees are kept apart** from the per-item price, so a $0.01 start fee never shows up as "$10 per 1,000". A start fee is recognized by its one-time flag, by names such as actor-start, run\_start, run-started or ActorRunStarted, and by titles such as "Actor Start", because many Actors name it something other than actor-start.
- **The Store search is loose.** It also matches words in descriptions and READMEs: "truth social" returns 422 Actors, only 46 of which have both words in the title or name. `matchMode` decides (strict by default), and the no-matches row says how many had the words only in the description.
- **The Store listing lags.** Row values come from `/v2/acts/<id>`, not from the cached Store listing. The summary row, which covers every matched Actor, says it is built from the listing.
- **The rating the Store page shows is not always the one in the Actor statistics.** On 2026-09-25, 169 of 719 rated Actors in our sample had a different `actorReviewRating` in their statistics than on their Store page (one showed 4.4 on the page and 1.85 in the statistics; some show 0 with five reviews). `rating` is the Store page value and `ratingActorStats` the other one, so you can see both.
- **30-day users** come from `totalUsers30Days` (there is no user count inside the 30-day run statistics).
- **Market share says what it counts.** `shareDenominator` states whether Actors published by Apify itself are in the denominator (`includeApifyOwned`).

### Revenue estimate: what it is and what it is not

`estimatedCreatorRevenue30dUsd` = 30-day runs x (start fee + 1 primary-event item, both at the BRONZE price) x the creator share (100% minus the Apify margin of the current price entry; 80% when not published).

It is an estimate, and the column says so. It counts every run as a paying customer's run returning one item: runs by free-plan users earn the developer nothing (real revenue can be lower), and runs returning many items earn more (it can be higher). Platform usage costs are not subtracted. Rental (monthly) and free Actors are not estimated. `estimatedCustomerSpend30dUsd` is the same without the creator share.

### Monitor mode

Set `onlyChanges` and a `watchName`, then schedule the Actor (for example daily). The first run returns the top Actors as the starting point. Later runs return only:

- `new-competitor`: an Actor that was not in the matched results of that search term or category before (anywhere in the list, not only the top);
- `price-changed`: any change in the price table (event names, any plan, start fee, pricing model); `changes` gives the previous and current table;
- `users-changed`: 30-day users moved by at least `userChangePercent` % and `userChangeMinimum` users.

A run in which nothing changed returns one free `no-change` row per query and charges only the run start fee. Changes that could not be returned (the per-query cap or your maximum charge) are not remembered, so the next run returns them.

### Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `searchTerms` | list | (example: google maps scraper) | Store search terms. Each returns the top Actors plus a free summary row. If searchTerms, categories and actorIds are all empty, the example term is used. |
| `categories` | list | none | Store categories (AI, AGENTS, AUTOMATION, BUSINESS, COVID\_19, DEVELOPER\_EXAMPLES, DEVELOPER\_TOOLS, ECOMMERCE, FOR\_CREATORS, GAMES, JOBS, LEAD\_GENERATION, MARKETING, NEWS, SEO\_TOOLS, SOCIAL\_MEDIA, TRAVEL, VIDEOS, REAL\_ESTATE, SPORTS, EDUCATION, INTEGRATIONS, OTHER, OPEN\_SOURCE, MCP\_SERVERS). |
| `actorIds` | list | none | Specific Actors as username/actor-name, username~actor-name, Actor ID or apify.com URL (up to 500). The same Actor given twice is returned and charged once. |
| `matchMode` | select | title | `title`: all words in the title or name. `titleOrDescription`: also the description. `store`: the Store's results as they are. |
| `maxActorsPerQuery` | integer | 10 | Actors returned (and charged) per search term or category, 1 to 200. An Actor already returned for an earlier term in the same run is not repeated or charged again; the summary row counts it in `alreadyReturnedEarlierInRun`. |
| `maxStoreResults` | integer | 1000 | Store results read per term before matching, 100 to 3,000. |
| `minUsers30Days` | integer | 0 | Leave out Actors with fewer 30-day users. |
| `includeApifyOwned` | boolean | true | Keep Actors published by Apify itself. |
| `includeUnrunnableActors` | boolean | false | Include Actors the Store API hides by default (for example from unverified developers). |
| `minUsersForPriceBand` | integer | 5 | The summary's price band uses only Actors with at least this many 30-day users. |
| `includeReviews` | boolean | false | Add the written reviews (rating, date, text, whether the developer replied), lowest rating first. Reviewer names are not returned. No extra charge. |
| `maxReviewsPerActor` | integer | 5 | Reviews per Actor, 1 to 50. |
| `onlyChanges` | boolean | false | Monitor mode (see above). |
| `watchName` | string | none | Name of the remembered state. With it set and `onlyChanges` off, all top Actors are returned with `changeType` filled. |
| `resetMonitoringState` | boolean | false | Forget what this watch remembered. |
| `userChangePercent` | integer | 20 | Smallest user move (percent) reported in monitor mode. |
| `userChangeMinimum` | integer | 5 | Smallest user move (users) reported in monitor mode. |

### Output columns

Per Actor: `status`, `query`, `queryType`, `storeSearchPosition` (where the Store's own search puts it), `rankByUsers30Days`, `matchedIn`, `actorId`, `fullName`, `title`, `url`, `developerUsername`, `isApifyOwned`, `categories`, `description`, `users30Days`, `users7Days`, `users90Days`, `usersAllTime`, `runs30Days`, `runsPerUser30Days`, `succeededRuns30Days`, `failedRuns30Days`, `timedOutRuns30Days`, `abortedRuns30Days`, `failRate30DaysPct` (failed + timed out, over all runs), `rating` (as on the Store page), `ratingSource`, `ratingActorStats`, `reviewCount`, `bookmarkCount`, `createdAt`, `ageDays`, `modifiedAt`, `lastRunStartedAt`, `daysSinceLastRun`, `pricingModel`, `primaryEventName`, `primaryEventPricePer1kUsd` (all plans), `primaryPricePer1kUsdFreePlan`, `primaryPricePer1kUsdPaidPlan`, `freePlanPriceMultiple`, `startFeeUsd` (all plans), `flatMonthlyPriceUsd`, `pricingEvents` (every event with its price on each plan), `minimalMaxTotalChargeUsd`, `priceStartedAt`, `priceChangesSoFar`, `scheduledPriceChange`, `estimatedCustomerSpend30dUsd`, `estimatedCreatorRevenue30dUsd`, `creatorShare`, `estimateBasis`, `agenticPaymentsEnabled`, `badge`, `notice`, `isDeprecated`, `reviews`, `reviewsNote`, `changeType`, `changes`, `previousCheckedAt`, `watchName`, `note`, `checkedAt`.

Summary row (covers every matched Actor, before `minUsers30Days`): `matchMode`, `storeResultsRead`, `storeResultsTotal`, `matchedActors`, `analyzedActors`, `alreadyReturnedEarlierInRun`, `users30DaysTotal`, `actorsWithAnyUsers30Days`, `actorsWithUsersForBand`, `leaderFullName`, `leaderUsers30Days`, `leaderSharePct`, `shareDenominator`, `apifyOwnedActors`, `apifyOwnedUsers30Days`, `paidPlanPricePer1kUsdBand`, `paidPlanStartFeeUsdBand`, `priceBandBasis`, `estimatedCustomerSpend30dUsdAllMatched`, `estimatedCreatorRevenue30dUsdAllMatched`, `estimateBasis`.

Free rows that say why: `no-matches`, `not-found` (private and deleted Actors look the same to the public API), `bad-input`, `unreachable` (the API did not answer after 5 tries), `budget-reached`, `no-change`, `more-changes-not-returned`, `already-returned` (monitor mode: the changes of this term were returned for an earlier term in the same run).

### Pricing

Pay per event: one **run start** fee per run that returns at least one Actor row (or, in monitor mode, that compared the Store), and one **Actor row** fee per Actor returned. Summary rows, reviews and every row that says why nothing was returned are free. A run whose maximum total charge has no room for the start fee plus one row requests nothing and is charged nothing.

### Limits

- Only public Actors are visible to the public API. The Store API hides some Actors unless `includeUnrunnableActors` is on.
- Users and runs are Apify's 30-day statistics; the Store listing used for the summary and for monitor comparisons can lag the per-Actor numbers by about a day.
- The monitor memory is a named key-value store in your account; two runs of the same watch finishing at the same moment can still overwrite each other.

### Support

Questions and requests: open an issue on the Issues tab of this Actor.

# Actor input Schema

## `searchTerms` (type: `array`):

Apify Store search terms, one per line (for example google maps scraper). For each term the Actor reads the Store search results, keeps the Actors whose title or name contain all the words (see Match mode), ranks them by 30-day users and returns the top ones plus one free summary row for the term. If searchTerms, categories and actorIds are all empty, the example term google maps scraper is used.

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

Apify Store categories to rank, one per line: AI, AGENTS, AUTOMATION, BUSINESS, COVID\_19, DEVELOPER\_EXAMPLES, DEVELOPER\_TOOLS, ECOMMERCE, FOR\_CREATORS, GAMES, JOBS, LEAD\_GENERATION, MARKETING, NEWS, SEO\_TOOLS, SOCIAL\_MEDIA, TRAVEL, VIDEOS, REAL\_ESTATE, SPORTS, EDUCATION, INTEGRATIONS, OTHER, OPEN\_SOURCE, MCP\_SERVERS. The Store's most popular Actors in the category are read and ranked by 30-day users.

## `actorIds` (type: `array`):

Specific public Actors to analyze, one per line, as username/actor-name, username~actor-name, an Actor ID or its https://apify.com/username/actor-name URL (up to 500). Each one returns one row. No summary row is made for this list.

## `matchMode` (type: `string`):

The Apify Store search is loose: it also returns Actors that mention a word only in the description or README. title keeps Actors whose title or name contain every word of the term (strict, the default). titleOrDescription also accepts the description. store keeps the Store's results as they are.

## `maxActorsPerQuery` (type: `integer`):

How many Actors (ranked by 30-day users) are returned and charged per search term or category (1 to 200). The free summary row always covers every matched Actor. In monitor mode, this caps the changed Actors returned per term; the rest are returned by the next run.

## `maxStoreResults` (type: `integer`):

How many Apify Store search results are read before matching (100 to 3,000, in pages of 1,000). The summary row says how many results the Store had in total.

## `minUsers30Days` (type: `integer`):

Leave out Actors with fewer users in the last 30 days (0 keeps all).

## `includeApifyOwned` (type: `boolean`):

Keep Actors published by the apify account. Turn off to see the market without them; the summary row's leader share and price band then leave them out too and say so.

## `includeUnrunnableActors` (type: `boolean`):

The Store API leaves out Actors it does not consider safe to run automatically (for example from developers who have not passed verification). Turn on to include them, as the Store API's includeUnrunnableActors option does.

## `minUsersForPriceBand` (type: `integer`):

The summary row's paid-plan price band (min, quartiles, max) uses only matched pay-per-event Actors with at least this many users in 30 days, so that listings nobody uses do not set the market price.

## `includeReviews` (type: `boolean`):

Add each Actor's written reviews from its public Reviews tab: star rating, date, text and whether the developer replied, lowest rating first. The reviewer's name is not returned. Costs one extra request per Actor, no extra charge.

## `maxReviewsPerActor` (type: `integer`):

How many written reviews to add per Actor (1 to 50), lowest rating first and newest first within the same rating.

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

Return only Actors that changed since the last run with the same watch name: a new competitor in the results of a search term or category, a price change (any event, any plan, start fee or pricing model) or a move in 30-day users of at least the percentage and number below. The first run returns the top Actors as the starting point. A run in which nothing changed returns a free row saying so and charges only the run start fee.

## `watchName` (type: `string`):

Name of the remembered state used to compare runs (letters, digits, dot, dash, underscore; up to 40). Setting it (or turning on monitor mode) fills changeType and changes. Use a different name for each list you track on its own schedule. With monitor mode on and no name, the name default is used.

## `resetMonitoringState` (type: `boolean`):

Start this watch over: forget the remembered Actors and prices before this run, so the top Actors are returned as a first check.

## `userChangePercent` (type: `integer`):

In monitor mode, report an Actor whose 30-day users moved by at least this percentage of the remembered number (and by at least the minimum below).

## `userChangeMinimum` (type: `integer`):

In monitor mode, the smallest move in 30-day users that is reported, so that 1 to 2 users on a tiny Actor are not reported as a 100% change.

## Actor input object example

```json
{
  "searchTerms": [
    "google maps scraper"
  ],
  "matchMode": "title",
  "maxActorsPerQuery": 10,
  "maxStoreResults": 1000,
  "minUsers30Days": 0,
  "includeApifyOwned": true,
  "includeUnrunnableActors": false,
  "minUsersForPriceBand": 5,
  "includeReviews": false,
  "maxReviewsPerActor": 5,
  "onlyChanges": false,
  "resetMonitoringState": false,
  "userChangePercent": 20,
  "userChangeMinimum": 5
}
```

# Actor output Schema

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

One row per Actor: 30-day users, runs, runs per user, fail rate, rating, age, last run, pricing by plan (primary event per 1,000 and start fee), scheduled price changes, and a paid-plan revenue estimate with its basis. One free summary row per search term or category with the leader's share and the paid-plan price band. In monitor mode, only new competitors, price changes and user swings. Inputs that cannot be read come back as a free row that says why.

# 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 = {
    "searchTerms": [
        "google maps scraper"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("neverempty/apify-store-competitor-analyzer").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 = { "searchTerms": ["google maps scraper"] }

# Run the Actor and wait for it to finish
run = client.actor("neverempty/apify-store-competitor-analyzer").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 '{
  "searchTerms": [
    "google maps scraper"
  ]
}' |
apify call neverempty/apify-store-competitor-analyzer --silent --output-dataset

```

## MCP server setup

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

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/2LUn6Iiyq5pKwemFR/builds/4nYSVwy8clvFjBkLz/openapi.json
