The question every censorship analyst keeps asking

"Which countries behave like Iran?" It comes up constantly — a journalist writing a comparative piece, a researcher looking for a label-rich neighbor to borrow signal from, the forecast model needing a zero-shot prior for a country it has barely measured. Until now Voidly Atlas had no single answer. The DTW shutdown cohorts grouped countries by the shape of their daily signal series, but shape alone misses how a country blocks — its method mix, the categories it targets, how severe and how bursty its blocking is.

This finding ships a country censorship-behavior similarity graph: every country is embedded into a vector space built from its measured blocking behavior, and for each country we surface the top-10 most behaviorally similar countries by cosine similarity.

The feature vector — 32 dimensions of measured behavior

For each country, over a trailing 365-day window, the build script assembles seven feature families:

All features are standardized (zero-mean, unit-variance) so a high-variance family like outage fraction does not drown out a low-variance one. Pairwise cosine similarity then ranks neighbors; a UMAP 2D projection (PCA fallback if umap-learn is unavailable) gives coordinates for a behavioral map.

What it found — 135 countries embedded

The first run on 21 May 2026 embedded 135 countries (every country with at least 20 evidence rows in the trailing window) across 32 features. The neighbor lists are intuitive where they should be:

And it surfaces pairs worth a second look. Czechia and Albania land at cosine 0.85 despite a two-tier risk gap — a reminder that the graph measures the footprint, not the politics. Two countries can rhyme behaviorally because both run seasonal piracy blocks or both show the same DNS-poisoning signature, while their governments, laws and intent are nothing alike.

Honest caveats

Similarity here is behavioral, not political. This is the single most important caveat and it is baked into every API response. A stable democracy with court-ordered sports-piracy blocking can sit near an authoritarian state if their measured blocking footprints rhyme. The graph is a tool for "whose blocking looks like whose," never for "whose government looks like whose."

Feature vectors are sparse for low-coverage countries. A country with few OONI probes inside it populates only the regime / continent / cohort one-hot dimensions; its behavioral families are near-zero. Those countries are flagged sparse: true (fewer than 3 of 5 behavioral feature families populated) and their neighbor lists should be read with low confidence — they are dominated by the one-hot blocks, not by measured behavior.

The 2D projection loses information. The /graph endpoint compresses 32 dimensions to 2 for plotting. Pixel distance in that projection is a visual aid only — use the cosine neighbors list, not the projected coordinates, for any quantitative similarity claim.

How to use it

GET /v1/atlas/country-similarity/{cc} returns the top-10 nearest countries for a given ISO-2 code plus that country's own behavioral metadata. GET /v1/atlas/country-similarity/graph returns the UMAP/PCA 2D coordinates for all 135 embedded countries. GET /v1/atlas/country-similarity/info documents the feature groups and refresh cadence. The sidecar is rebuilt weekly (Monday 05:10 UTC). Build script: scripts/build-country-similarity-graph.py; endpoint patcher: scripts/patch-atlas-country-similarity-endpoint.py.