Quick answer
The eCFR — the codified, currently-in-force text of US federal regulations — publishes official XML with no key and no signup:
GET https://www.ecfr.gov/api/versioner/v1/full/{date}/title-{title}.xml?part={part}
That is the eCFR Regulations Scraper: give it {title, part} pairs, get one flat row per section — a well-formed citation like 29 CFR 570.1, the heading, and the full verbatim body text.
The API is genuinely pleasant. Our own build was not, and the two ways it went wrong are worth more to you than another tour of a JSON schema.
Our first cloud run succeeded, and did nothing at all 💀
The run finished. Status: SUCCEEDED. Exit code 0. Four lines of log. Zero rows.
The Dockerfile said:
CMD ["python", "-m", "src.main"]
and the runner lived in src/__main__.py.
Importing src.main as __main__ is perfectly legal Python. It defined main(). It never called it. The container started, imported a module, and exited cleanly — which the platform records, correctly, as success.
The reason this survived local testing is the part worth remembering: apify run locally executes python -m src, while the deployed container runs whatever CMD says. Local and cloud had different entrypoints. Every local test passed while the shipped artifact did nothing.
This shape is expensive because it is invisible in exactly the place you look for problems. A zero-row SUCCEEDED run scores 100% on every health dashboard we have. We have shipped this defect before, monetized, and charged a per-run start fee four times for empty datasets before anyone noticed.
The fix is not "be careful." It is a check that refuses to start a cloud run when CMD and the real entrypoint module disagree — one that runs before the run, not before the publish, because the run is where the money is.
Then it passed QA on one row, with the product untested 🎣
The second run worked. One row. Green.
Our smoke test builds its input from the Actor's own input_schema.json prefill, and the prefill asked for Title 1, Part 1 — which contains exactly one section.
So the multi-section parse loop, the nesting walk, the citation builder across differently-shaped parts — the entire product — never executed in the cloud. It passed on the one code path that a single section exercises.
Prefill breadth silently sets cloud test coverage. The prefill is not a demo value; it is the payload your automated verification actually runs. A one-item prefill means your multi-item path ships having never run on the platform.
Widened to Title 1 Part 1 plus Title 29 Part 570: 75 rows across two titles, and a real exercise of the walk. We confirmed the section count independently against the GPO XML rather than trusting our own output — 74 sections in 29 CFR 570, counted from the source.
What the GPO XML actually does 📄
Sections are not flat. SECTION nodes nest inside subject groups and part wrappers, and the depth varies by part — so a fixed-depth XPath works on the part you tested and quietly misses provisions elsewhere. We walk every SECTION node regardless of nesting.
Two smaller things that cost time:
- Dates must be in force. Ask for a date the title did not exist in and you get an error, not an empty result. Omit the date and we resolve the latest in-force date for that title automatically, rather than making you guess a valid one.
- This is not a change feed. The eCFR answers "what is the rule right now, verbatim." For the daily journal of rulemaking, that is the Federal Register — a different corpus answering a different question.
What a row looks like
Citation (29 CFR 570.142), title number, part, section number, heading, full body text, the resolved as-of date, and an ISO-8601 fetch timestamp. Pydantic-validated, with a regex-checked citation on every row — a malformed citation fails loudly at build time instead of landing in your index.
Who this is for 🎯
- Compliance and GRC — verbatim rule text for a control mapping.
- Legal ops — a clean, citation-tagged corpus for a search index or RAG pipeline.
- Audit — a snapshot of a Part's in-force text on a specific date.
- Industry monitoring — a handful of Parts, without pulling an entire Title.
The honest limitations 🚧
- Up to 20
{title, part}pairs per run. This is a targeted extractor, not a bulk mirror of all 50 titles. - Currently-in-force text only. No amendment history and no diffs between dates.
- Section-level granularity. Appendices and tables come through as body text, not as separate structured objects.
Pricing
$0.20 per run plus $0.002 per row — $2.20 per 1,000. Pay for rows that land.
→ eCFR Regulations Scraper on Apify
Built by Devil Scrapes. We handle the nesting, the in-force date resolution, and the retries — and we now check that our container actually runs the code before we charge anyone for it.
Top comments (0)