eCFR Atlas
API

How the numbers are made

Methodology

Every word count on this site is produced by parsing the eCFR's own XML. None is estimated, extrapolated or inferred from file size. This page states the rules precisely enough to disagree with.

What counts as a word

After the excluded elements below are removed, the remaining text is split into tokens and each token is counted as one word if and only if it contains at least one Unicode letter or number. The alphanumeric test is /[\p{L}\p{N}]/u. There is no Unicode normalisation pass; the text is scanned code point by code point exactly as eCFR publishes it. Three kinds of character end a token:

  • any Unicode whitespace character;
  • en dash, em dash and horizontal bar (–, —, ―), because they join independent words in prose;
  • a run of two or more hyphen-minus characters. A single hyphen does not split.

Zero-width and invisible formatting characters (U+00AD soft hyphen, U+200B–U+200D, U+2060, U+FEFF) are deleted rather than treated as boundaries, so a word broken across a printed line counts once.

Consequences of that rule, spelled out because they are where reasonable people differ:

  • 60.1 is one word. Section numbers count.
  • cross-reference is one word, not two. A single hyphen joins.
  • and/or is one word. Slashes, apostrophes and periods do not split.
  • § and — on their own are not words: no letter, no digit. So § 60.1 is one word, not two.
  • Paragraph designators are counted. A bare (a) contains the letter “a”, so it is one word, and (a)(2)(iii) is one word too. They are part of the regulation and they are how it is cited.
  • words—including is two words. An em dash separates even with no space around it.
  • Table contents are not counted at all — see the exclusions below. A table of emission limits is regulation, and the counts on this site do not reflect it. This is the single largest known limitation of the measurement.

What is excluded, and why

Counting a part's raw XML would count its scaffolding. The following eCFR elements are removed before tokenisation, along with their contents:

HEAD
Headings. They repeat the citation already counted in the structure.
AUTH, SECAUTH
The statutory authority note, at part level and at section level. It cites the enabling statute; it is not the regulation text. It is shown on every part page, just not counted.
SOURCE
Federal Register source notes — publication provenance, not regulatory content.
CITA
Citation notes.
CONTENTS
Generated tables of contents, which would double-count every section heading.
EAR
The running-head “ear” printed in the margin of the paper CFR.
FTNT
Footnote apparatus.
XREF
eCFR's own editorial navigation — “Link to an amendment published at 91 FR 43564” — which appears and disappears as amendments pend. Counting it would make a section's total move for a reason that has nothing to do with the regulation. Measured at 17 occurrences and 204 words in 40 CFR 60, and absent from 1 CFR entirely.
Table markup: TABLE, CAPTION, THEAD, TBODY, TFOOT, TR, TH, TD, and the GPO vocabulary GPOTABLE, BOXHD, CHED, ROW, ENT, TTITLE, TDESC, TNOTE
Removed with their contents, so no text inside a table is counted — neither the column labels nor the values. The reasoning is that a table's “words” are largely repeated headers and units, and counting them makes a title's total a function of how its tables were laid out rather than of how much regulation it contains. It is a defensible line and it is also a real limitation: a part whose substance lives in tables measures low here, and this site does not currently publish a separate table-cell count.

Two things that look like apparatus are deliberately kept, having been checked. HD1/HD2/HD3 — undesignated centre headings inside a section body — are counted, because unlike HEAD they appear in no ancestor's table of contents and so duplicate nothing: 1,997 of them and 9,418 words in 40 CFR 60. MATH is kept too, but eCFR publishes equations as raster images, so it contributes nothing. Equations are effectively invisible to this measurement.

The exclusions matter more than they sound. Measured against 1 CFR Chapter I, the heading and note boilerplate is 18.4% of the text. A count that includes it is not slightly high; it is high by nearly a fifth, and unevenly, because boilerplate density varies with how finely a part is subdivided.

How the text is extracted

With a real XML parser, never a regular expression. That is a hard rule in this codebase and it is not stylistic: the CFR's XML does not have the regular structure a pattern would need. Nesting depth is not sequential — title 7 jumps from DIV2 straight to DIV5 in 35 places — and title 40 contains 19,134 untyped DIV elements sitting inside sections. Any pattern that appears to work does so by accident on the titles it was tested against.

