Pay per event vs per result: how not to overpay for scraped rows
The headline price per row is the least useful number when comparing scrapers. What decides your bill is what counts as a billable row, whether filtered rows are charged, what an empty run costs, and whether the invoice can exceed what landed in your dataset.
The four questions
Ask these of any scraper you are comparing, including the ones on this site.
1. What counts as a billable row? A review scraper that bills the property context row, the status row and the review row at the same price bills you three times for one review. The honest shape is that the row carrying the value is charged and the rows carrying the bookkeeping are free.
2. Are filtered rows charged? This is the biggest single lever. Ask for one- and two-star reviews of a company with 125,000 reviews: if the filter runs before billing, you pay for the complaints; if it runs in your code afterwards, you paid for all 125,000. A concrete example from this suite: one hotel property with 324 visible reviews delivered 8 rows under a rating ceiling with a text requirement — and billed 8.
3. What does an empty run cost? Alerting workloads are mostly empty by design. A daily price-drop check that finds no drops, a complaints feed on a quiet week, a flight alert with nothing under your ceiling — all should cost nothing. If empty runs cost money, the price of monitoring is the price of polling, and daily cadence becomes expensive for no reason.
4. Can the invoice exceed the dataset? When a run reaches its spending limit, does it stop delivering, or keep delivering rows it cannot charge for and bill you later? The first behaviour keeps the dataset and the invoice in agreement; the second is how people end up reconciling.
Where server-side filters change the arithmetic
Some filters run on the source's servers, some run in the scraper before billing, and some can only run in your code afterwards. The difference is money.
- Server-side — Trustpilot's star, date, language and keyword filters run on Trustpilot. Booking's language, traveller type and keyword filters run on Booking. AliExpress applies photos-only, follow-ups-only and same-country filters itself. Rows you excluded are never fetched, so you save time as well as money.
- Before billing — TripAdvisor has no rating sort, so a rating filter reads the pages and drops rows before charging. You pay for what you keep; the actor absorbs the fetch.
- After the fact — anything the tool does not support. You pay for every row and filter in pandas.
When a listing says "filters", find out which of the three it means.
Reading a per-row price properly
The suite here spans an order of magnitude, and the spread is not arbitrary:
| Row | Price | Why |
|---|---|---|
| Trustpilot review | $0.0007 | Compact JSON, one browser solve amortised over a whole run |
| Indeed review, AliExpress review | $0.002 | Datacenter, 20-50 rows per request |
| Airbnb occupancy month, Google Hotels offer | $0.002 | A derived row on top of a request already made |
| Hostelworld, HRS, Kurzurlaub review | $0.003 | Open APIs, small pages |
| Google Hotels hotel row, Amazon product | $0.004 | One request per entity |
| OTA review rows, Amazon review | $0.005 | Residential traffic or heavier pages |
| Rate parity row | $0.01 | Every source for one property and date, pre-compared |
The last one is the useful lesson. It is the most expensive row here and usually the cheapest way to get the answer, because the alternative is five price rows plus the work of aligning them. Price per row is not price per answer.
Worked examples
Full corpus of one TripAdvisor hotel (1,456 English reviews) 1,456 x $0.005 = $7.28
Daily complaints feed, same hotel, 2 new complaints a week 8 x $0.005 = $0.04 / month
Trustpilot: 1,000 reviews of one company 1,000 x $0.0007 = $0.70
Amazon: 13 reviews each on 500 products 6,500 x $0.005 = $32.50
Rate parity: 50 properties x 30 dates, weekly 1,500 x $0.01 = $15 / week
Flight alert: 3 routes x 30 days, nothing under the ceiling $0.00
The last line is not a joke: it is the shape most monitoring workloads should have, and it only exists if filtering happens before billing and empty runs are free.
What to check on a listing before you run it
- Does it state the ceiling for the source? Amazon's 8-13 reviews per product, Trustpilot's 200 per filtered view, Despegar's four comments per hotel are facts about the source that no scraper changes. A listing that does not mention them has either not measured them or is hoping you will not notice.
- Does it distinguish error from empty? "No reviews found" should mean the entity has none, not that a proxy was refused. Ask what a blocked target looks like in the output.
- Does it charge for duplicates? Give it the same hotel as a URL, a name and an id and see whether you pay once or three times.
- Are status rows free, and do they tell you what happened — rows delivered, rows filtered, pages read, the source's own total?
The model used here
Every actor on this site is pay-per-event, and the event is a delivered row: reviews, priced hotels, fares, listings, occupancy months. Context rows (the hotel, product, app or company), status rows, targets with no data, unknown ids, duplicate inputs and failed targets are free, filters run before billing, and a run that reaches its spending limit stops delivering rather than writing rows it cannot charge for.
Apify's own platform usage — compute, and residential proxy traffic where a source needs it — is billed separately and is a fraction of a cent per run for most of these; the residential sources are where it becomes visible, and that is reflected in their row price.
Run it
The hub lists every actor with its per-row price, and each actor page carries its full pay-per-event schema — every event, what it is, and exactly what triggers it. Related: scheduling with relative dates so a cheap run stays correct, and tracking competitor prices with n8n for the workflow that makes empty runs free in practice.
FAQ
What is the difference between pay-per-result and pay-per-event?
Pay-per-result bills one price for every item written to the dataset. Pay-per-event bills named events at their own prices, which lets a run charge for a review row but not for the context row, the status row or the row a filter removed. Practically: per-result makes every row cost the same, so free context rows are impossible; per-event lets the useful rows carry the price and everything else be free.
What about compute and proxy costs?
Those are Apify platform usage, billed separately from the event price and generally tiny for these actors — a fraction of a cent per run for the JSON-endpoint scrapers. The exception is the residential-proxy sources: TripAdvisor pages are about a megabyte per ten reviews, which is why a residential review row costs more than a datacenter one. When you compare listings, check whether proxy traffic is inside the row price or billed on top.
Can a run bill me for more rows than I received?
It should not, and that is a question worth asking explicitly. The invariant to demand is: when a run hits its spending limit it stops delivering rather than writing rows it cannot charge for, so the dataset count and the invoice always agree. Without that, a limit hit halfway through leaves you with a partial dataset and a full bill.
Is a cheaper row always cheaper?
No. A $0.002 row that you must fetch a hundred of to find the ten you wanted costs more than a $0.01 row that arrives pre-filtered. The parity row here is the most expensive row in the suite at $0.01, and it replaces five separate price rows plus the join.
Run Trustpilot Reviews Scraper on Apify →
Other actors used on this page: apify.com/kestrel/hotel-rate-parity, apify.com/kestrel/amazon-reviews-scraper, apify.com/kestrel/google-hotels-prices.