Independent measurement of the open web

Methodology annex · Report 01

How this was measured

A measurement is only worth as much as the account of how it was taken. This is the full method for Content provenance on the open web, including the two errors we made and corrected before publishing.

Last updated

1. Sample frame

Tranco top-1M, a research-oriented domain ranking that aggregates several sources and is designed to resist the manipulation affecting commercial traffic lists. We use a published frame rather than a hand-picked list specifically so the sample is not ours to choose.

Four rank bands, 700 domains drawn from each:

BandRanksDrawn
top1k1 – 1,000700
top10k1,001 – 10,000700
top100k10,001 – 100,000700
tail100,001 – 1,000,000700

Selection within a band uses a fixed stride, not a random draw (stride = floor(pool / 700), taking every nth eligible domain). This is deterministic: re-running against the same Tranco snapshot selects the same domains. There is no seed to disclose because there is no randomness.

Exclusions from the frame

Domains matching a published pattern list are removed before sampling: DNS and CDN infrastructure, certificate and OCSP endpoints, telemetry and analytics collectors, and platform asset hosts. These rank highly in a DNS-derived list but are not websites. The exclusion is stated because it is a judgement call that affects the denominator.

2. Collection

  1. Load https://<domain>/ in headless Chromium (Playwright), 1366×900, en-GB, Europe/London, 20 s navigation timeout.
  2. Wait for DOM content, then a short settle period for client-rendered pages.
  3. Collect image URLs from the rendered DOM: img[src], currentSrc, data-src, every candidate in srcset, every source[srcset], plus og:image.
  4. Deduplicate, resolve to absolute URLs, drop SVG and data: URIs, cap at 30 per domain.
  5. Fetch the first 128 KB of each image with an HTTP Range request.
Why a ranged request. C2PA manifests sit near the head of the file — the JPEG APP11 segment, the PNG caBX chunk and the XMP packet all appear before the image data. Fetching 128 KB instead of whole files reduces a million-image crawl from tens of terabytes to roughly 60–120 GB, and reduces load on the sites measured. Images are disabled in the renderer for the same reason: URLs are read from the DOM, and only the ranged fetch downloads bytes.

3. Detection

Two stages. The first is cheap and deliberately permissive; the second is authoritative.

render page → collect image URLs → ranged fetch
   → stage 1: byte scan     (permissive — must never miss)
   → stage 2: c2patool      (authoritative — removes false hits)

Stage 1 scans the bytes for:

Stage 2 passes every stage-1 hit to c2patool 0.27.7, the C2PA reference implementation. Only confirmed manifests are counted. Stage 1 over-firing costs one tool invocation; stage 1 under-firing loses a manifest permanently and invisibly, so the threshold is set accordingly.

4. The recall gate

The instrument was not permitted to measure anything until it had been shown to detect what it was looking for. A detector that finds nothing produces the same output as a web that contains nothing, and the two are indistinguishable without a gate.

Gate results against the C2PA reference test corpus.
CheckResult
Ground truthc2patool 0.27.7
Recall on known positives11 / 11 — 100%
Formats verifiedJPEG, PNG, WebP
Delivery modes verifiedembedded JUMBF and remote manifest
False positives at stage 12 — both removed by stage 2
Confirmed positive on the live webyes

5. Non-response

Every failure is recorded with a cause derived from the actual Chromium error code, not a catch-all. Causes are reported by rank band so that bias can be assessed rather than asserted. A domain we could not reach is never counted as a domain without provenance.

Categories: DNS name resolution failure · connection refused or reset · TLS or certificate error · HTTP/2 or QUIC protocol error · timeout · bot wall (403/429/503) · JavaScript challenge page · reachable but no qualifying images · other HTTP error.

6. Statistics

Rates are reported with a Wilson score interval at 95%, which behaves correctly for very small proportions where the normal approximation does not. We report the interval, and where a single number is needed we use the upper bound rather than the point estimate.

We also publish an explicit worst-case bound: the rate that would obtain if every unmeasured domain carried provenance on every image. It is an absurd assumption by construction. It is published because it is the first objection a reviewer should raise.

7. Errors made and corrected

Both of the following were caught before publication. They are recorded here because a methodology that lists no mistakes is not describing a real process.

7.1 Instrument recall was mistaken for population recall

An earlier draft reported "100% recall" as evidence that the finding was trustworthy. That figure describes the detector's performance on files already in hand. It says nothing about the share of the population that could be reached. The two are unrelated, and conflating them would have overstated the study's authority. The published version reports coverage and recall separately, and reports coverage by band.

7.2 The first failure taxonomy was a catch-all

An earlier version classified any navigation error that was not a timeout or a certificate problem as "DNS failure", producing a 22.8% bucket that hid connection resets, protocol errors and possibly silent blocking. It was replaced with classification on the actual Chromium error code, retaining the raw string. The corrected data showed the bucket was in fact dominated by genuine ERR_NAME_NOT_RESOLVED — but that was a finding, not an assumption, and it was only available once the taxonomy was real.

8. What this method cannot tell you

9. Corrections policy

If you are named in a study and believe something is wrong, write to corrections@netcensus.org. We re-run the measurement and publish the outcome either way, with the date. Corrections are free, and we do not require anything in return.