Apify Store Scraper: Honest Ratings, Weak Leaders
Pricing
from $2.70 / 1,000 listing analyses
Apify Store Scraper: Honest Ratings, Weak Leaders
Read the Apify Store with honest ratings: listings nobody has reviewed show as unrated, never as badly rated, and a weak leader comes with its reason in plain words. Search, or filter by category, developer and pricing model, for users, runs, success rate and price on every plan.
Pricing
from $2.70 / 1,000 listing analyses
Rating
0.0
(0)
Developer
Pradio Actors
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a month ago
Last modified
Categories
Share
What does Apify Store Scraper do?
This Apify Store scraper shows listings nobody has reviewed as unrated, never as badly rated, and says in plain words why a popular listing is weak. Search any niche, or read a whole category, one developer's catalogue or the whole Store, and get each Actor's users, runs, success rate, rating and price on every plan.
It reads one unauthenticated public endpoint, in one run. Built for Actor developers deciding what to build next, and for anyone who wants to know who actually dominates a category.
Features
- Unrated is kept apart from badly rated. Listings nobody has reviewed are shown as unrated, never as badly rated, so a new Actor never looks like a failing one.
- The reason in plain words. A weak listing says why it is weak, such as "rating 3.41 over 88 reviews", a high failure rate, or a maintenance notice.
- Only listings that match. The Store's search also returns popular listings that have nothing to do with your words; each one is checked and set aside before anything is saved or billed. Turn the check off when you want the Store's own matches.
- The Store's own filters. Narrow a run to one category, one developer or one pricing model, or leave the search empty to read a whole category or the whole Store.
- Five orders. Most used, best match, newest, last updated or most users of all time, and a starting position to continue a long read in the next run.
- A usage floor. Keep only listings with at least as many users in the last 30 days as you set; the rest are never saved and never billed.
- Usage over three windows and all time. Users over the last 7, 30 and 90 days and since launch, plus runs, builds, bookmarks and when it last ran, so you can see whether a listing is growing or fading.
- Every run outcome. Succeeded, failed, stopped and timed-out runs over the last 30 days, and a success rate that counts timeouts against the Actor, as the platform does.
- Price on every plan. How each Actor charges, every event it charges for, the main event's price on each Store plan from Free to Diamond, its start price, a rental's monthly price and trial, the lowest charge limit it allows, when the price last changed and whether AI agents can pay for it directly.
- Where it ranks. Each listing's position in the Store results for your search, and the categories it is filed under.
- One listing, one row, one charge. The Store sometimes returns the same listing twice while paging; the repeat is dropped before anything is saved or charged.
- The denominator on every row. How many listings were examined, how many matched and whether your limit cut the search short.
- An empty run is an answer. A run that saves nothing returns a row that says why (no listing matched, the Store had nothing for the filters, or your own filter set every match aside), and it is not charged.
How do I use Apify Store Scraper?
Setting up a run takes ten seconds, and you need nothing beyond your Apify account. Every field is ready to go, so you can press Start as it is.
Scan a niche. Every Actor matching "instagram", with its usage, rating and price:
{"search": "instagram","limit": 100,"minReviewsForRating": 3,"onlyWeak": false}
Find the weak leaders only. Just the listings with a real weakness signal, for "amazon reviews":
{"search": "amazon reviews","limit": 100,"onlyWeak": true}
Read a whole category. No search, just the most used Actors filed under Lead generation that have real users:
{"category": "LEAD_GENERATION","sortBy": "popularity","limit": 200,"minUsers30d": 50}
Read a competitor's whole catalogue. Every Actor one developer publishes, newest first:
{"developer": "apify","sortBy": "newest","limit": 500}
You get one row per relevant Actor. Here is one from a run on 28 September 2026, for "instagram" (the icon link is left out here):
{"name": "apify/instagram-scraper","title": "Instagram Scraper","url": "https://apify.com/apify/instagram-scraper","users30d": 44668,"runs30d": 17164438,"failureRate": 0.00004783145244837029,"rating": 4.705390594096097,"reviewCount": 599,"ratingState": "value","pricingModel": "PAY_PER_EVENT","notice": "NONE","weak": false,"weakReasons": [],"users7d": 24171,"users90d": 76426,"bookmarks": 4451,"categories": ["SOCIAL_MEDIA"],"primaryEvent": "result","pricePerEvent": 0.0027,"startPrice": null,"actorId": "shu8hvrXbJbY3Eb9W","developer": "apify","usersTotal": 408692,"runsTotal": 201849112,"buildsTotal": 3661,"lastRunAt": "2026-09-28T10:24:01.660Z","runs30dSucceeded": 17118654,"runs30dFailed": 821,"runs30dAborted": 5617,"runs30dTimedOut": 39346,"successRate30d": 0.9973326245811253,"priceTiers": {"FREE": 0.0027,"BRONZE": 0.0023,"SILVER": 0.0019,"GOLD": 0.0015,"PLATINUM": 0.0009,"DIAMOND": 0.0005},"chargeEvents": [{"event": "result","price": 0.0027,"primary": true,"oneTime": false}],"pricePerUnit": null,"trialMinutes": null,"minChargeLimit": 0.0027,"apifyMargin": 0.2,"pricingSince": "2026-02-20T12:24:59.754Z","agentPayable": true,"badge": null,"rank": 2,"searchTerm": "instagram","filters": {"category": null,"pricingModel": null,"developer": null,"sortBy": "popularity","offset": 0,"minUsers30d": null},"examined": 99,"relevant": 47,"discarded": 52,"capped": true,"retrievedAt": "2026-09-28T13:53:23.072Z"}
That is the market leader. Its rank is the Store's own search position, counted over every
distinct listing the Store returned, including the ones this Actor then set aside because they
do not match every word of your search. The listing the Store placed first for "instagram" did
not match, so no row carries the top rank.
Its failure rate is close to zero, and its success rate is a little lower: most of its unsuccessful runs timed out rather than failed. Only the run-outcome columns show that, and the platform counts a timeout against an Actor as it counts a failure.
This is what a weakness signal looks like, from the same run:
{"name": "apify/instagram-hashtag-scraper","url": "https://apify.com/apify/instagram-hashtag-scraper","users30d": 10052,"rating": 3.406389274716537,"reviewCount": 88,"ratingState": "value","weak": true,"weakReasons": ["rating 3.41 over 88 reviews"]}
More than ten thousand people a month use it, and it is rated 3.41 across eighty-eight reviews. That is a real audience being served badly, which is the only kind of gap worth building into.
And this is what an Actor nobody has reviewed looks like, from a larger "instagram" run the same day:
{"name": "datavoyantlab/instagram-following-scraper","users30d": 89,"rating": null,"reviewCount": 0,"ratingState": "unrated","weak": false,"weakReasons": []}
Questions it answers before you build
"Is this niche taken?" Sort the output by users30d. If one Actor holds most of the
usage and is rated above 4.5, the niche has a leader and you are picking a fight. If the
usage is spread across many mid-rated listings, nobody has won it yet. Compare users7d
with users90d to see whether the niche is growing.
"Is the leader actually good?" weak and weakReasons answer this. A leader with a 3.8
rating over a hundred reviews is a leader by inertia.
"Am I about to build something nobody wants?" A search that returns almost nothing is
not automatically an opening. Read examined on the empty-search row: if fifty listings
were read and none matched every word of your search, that is evidence nobody serves the
target only when your words are the ones a buyer would type. Try a buyer's wording before
concluding anything.
"What should I charge?" Read priceTiers and chargeEvents across the niche: what the
main event costs on each plan, which Actors add a start fee, and pricingSince for who changed
their price lately. The Pricing view in the Output tab puts them side by side.
The unrated trap
The Store API returns actorReviewRating = 0 for Actors that have never been
reviewed, and a large share of the catalogue has no reviews at all. A naive
rating < 4.2 filter flags every one of them as a weak incumbent. Reading the field
correctly leaves them out, so only listings with real reviews can be called weak.
So this Actor reports ratingState explicitly: value, unrated, too_few_reviews or
missing. An Actor nobody has reviewed is reported as unrated, never as a bad one.
Input
The form groups the fields the same way: what to read, what to keep, and how a weak listing is judged.
| Field | Default | Meaning |
|---|---|---|
search | instagram in the form, none through the API | Free-text query; leave it empty to read by the filters alone |
category | none | Only listings filed under this Store category |
pricingModel | none | Only listings that charge this way: pay per event, free, monthly rental or pay per result |
developer | none | Only listings by this developer, as written in their Store URLs |
sortBy | popularity | The order: most used, best match, newest, last updated, or most users of all time |
limit | 100 | Listings to read before relevance filtering, up to the whole Store |
offset | 0 | Skip this many listings first, to continue a long read |
matchEveryWord | true | Keep only listings that contain every word of the search |
minUsers30d | none | Keep only listings with at least this many users in the last 30 days |
onlyWeak | false | Return only listings with a genuine weakness signal |
minReviewsForRating | 3 | Below this many reviews, rating is reported as null |
weakRatingBelow | 4.2 | A rating under this counts as a weakness signal |
minRunsForHealth | 100 | Below this many runs, the failure rate is still shown but cannot mark a listing weak |
weakFailureRateAbove | 0.167 | A failure rate above this counts as a weakness signal |
Every field is optional, so a run with no input succeeds: through the API, an empty input reads the most used listings in the whole Store.
Output
Two row shapes share the dataset. Check result to tell them apart.
A listing row, one per relevant Actor found:
| Field | Meaning |
|---|---|
name | username/actor-name |
title | display title |
url | Store page |
users30d | distinct users in the last 30 days |
runs30d | total runs in the last 30 days, or null |
failureRate | failed ÷ total, or null when the total is zero |
rating | only when backed by enough reviews, else null |
reviewCount | number of reviews, or null |
ratingState | value · unrated · too_few_reviews · missing |
pricingModel | e.g. PAY_PER_EVENT or FREE |
notice | e.g. UNDER_MAINTENANCE |
weak | whether any weakness signal fired |
weakReasons | which ones, in words |
users7d | distinct users in the last 7 days, or null |
users90d | distinct users in the last 90 days, or null |
bookmarks | how many Apify users bookmarked it, or null |
categories | the Store categories it is filed under, or null |
primaryEvent | on a pay-per-event Actor, the event it mainly charges for, or null |
pricePerEvent | that event's price in USD on the free plan, or null |
startPrice | what a run costs to start, in USD, or null when it lists none |
actorId | the Actor's permanent id, which survives a rename: the key to join runs from different days |
developer | the developer's handle, as in the Store URL |
usersTotal | distinct users since launch, or null |
runsTotal | runs since launch, or null |
buildsTotal | how many times the developer has built it, a rough sign of upkeep, or null |
lastRunAt | when anybody last started a run of it, or null |
runs30dSucceeded | runs in the last 30 days that succeeded, or null with no runs |
runs30dFailed | runs in the last 30 days that failed, or null with no runs |
runs30dAborted | runs in the last 30 days that were stopped before they finished, or null with no runs |
runs30dTimedOut | runs in the last 30 days that ran out of time, or null with no runs |
successRate30d | succeeded ÷ total, counting timed-out and stopped runs against it, or null with no runs |
priceTiers | the main event's price in USD on each Store plan, from FREE to DIAMOND, or null |
chargeEvents | every event it charges for: name, free-plan price, whether it is the main one, whether it is once per run |
pricePerUnit | a monthly rental's price per month, or a pay-per-result price per result, in USD, or null |
trialMinutes | a monthly rental's free trial in minutes, or null |
minChargeLimit | the lowest total charge limit in USD a buyer may set for one run, or null |
apifyMargin | the share of the price the platform keeps, from 0 to 1, or null |
pricingSince | when the current price took effect, or null |
agentPayable | whether AI agents can pay for its runs directly, or null |
badge | a badge the Store shows on the listing, such as risingStar, or null |
pictureUrl | the link to the listing's icon, or null |
rank | its position in the Store results in the order you chose (most used first by default), counted before irrelevant listings are dropped; with a starting position, ranks carry on from it |
searchTerm | the query that produced this row, or null on a run with no search |
filters | the rest of the input that shaped the run: category, pricingModel, developer, sortBy, offset, minUsers30d |
examined | how many distinct listings were fetched before relevance filtering |
relevant | how many were kept: those that matched every word, or all of them with no search or the check off |
discarded | examined minus relevant |
capped | true if the fetch stopped at your limit, so more may exist |
retrievedAt | when these numbers were read; Store figures change daily |
pricePerEvent is the first price the Store page shows. Buyers on paid plans often pay less,
and a free Actor has no event, so all three price columns are null there.
An empty-search row, when a run saves no listing: you get a row that says why instead of an empty dataset that could mean anything.
| Field | Meaning |
|---|---|
result | NO_RELEVANT_LISTINGS, or STOPPED_EARLY if the charge limit cut the run short |
searchTerm | the query that was run, or null with no search |
filters | the rest of the input, as on a listing row |
examined | how many listings were read before concluding none matched |
relevant | 0, unless listings matched and your weak-only or usage filter set every one aside |
why | why nothing was saved: no listing matched every word, the Store had nothing for the filters, or your own filter set every match aside |
interpretation | how to read a zero result |
charged | false: no listing-analysed events. The apify-actor-start event still applies; see Pricing. |
pushed | on a STOPPED_EARLY row, how many listings were already analysed and saved before the limit was reached |
{"result": "NO_RELEVANT_LISTINGS","searchTerm": "quantum ferret grooming","filters": {"category": null,"pricingModel": null,"developer": null,"sortBy": "popularity","offset": 0,"minUsers30d": null},"examined": 50,"relevant": 0,"why": "50 listing(s) were examined and none matched every token of \"quantum ferret grooming\". The Apify Store search parameter narrows but does not rank by relevance, so relevance is verified here against title, name and description.","interpretation": "No listing examined matched every word of your search. That is evidence nobody serves the target only when the words are the ones a buyer would type. An unusual phrasing can miss listings that do serve it, so try the words a buyer would use before concluding anything.","charged": false}
Absent data is reported as absent (null), never disguised as a zero. That rule governs
rating, runs30d, failureRate, reviewCount and every price and usage column.
Honest limits
- Relevance is verified here, not by the API. The Store
searchparameter also returns listings that match only in text you cannot see: under the default ordergithubandgoodreadsboth return Instagram Scraper as the top result. Every word of the search must appear in the listing's title, name or description, and on most searches the greater part of the returned listings is set aside. TurnmatchEveryWordoff to keep them. - The Store's paging repeats itself. On a long read for a common word, the Store returns
some listings more than once. Each repeat is dropped, so
examinedcounts distinct listings and you pay once per listing. - The default order is usage, not relevance. A small listing for a common word can sit
beyond your
limit. Raise it, search a narrower phrase, or setsortBytorelevance. - There is no last-modified date on a listing in the Store API.
lastRunAtmeasures use, not maintenance, andbuildsTotalis only a rough sign of upkeep, so weakness is judged from run statistics instead. ThelastUpdateorder does sort by the latest change. - The Store sometimes returns a short page. A page can hold fewer listings than it counts,
so every page is asked for in full and advanced by what actually arrived;
cappedsays whether your limit, not the end of the Store, stopped the read. - No proxy required. One unauthenticated request to a documented public endpoint.
- No personal data is collected.
Pricing
Pay per event. There are exactly two, and these are the prices the platform charges:
| Event | Price | When |
|---|---|---|
listing-analysed | $0.005 | once per listing row, and only after that row is saved in your dataset |
apify-actor-start | $0.00005 | once per gigabyte of memory, when the run starts |
So a run that analyses 100 listings costs about $0.50: 100 x $0.005, plus a single start event at $0.00005. A listing the Store returns twice is still one row and one charge.
You pay for the listings that match your search, not for your limit. The limit is how many
listings are read; only the rows kept are billed. A listing your usage floor or the weak-only
switch sets aside is never saved and never billed either. The "instagram" run above had a limit of
100 and kept 47 matching listings, so it billed 47 rows.
$0.005 is the free-plan price. On paid plans a listing costs $0.0042 (Bronze), $0.0034 (Silver) or $0.0027 (Gold, Platinum and Diamond).
A run that finds nothing relevant charges no listing-analysed events at all. You pay
the start event and nothing else.
A read of a whole category or the whole Store bills every listing it keeps, so for a wide read set a usage floor to keep only the listings people use, and set a charge limit (below).
You can cap what a run may spend. Apify has a per-run Limit total charge setting
(maxTotalChargeUsd) in the run options. This Actor does not define it, the platform does,
and it applies to any pay-per-event Actor. Set it and the run stops when it is reached.
When that happens you do not silently get a short dataset. The run writes a
STOPPED_EARLY row naming how many listings it had already saved and how many relevant ones
it had found, so a run that was cut short can never be mistaken for a market that was small.
Raise the limit and re-run to see the rest.
apify-actor-start is Apify's own platform event, charged on every pay-per-event Actor
rather than added by this one. It buys your run five free seconds of compute, so it
usually saves more than it costs. Memory is capped at 1,024 MB in actor.json, and the
start event is priced per gigabyte allocated, so the cap holds it to a single event.
How to read the numbers
| You see | It means | It does not mean |
|---|---|---|
rating: null, ratingState: "unrated" | nobody has reviewed it | it is bad |
rating: null, ratingState: "too_few_reviews" | fewer than minReviewsForRating reviews | it is bad |
failureRate: null | no runs in the window, so the ratio has no denominator | it never fails |
runs30d: null with users30d > 0 | the Store gave a user count but no run count for the window; they are two separate Store figures | nobody ran it |
pricePerEvent: null on a FREE listing | it has no event to price | it costs nothing to run |
successRate30d well under 1 while failureRate is near 0 | its unsuccessful runs mostly timed out or were stopped | it works |
priceTiers: null on a pay-per-event listing | its main event has one price for every plan, or no main event is marked | it has no price |
agentPayable: false | AI agents cannot pay for it without an Apify account | agents cannot use it |
weak: false | no signal fired on the data available | it is good |
weak: false is the one worth dwelling on. It means nothing tripped a threshold, not that
the Actor is well made. The signals are what the Store publishes; a well-marketed Actor
with a bad output has no field that says so.
Questions
How current is this? Live at the moment you run it. The Store API is queried directly; nothing is cached between runs.
Why does the count change between runs? The catalogue changes, and the Store's own ordering is not stable across pages. Two runs minutes apart can return the same listings in a different order and occasionally a different count.
Can I get every Actor in the Store? Yes. Leave the search empty and raise limit to cover
the whole Store, or split the read between runs with offset. Every listing kept is billed, so
a usage floor (minUsers30d) keeps a wide read to the listings people use.
How do I track a competitor over time? Set developer to their handle and run it on a
schedule. Join the runs on actorId, which survives a rename, and compare users30d,
successRate30d, pricePerEvent and pricingSince from one run to the next.
Can I schedule it? Yes. Save your input as a task, then add a schedule from the Actor's
Actions menu. A weekly schedule suits most markets; every row is stamped with
retrievedAt.
Does it need a proxy or an account? Neither. One unauthenticated request to a documented public endpoint.
What if my search returns nothing? You get an empty-search row rather than an empty
dataset, and it costs you no listing-analysed events. You pay only the start event, as
every run does. See the shape above.
Is it legal to use? It reads the public Apify Store catalogue through Apify's own documented endpoint, the same figures any visitor sees on the Store pages, and it collects no personal data. You are responsible for having the right to read what you give it and for how you use the rows.
Where this fits with other Actors
It reads the Store; it does not read the web. When you know which listings matter, Website Content Crawler reads the pages behind them.
Integrations
This is an ordinary Apify Actor, so everything the platform offers works with it: schedule it, call it from the Apify API or the JavaScript and Python clients, wire it into Zapier, Make, n8n, Slack or a webhook, or reach it from an AI agent over MCP. Output goes to a dataset you can export as JSON, CSV or Excel.
A weekly schedule is the shape most people want: markets move slowly, and every row is
stamped with retrievedAt so two runs can be compared honestly.
From code, with the JavaScript client:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('pradio/store-intel').call({ category: 'SEO_TOOLS', minUsers30d: 50 });const { items } = await client.dataset(run.defaultDatasetId).listItems();
Found a problem?
Report it on the Issues tab. A bug report with the search term you used and the row that looked wrong is enough. The run id helps and is not required.
Two things worth reporting that people usually do not: a listing this scored weak that you
know is good, and a listing it scored fine that you know is not. Both are threshold problems
rather than bugs, and thresholds only move when somebody says so.
If this Actor saved you time, a review on the Store helps other buyers find it; problems go to the Issues tab.
Unofficial
Not affiliated with or endorsed by Apify. It reads the same public catalogue endpoint any visitor can.
Release notes
- 2026-09-28: new inputs to read by category, developer and pricing model, in five orders, from a starting position, with a usage floor and the word check as a switch; the search is now optional, so a run can read a whole category or the whole Store. New columns: every 30-day run outcome and a success rate, all-time users, runs and builds, the last run, the main event's price on every plan, every charge event, rental price and trial, the lowest charge limit, when the price last changed, whether agents can pay, the badge, the icon and the Actor's id. A busy moment at the Store is retried rather than failing the run, and a short page from the Store no longer reads as the end of the market. A listing the Store returns twice in one long read is returned and billed once. Earlier columns added the same day:
rank,users7d,users90d,bookmarks,categories,primaryEvent,pricePerEventandstartPrice. - 2026-08-19: first release. One row per Store listing for a search term, with users, rating, reviews and price, and a score for how the listing is doing.

