kestrel actors docs

kestrel actorsGuides

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.

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:

RowPriceWhy
Trustpilot review$0.0007Compact JSON, one browser solve amortised over a whole run
Indeed review, AliExpress review$0.002Datacenter, 20-50 rows per request
Airbnb occupancy month, Google Hotels offer$0.002A derived row on top of a request already made
Hostelworld, HRS, Kurzurlaub review$0.003Open APIs, small pages
Google Hotels hotel row, Amazon product$0.004One request per entity
OTA review rows, Amazon review$0.005Residential traffic or heavier pages
Rate parity row$0.01Every 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

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.

More guides