Quick answer
We gate every Actor release on "two successful runs at least an hour apart." The Cars.com Listings Scraper passed that gate while being 33% reliable — 1 success in 3 — and passing it meant nothing. Two greens an hour apart on a coin-flip scraper is evidence you rolled the dice enough times, not evidence of reliability. The fix was the same one-retry-budget bug we had found in a different Actor that morning, and it took cars.com from 33% to 5 out of 5 at $1.40 per 1,000 results.
Why did a passing gate prove nothing? 🎲
The rule exists for a good reason: a scraper can get lucky once, and a single green run right after a build tells you almost nothing about a target with active anti-bot defences. Requiring two greens spaced an hour apart is meant to catch the actor that works only on a warm cache or a lucky exit IP.
What it does not catch is an Actor whose per-run success probability is simply low. At 33%, the chance of eventually getting two greens an hour apart is essentially 1 — you just have to keep running it. The gate measures spacing. It does not measure rate. If nobody counts the failures in between, an unreliable Actor walks straight through.
That matters more here than it sounds, because publishing a monetized Actor on this platform is a one-way door: once it is public and priced, it cannot be unpublished. So the honest move was to refuse the lucky second green and go find out why one run in three was dying.
What was actually broken? 🧱
The same defect we had root-caused in the Manta scraper hours earlier: one retry budget shared between two unrelated failure classes.
- cars.com refuses you — a genuine challenge response from the site.
-
The request never reaches cars.com — a
Page.gototransport timeout on a dead residential proxy tunnel. The site has no idea you exist.
Both look like "navigation failed" at the call site. Sharing a budget means the transport faults spend the attempts the real challenge needed, and — worse — every exhaustion gets reported as a bot wall, so the logs point at the site when the plumbing is at fault. The fix is independent budgets, sized separately, with the error message naming which one ran out.
The stale verdict underneath it 📁
Cars.com had been shelved with the note "403 on all four proxy tiers." That verdict was wrong by the time we read it. Camoufox reaches cars.com fine, and the code proving it had been sitting on an unmerged branch — meaning our main was behind what was actually deployed, and any routine push from main would have silently reverted the working code.
That is a failure mode worth naming, because it is invisible: a fix can be committed, deployed, and then quietly reverted by the next deploy from a branch that never received it. "Committed" and "deployed" diverge without anything erroring. Two of this fleet's longest debugging sessions have been spent reading failures produced by code we had already fixed.
How do you know the rows are real? 🕵️
Because a SUCCEEDED run with rows is not proof of delivery. A blocked page that returns 200 can feed fallback selectors enough furniture to manufacture plausible-looking rows, and "has a title and a link" validation will wave them through.
So the delivery check asserts something only a real vehicle listing can satisfy: a valid 17-character VIN and a cars.com detail-page URL shape. Final verification was 5 runs out of 5 SUCCEEDED, 5 real rows each, 0 of 5 failing the VIN/URL check — genuine vehicles, a 2018 Jaguar XE, a 2021 Escalade, a 2019 AMG E 63 S. Residential proxy usage was confirmed from platform billing on all five runs, not from the config we requested.
One more trap worth recording: an early billing read showed 0.00 residential transfer and looked like proof the proxy tier had been ignored. It was not — run cost settles late, and proxy transfer can be the majority of a browser run's bill while showing zero immediately after the run ends. Never price, and never draw a tier conclusion, off an immediate read.
Also fixed on the way through
- A TIMED-OUT run caused by detail-page enrichment retrying a failing fetch on every row with no circuit breaker. One bad detail page should cost you one row, not the run.
- The Actor billed its start fee before validating input, so a malformed request was charged for nothing.
- No smoke-marked tests, so the fast pre-publish check had nothing to run.
FAQ
What does it cost?
$0.20 per run start plus $0.0012 per row — $1.40 for 1,000 listings. You pay for results, not for runtime.
Do I need a proxy or an account?
No. The browser engine, residential proxy rotation, challenge retries and backoff are all inside the Actor.
What is in a row?
VIN, year, make, model, trim, price, mileage, dealer, location and the listing URL.
Will a search that matches nothing fail the run?
No. Zero legitimate matches finishes SUCCEEDED with a message naming what was searched. Only real errors fail.
Built by Devil Scrapes. We do the dirty work so your dataset stays clean. 😈
Top comments (0)