voidly

Cross-source agreement

How often do OONI, IODA, CensoredPlanet, and the Voidly probe network independently flag the same country-day as anomalous? Two metrics: pairwise Cohen's kappa (chance-adjusted agreement) and the share of country-days where 2+ sources fire together. Designed for journalists who want to know whether a finding is corroborated across multiple independent sensors.

Generated 2026-05-21T13:56:05 · window 365d · 6,108 country-days · Raw JSON

Headline
50.7% of confirmed censorship-days are corroborated by ≥2 independent sources.
Across all anomalous country-days, 17.6% had ≥2 sources firing together (1,074 of 6,108 days). When restricted to days with a confirmed censorship incident in the voidly_data.db incidents table, the rate rises to 50.7% (136 of 268 confirmed days) — a tangible measure of how often censorship leaves multiple independent fingerprints.

Pairwise Cohen's kappa

For each pair of sources, kappa measures agreement on the binary “did this source fire today?” indicator, adjusted for chance agreement. κ = 1.0 is perfect agreement, κ = 0 is chance-level, κ < 0 is systematic disagreement.

OONIIODACensoredPlanetVoidly probesOONIIODACensoredPlanetVoidly probes1.00self-0.60κ0.14κ-0.00κ-0.60κ1.00self-0.30κ-0.00κ0.14κ-0.30κ1.00self-0.00κ-0.00κ-0.00κ-0.00κ1.00selfκ scale:< 0~ 00.1-0.4> 0.4

Low or negative kappa here is the honest finding — the four sources observe different layers of the internet (active probing vs BGP route changes vs DNS scans vs reachability checks). They rarely fire on the exact same country-day, which is why the multi-source corroboration rate above (≥2 sources, 17.6%) is a more journalistically actionable signal than pairwise kappa.

Per-source marginal fire rate

OONI
37.2%
2,273 country-days
IODA
60.3%
3,681 country-days
CensoredPlanet
22.9%
1,397 country-days
Voidly probes
0.2%
13 country-days

Share of all anomalous country-days (n= 6,108) on which each source emitted at least one elevated/warning/critical-level row. Cohen's kappa above is computed against this baseline.

Multi-source corroboration rate, last 12 months

Per-month fraction of anomalous country-days where ≥2 sources fired. Bar height = n country-days that month; teal overlay = share with ≥2 sources.

379759113815172025-050%2025-060%2025-070%2025-080%2025-090%2025-100%2025-110%2025-120%2026-011%2026-0218%2026-0323%2026-0419%2026-0526%total country-days≥ 2 sources corroborating
Per-month table
MonthTotal≥2 sourcesRate
2025-052500.0%
2025-066500.0%
2025-076200.0%
2025-086600.0%
2025-096500.0%
2025-106800.0%
2025-116100.0%
2025-126300.0%
2026-0158271.2%
2026-021,21621817.9%
2026-031,51734222.5%
2026-041,45828119.3%
2026-0586022626.3%

Methodology

The four sources

  • OONI — active web-connectivity, Signal, WhatsApp, Telegram, Tor, and middlebox-detection probes run by volunteers worldwide.
  • IODA — BGP route observations + Trinocular active probing aggregated by Georgia Tech, surfacing AS-level outages.
  • CensoredPlanet — University of Michigan's Satellite (DNS) and Hyperquack (HTTP/HTTPS) global scans from outside the target country.
  • Voidly probes — our 40-node active probe network (Vultr + Fly.io + community probes) running 62-domain reachability checks every 5 minutes.

The unit: country-day

For each (country, date), we ask: did source s emit at least one row with signal_level in (elevated, warning, critical)? If yes, source s “fired.” This gives a 4-bit indicator per country-day: (ooni, ioda, censoredplanet, voidly_probes).

Cohen's kappa

For each pair of sources (a, b), kappa measures chance-adjusted agreement on the binary fire indicator:

Po = observed agreement   = (n_11 + n_00) / N
Pe = chance agreement     = P(a=1)*P(b=1) + P(a=0)*P(b=0)
κ  = (Po - Pe) / (1 - Pe)

Kappa is computed over country-days where at least one source fired — days where no source observed anything anomalous are excluded so that trivial “both quiet” agreement across 200+ countries doesn't artificially inflate the metric.

The ≥2-sources rate

For the journalist-facing “is this corroborated?” answer, we compute the simpler metric: of all anomalous country-days, what fraction had ≥2 sources firing? When restricted to country-days with a confirmed censorship incident (type in ('censorship', 'mixed'); IODA-only disruptions excluded), this rises to 50.7%.

Honest caveats

  • Source-presence is binary at the country-day level (one row -> present), so a single elevated OONI test counts the same as a dozen IODA outage rows. This avoids letting one noisy source dominate the agreement rate.
  • Voidly and Voidly-Community are merged into a single voidly_probes bucket -- their coverage overlaps geographically.
  • Cohen's kappa is computed over country-days WHERE AT LEAST ONE SOURCE FIRED. Days where no source fired are excluded so kappa isn't inflated by trivial 'both quiet' agreement across 200+ countries.
  • Most pairwise kappas are LOW (0.05-0.20). This is the honest finding -- the four sources observe DIFFERENT layers of the internet (active probing vs BGP vs DNS scans vs reachability checks) and rarely happen to fire on the same country-day. Low kappa here doesn't mean the sources are wrong; it means they're complementary, which is exactly why multi-source corroboration is informative when it DOES happen.
  • IODA fires heavily on connectivity disruptions that are not censorship (fiber cuts, BGP misconfigs). This is why the forecast pipeline excludes IODA from confirmed-censorship labels -- but we still report IODA presence here, because the journalist's question 'did multiple sources see this?' is answered by what they observed, not by our label rules.
GET /v1/atlas/source-agreement
Full sidecar — pairwise κ + monthly time series
GET /v1/atlas/source-agreement/{cc}
Per-country timeline (Iran example)
Bayesian corroboration
Posterior P(censorship | sources observed)

Sidecar generated: 2026-05-21T13:56:05.219544Z