Scraping platform costs: measure successful rows, not browser minutes
A scraping job usually fails in boring ways: the browser hangs, a selector starts returning empty strings, a login expires, or the target site returns a captcha halfway through the run. The awkward part is that many platforms still bill you for the work done before the failure. If you run enough jobs, that difference shows up both in your invoice and in the amount of defensive code you need around the scraper. Billing by compute time changes how you build A lot of scraping platforms charge for runtime. Apify, for example, uses compute units: memory multiplied by time. A browser-heavy actor running for ten minutes with 2 GB of RAM consumes roughly a third of a compute unit before any actor-specific result fees. That model is reasonable from the provider side. Chromium processes are expensive. Proxies cost money. Retries use resources. But as the caller, you care about a different unit: did I get the rows I needed? The hard part is that runtime billing makes cost hard to know before execution. A job that normally takes 30 seconds might take 8 minutes when a site slows down. A job that returns malformed data can still count as successful from the platform's point of view. A job that fails after rendering 200 pages still consumed browser time. If your pipeline runs once a day, that may be fine. If it runs continuously, you probably want a local cost model that tracks outcomes, not just requests. type ScrapeRun = { jobId : string ; target : string ; startedAt : string ; finishedAt ?: string ; status : " queued " | " running " | " succeeded " | " failed " ; rowsExpected ?: number ; rowsReceived ?: number ; billedUnits ?: number ; }; function isUsefulResult ( run : ScrapeRun ) { if ( run . status !== " succeeded " ) return false ; if ( run . rowsExpected && ( run . rowsReceived ?? 0 ) < run . rowsExpected * 0.9 ) { return false ; } return ( run . rowsReceived ?? 0 ) > 0 ; } function costPerUsefulRow ( run : ScrapeRun ) { if ( ! isUsefulResult ( run )) return Infinity ; ret