ActorStack.dev

Reading robots.txt as a specification, not an obstacle

A site's robots.txt is the only machine-readable statement it makes about crawling. Treating it as the specification — and downloading it on every run — is why a scraper survives.

By Oswaldo Carabano7 min read

Short answer

robots.txt is the one place a site declares, in a machine-readable form, which URLs crawlers may request. Downloading the live file on every run rather than hard-coding its contents means a scraper adapts when the site changes its mind, and it turns compliance into a property of the code instead of a claim in a README. coches.net, for example, disallows `pg=7` through `pg=69`, which sets the maximum compliant pagination depth at six.

Key points

  • robots.txt is a declaration by the site, which makes it the closest thing to a contract when there is no API.
  • Fetching it live on every run means a rule change takes effect immediately instead of at your next deploy.
  • Specific pagination disallows are common and easy to miss: coches.net enumerates `pg=7` to `pg=69` individually.
  • A disallowed path is often also a dead end — deep pagination on coches.net stops returning results past roughly page 300 anyway.
  • Compliance and reliability point the same way far more often than they conflict.
On this page6 sections

Most scraping guides mention robots.txt once, in a paragraph about ethics, and then never again. That framing is why it gets ignored: presented as a moral obligation it competes with getting the job done. Presented as what it actually is — the only machine-readable specification the site publishes about automated access — it stops being a competing concern and becomes the document you design from.

What robots.txt is and is not

It is a plain-text file at a site's root in which the site states which URL patterns automated clients may and may not request. It is a declaration, not a technical control: nothing enforces it, which is exactly why respecting it is a decision rather than a constraint.

It is not a statute, and its legal weight varies by jurisdiction and context. What it does unambiguously establish is intent — which converts ignoring it from an oversight into a deliberate act, and that distinction tends to matter more than people expect when anything goes wrong.

Why the file gets downloaded every run

The tempting shortcut is to read it once during development, encode the rules as constants, and ship. It works until the site changes its mind — and then your scraper is confidently violating rules it has never seen, using a copy that was accurate in August.

Downloading it live at the start of every run costs one HTTP request and makes compliance a property of the code rather than a claim in a README. If coches.net tightens its pagination rules tomorrow, the next run adapts; nobody has to notice, remember, and deploy.

Reading a real one

Here is the part of coches.net's file that governs a listing scraper. It is not a wildcard — it enumerates the disallowed pagination values one at a time:

coches.net/robots.txt — excerpt
User-agent: *
...
Allow: /concesionarios/
Disallow: /*/Detail/
Disallow: /ws/
Disallow: /*pg=7*
Disallow: /*pg=8*
...
Disallow: /*pg=69*
Disallow: /*?q=*

Four design decisions fall straight out of that:

  • Dealer pages are explicitly allowed, so a dealer dataset is on the intended surface.
  • Detail-page patterns are disallowed, which is one of two reasons the Actor does not request advert pages — the other being that they sit behind stricter bot protection.
  • Internal endpoints under /ws/ are off limits, so no “undocumented API” shortcut.
  • Pagination stops at six. Which determines the entire discovery strategy.

Pagination limits hide in plain sight

A pagination disallow is the most consequential rule a listing site can publish and the easiest to miss, because it looks like clutter. Six allowed pages is roughly 210 rows per URL — nowhere near an inventory of hundreds of thousands.

The answer is breadth rather than depth: expand facets — make, then province, then price band — so each combination has its own shallow, permitted page list. How that works in practice.

When the rules and your interests agree

Far more often than the ethics framing suggests. On coches.net, deep pagination is disallowed and ineffective: the site's own search stops returning results past roughly page 300, so a crawler that ignored the rule would still miss about 96% of the inventory. The compliant strategy is also the only one that works.

The same pattern shows up in rate limiting. Measured against Nextdoor, concurrency 5 ran clean while 10 triggered a roughly four-minute cooldown — so the polite configuration is the fast one, and the aggressive one is slower in wall-clock terms. Sites are not usually punishing you arbitrarily; they are protecting infrastructure whose failure modes also degrade your run.

When they do not

Sometimes the rules simply put the data you want out of reach. Then the honest outcome is that the data is unavailable to you by that route, and the correct behaviour for the scraper is to report the failure rather than route around it.

Concretely, that means no CAPTCHA solving, no TLS or browser fingerprint spoofing, and no requesting a path the file disallows. It is a real product limitation and it is stated on each Actor's page as one — because a tool whose reliability comes from evading detection has a reliability that lasts exactly until the detection improves.

Frequently asked questions

Is robots.txt legally binding?
It is not a statute, and its legal weight varies by jurisdiction and context. It is, however, an explicit statement of the site's wishes, which makes ignoring it a deliberate act rather than an oversight — and that distinction tends to matter.
Should a scraper cache robots.txt?
Within a run, yes. Across runs, no: the point of reading it live is that a rule change takes effect without a code change.
What happens when robots.txt blocks the data you need?
The honest outcome is that the data is not available to you by that route. This project's Actors report the failure instead of routing around it.

Sources

Every URL below was requested and returned a page on the date shown.

  1. Site declarationchecked 18 Aug 2026
    coches.net/robots.txtcoches.net
  2. Site declarationchecked 18 Aug 2026
    nextdoor.com/robots.txtNextdoor
  3. Platform docschecked 18 Aug 2026
    Crawlee — web scraping and browser automation libraryApify
  4. Operator claimchecked 18 Aug 2026
    Coches.net Car Listings & Dealer Scraper — Actor README and input schemaActorStack / Apify Store
A white measuring tape curving across a dark background, showing the numbers 15 to 45.
EngineeringExplainer

Measured fill rates

A field list is a promise. A fill rate is a measurement. This is what happened when one Actor's numbers were re-measured at n=741 instead of n=30.

6 min
Paper receipts and printed documents arranged on a desk beside office stationery.
EngineeringExplainer

Pay-per-event pricing

Charging per delivered row changes what you are allowed to ship. If an error row costs the user money, every bug becomes a billing dispute.

6 min
Racks of network equipment in a dimly lit server room, lit blue by their indicators.
EngineeringExplainer

Cache metadata

Shared caching makes runs fast and cheap and quietly destroys trust — unless the row itself reports where it came from and when.

5 min