A second trap sits at the fetch layer. eCFR's ?chapter= and ?subtitle= query parameters validate but do not slice: they return the entire title. Only ?part= and ?section= narrow the response. Code that assumes otherwise silently measures a whole title and attributes it to one chapter, which is exactly the failure that produced a 12.7× over-credit in this project's predecessor.

How agency scopes are resolved

eCFR gives each agency a list of CFR references. A reference may name a title, a subtitle, a chapter, a subchapter or a part, and the fields nest — one reference can carry several at once. The narrowest level present defines the scope. A reference naming both Chapter I and Part 60 is a reference to Part 60, and crediting the agency with the whole chapter would over-count it by the size of everything else in that chapter.

Twelve of the 487 references in the corpus carry a chapter alongside something narrower. They are the reason this rule is stated first and enforced in a shared function rather than re-implemented per caller.

How shared scopes are divided

Two totals are published for every agency, and they answer different questions.

Attributed
Every scope the agency claims, counted in full. Answers “how much regulation is this agency responsible for?”. It is correct per agency and wrong in aggregate — summing it across agencies counts each shared scope once per claimant.
Deduplicated
A scope claimed by n agencies contributes its words divided by n to each of them. Answers “how does the CFR divide up?”, and sums correctly to the corpus. This is the dashboard headline.

Even division is a modelling choice, not a measurement. Nothing in the data says how the administrative burden of a jointly held scope actually splits, so the site applies the only weighting that requires no invention and says so wherever the number appears. Rounding to whole words leaves a residual of at most one word per claimant. The full list of overlaps is on shared jurisdiction.

The dashboard also publishes a third figure, “words under shared jurisdiction”, and it is worth being exact about how the three relate, because it is easy to state wrongly. Write w for a shared scope's word count and n for its number of claimants. The shared figure is the sum of w — each shared scope counted once, so it is directly comparable with the deduplicated corpus total. The gap between the attributed and deduplicated totals is the sum of (n − 1) × w, which is larger: a scope claimed by six agencies contributes five extra copies of itself, not one. The two are equal only where every shared scope has exactly two claimants, and in this corpus they have between two and six.

How totals are rolled up

A parent's count is the sum of its children's — but only when every child is known. If one descendant could not be measured, the parent is reported as unmeasured rather than as a partial sum. This is deliberate and occasionally frustrating: a partial sum under-reports, and an under-report looks like a plausible number rather than an error, which makes it worse than an obvious gap.

Reserved nodes are the exception. A reserved part genuinely contains nothing, so it contributes a measured zero and does not spoil the roll-up.

What “—” means

An em dash is never a zero and never a placeholder. It means the value was not measured, and hovering it gives the reason. There are four:

not_computed — Not yet computed
The node is in scope but no sync run has reached it yet. It will resolve on a subsequent run without any intervention.
unavailable_fetch_failed — Source fetch failed
eCFR did not return the XML within the retry budget. Two distinct upstream failures produce this: a token-bucket 429, and a gateway timeout at about 50 seconds when the origin takes too long to generate a large title. The second is closer to a coin flip than an error — isolated fetches of title 49 failed twice in four attempts.
unavailable_parse_failed — Could not be parsed
The XML came back but could not be parsed into a countable subtree. Every one of these is a bug on our side, not upstream, and is worth reporting.
unavailable_too_large — Skipped — above the processing ceiling
The node exceeds the per-node processing ceiling and was skipped on purpose rather than processed partially. A partial count would look like a plausible number.

Every node in this state is listed, grouped and counted on data quality.

Dates

eCFR publishes on business days only — 57 issue dates in an 84-day window, none at a weekend, with a median of 48 changed sections per publishing day. Charts on this site do not smooth across those gaps.

Amendments carry two dates and they disagree in about half of all rows. This site keys content on issue date, not amendment date, because 40.4% of amendment dates fall before eCFR's 2017-01-01 full-text horizon; fetching at an amendment date returns nothing, and a naive comparison then renders “section added” for a section that has existed for decades.