◆ NICCOLÒ RIDI
← Back to Data

echr-py

Niccolò Ridi
A Python toolkit for empirical research on the European Court of Human Rights (2026)
524 Grand Chamber judgments · 4,416 citations · 1994–2026

The European Court of Human Rights has issued more than twenty-nine thousand judgments since 1959, and HUDOC publishes them alongside its decisions, orders and advisory opinions. Most judgments cite earlier ones, and those references form a network that maps which decisions the Court keeps returning to and which it decided once and left behind. echr-py is a Python toolkit that turns HUDOC into research-ready datasets, covering search and download, citation extraction, and network export.

This page describes the data and the problems it poses, shows the toolkit's core commands with each one copyable, and uses both to replicate the central finding of Voeten and Lupu's 2011 study of precedent in international courts. The replication covers every Grand Chamber judgment the Court has issued from 1994 to 2026.

I. The Data and the Question

HUDOC publishes every judgment, decision, and order the Court issues, and each record is structured. A record carries the application number, case name, respondent state, the Convention articles at issue, the judgment date, an importance rating from 1 to 4, whether any judge wrote separately, and whether a Committee, a Chamber, or the Grand Chamber decided it. That structure is what makes automated analysis possible.

Voeten and Lupu asked a question that is simple to state and hard to answer by reading. Citations carry different weight, so a decision cited fifty times shapes European law more than one cited twice. Which decisions anchor doctrine, and why those?

International courts operate without coercive enforcement, so they build legitimacy by embedding each new decision in a visible chain of past reasoning. On that account citation does the work of justification, and the shape of the citation network tells you something about how the Court manages its own authority.

The problems

Language. Judgments appear in several official languages, and the same case is cited differently across them. Resolution. Some references resolve cleanly to a target document, and others name a case without an application number. Recency. The Court's output grows every year, so any date-bounded corpus over-represents recent decisions and under-represents older ones that have had time to accumulate citations. Selection. HUDOC holds published decisions, and what was never published is invisible in a way that has its own pattern.

Welp — I double counted

An earlier draft of this essay reported 1,048 Grand Chamber judgments. There are 524. I have left the mistake in because it is the easiest one to make with this data, and because nothing about it looks like a mistake.

The search() and count functions default to languages=("ENG", "FRE"). Almost every Grand Chamber judgment appears in both English and French, and HUDOC stores each language version as a separate document with its own item ID. Ask for both and every judgment comes back twice. The number that lands is plausible, and it sorts and filters like any other number.

One line each way resolves it:

$echr-py count --body grand-chamber --collection JUDGMENTS
1048
$echr-py count --body grand-chamber --collection JUDGMENTS --language ENG
524
$echr-py count --body grand-chamber --collection JUDGMENTS --language FRE
524

524 and 524, exactly double. A language artefact scales by a clean factor where a real finding rarely does, and that is the signature to watch for. The same trap runs through the whole collection: its 58,427 “judgments” are 29,213 English and 29,214 French, and the stray extra one is a judgment with a French text and no English sibling. It is a small lesson in what “the corpus” means.

So pin the language. Every figure below counts each judgment once.

All of these are manageable, and all of them shape what the numbers below can support.

II. The Core Functions

Three commands handle most of the workflow, and you can copy each line separately. The package is on PyPI, and the source, issue tracker and full README are on GitHub.

1. Search and download

The search() function queries HUDOC by article, respondent state, date range, and importance level, and returns a typed collection with the metadata attached.

$pip install "echr-py[citations,analysis]"
Successfully installed echr-py-0.2.3
>>>from hudoc_py import search
>>>cases = search(article="6", respondent="TUR", date_from="2015-01-01", languages=("ENG",), sort="kpdate Ascending")
>>>len(cases)
1019
>>>print(cases[0].docname, cases[0].articles, cases[0].kp_date)
CASE OF GÜLAY COŞKUN v. TURKEY ['6', '6-1'] 2015-01-27

2. Citation extraction

The corpus build pipeline fetches every document under an application number, parses each into sections, paragraphs, opinions and bench, and resolves the Court-supplied citation list to exact documents. A second pass, citations locate, then finds every printed citation in the body, the footnotes and the separate opinions, with a paragraph pinpoint where the text provides one. The output below is what the commands print.

$echr-py corpus build --appno 46221/99 \
--rich-sections --citations --out ocalan/
echr-py corpus: 6 searched → 3 matched pairs; saved to ocalan/
>>>import pandas as pd
>>>df = pd.read_parquet('ocalan/cases.parquet')
>>>print(df[['itemid', 'docname', 'kp_date', 'separate_opinion']])
itemid docname kp_date separate_opinion 0 001-69022 CASE OF ÖCALAN v. TURKEY 2005-05-12 True 1 001-60979 CASE OF ÖCALAN v. TURKEY 2003-03-12 True 2 001-5562 ÖCALAN v. TURKEY 2000-12-14 None
>>>r = json.load(open('ocalan/citations/resolution-report.json'))
>>>print(r['mentions'], r['resolved'], r['review_required'])
122 95 27

3. Network export

You can export the citation graph as JSON, GEXF for Gephi, or a single offline HTML viewer, where each edge represents a citation from case A to case B; the JSON loads straight into NetworkX. The export below is a run of 7 October 2026 on the corpus-scoped resolution of every Grand Chamber judgment. Its 525th node is the Court's 2004 decision on its competence to give an advisory opinion, which the authority table resolves from its reporter reference; it is a decision, not a judgment, and the counts in Part III leave it out.

$echr-py graph export --kind citation-scl \
--format json --in corpus/citations --out network.json
echr-py graph: wrote network.json
>>>import json, networkx as nx
>>>G = nx.node_link_graph(json.load(open('network.json')), edges='links', directed=True)
>>>print(G.number_of_nodes(), G.number_of_edges(), round(nx.density(G), 4))
525 4426 0.0161

III. Replicating Voeten & Lupu

The replication measures in-degree centrality, meaning how many other judgments cite a given one. High in-degree marks a hub, a judgment the Court keeps returning to when it grounds a new holding.

Which judgments go into the corpus matters more than the measure itself. What follows is two corpora of exactly the same size, run through exactly the same pipeline.

First corpus: a thin recent slice

Take the Court's most recent 524 judgments, running from 16 December 2025 to 23 July 2026, seven months of output across every bench. Their SCL fields carry 4,063 citations between them. Resolve those against the corpus itself and almost nothing lands.

Six edges came out of four thousand references, and the median judgment in this corpus cites nothing inside it and is cited by nothing inside it.

You could write that up as a finding about the Court, with a long tail, a few hubs, and precedent thinly spread. What it actually measures is the window. Judgments cite earlier judgments, and in a seven-month frame almost every earlier judgment sits outside the frame. The 4,057 references that failed to resolve were pointing out of the box. Cut a citation network anywhere in time and this is what falls out.

Second corpus: the complete Grand Chamber

Now take a corpus that is closed rather than clipped: every Grand Chamber judgment the Court has handed down between 1994 and 2026. There are 524 of them, the same size as the slice above, which is a coincidence and a convenient one. The figures in this Part come from a run on 25 August 2026. A rebuild on 7 October 2026 with echr-py 0.2.3 returned 15,043 references, 4,426 internal citations, a density of 1.61% and eleven isolated judgments, with the same twelve hub cases within one or two citations of the counts below. Louvain community detection depends on its random seed: across forty seeds it returned seven, eight or nine clusters, so the eight below are one defensible partition rather than the partition.

Same method, same number of judgments, and the network is roughly seven hundred times denser at 1.61% against 0.0022%, with a mean in-degree of 8.41. 86% of Grand Chamber judgments are cited by at least one other Grand Chamber judgment, the median is cited six times, and the most-cited is cited sixty-two times.

The Grand Chamber is where the Court sends what it means to settle, and it is the bench that cites itself. The population is closed, so no citation falls off the edge of a window. It is small enough that its members genuinely refer to one another, and old enough, at thirty-two years, that the early judgments have had time to be picked up. This is the Court's own canon, and it behaves like one.

scroll to zoom · drag to pan · click a node for details
Doctrinal clusters

Figure 1 shows the complete Grand Chamber citation network, with 513 judgments and all 4,416 citations between them. The colours come from community detection rather than from Convention articles, using Louvain modularity on the citation graph, and node size scales with in-degree. You can scroll to zoom, drag to pan, hover over a node to see its neighbours, and click for the full record. Clicking a cluster in the legend mutes it. (Eleven judgments that neither cite nor are cited within the corpus are omitted, together with the one non-judgment node described in Part II.)

The clusters are doctrinal

Louvain community detection sees only the edges, meaning which judgment cites which, and it knows nothing about Convention articles, dates, or respondent states. It returned eight clusters from the link structure alone, and they map almost cleanly onto doctrinal areas.

ClusterSizeDominant articlesAnchor judgments
Property, remedies & pilot judgments916, 13Broniowski, Selmouni, Assanidze
Private life & discrimination888, 14K. and T., Christine Goodwin
Expression & association8010Fressoz and Roire, United Communist Party
Ill-treatment & liberty773, 5Kudła, Chahal, Labita
Life, force & jurisdiction692, 3Ilaşcu, McCann, Radomilja
Fair trial — civil limb616Roche, Z and Others, Micallef
Fair trial — criminal limb316Gäfgen, Sejdović
Legality & non-retroactivity167Scoppola, Stafford, Waite and Kennedy

The most interesting split is one the articles alone would not give you. Article 6 breaks into two clusters, a civil limb (Roche, Z and Others, on access to court and immunities) and a criminal limb (Gäfgen, Sejdović, on evidence and trial in absentia). Each limb cites internally and rarely crosses over. The Court's own citation practice treats them as two bodies of law that happen to share a provision number, and that shows up in the edges rather than in any of the metadata.

The hub cases

These are the twelve most-cited Grand Chamber judgments, and they are the cases a Strasbourg lawyer would name from memory.

#CaseCitedDateState
1K. and T. v. Finland622001-07-12FIN
2Kudła v. Poland542000-10-26POL
3Broniowski v. Poland422004-06-22POL
4Selmouni v. France381999-07-28FRA
5Assanidze v. Georgia372004-04-08GEO
6Fressoz and Roire v. France371999-01-21FRA
7Chahal v. United Kingdom361996-11-15GBR
8Ilaşcu and Others v. Moldova and Russia352004-07-08MDA / RUS
9Labita v. Italy342000-04-06ITA
10Radomilja and Others v. Croatia322018-03-20HRV
11McCann and Others v. United Kingdom311995-09-27GBR
12Gäfgen v. Germany292010-06-01DEU

K. and T. v. Finland sits at the top with sixty-two citations, and it is the reference point for the Court's Article 8 case law on taking children into care. Kudła created the effective-remedy requirement for excessive length of proceedings, and nearly everything that followed cites it. Broniowski was the first pilot judgment. McCann, from 1995, is still where Article 2 and lethal force begins. Age helps, though it settles less than you would expect: Radomilja is from 2018 and already has thirty-two citations, because it settled what “scope of the case” means.

What the Grand Chamber is made of

The composition looks very different from the Court's output as a whole, which is the point of having the bench.

Importance. HUDOC rates each judgment from 1 (case-law significance) down to 4. The Grand Chamber splits 387 / 112 / 14 / 11, which puts 74% at Level 1. Across the Court as a whole that ratio runs the other way, because most of what Strasbourg does is apply settled law to new facts. The Grand Chamber is the designed exception.

Separate opinions. 430 of the 524 judgments carry a separate opinion, which is 82%. Disagreement is the normal condition at this bench, and it follows from what gets referred there: the questions that divide.

Figure 2: Share of Grand Chamber judgments carrying a separate opinion, by Convention article.

Article 14, discrimination, draws separate opinions in 90% of the Grand Chamber cases where it is in issue, which is the highest of any article, and Article 6, fair trial, draws them in 79%, the lowest. Discrimination turns on contested judgments about comparators and justification, while fair-trial questions at this level are more often technical. The bench agrees about procedure more readily than it agrees about equality.

Temporal distribution

Grand Chamber judgments run from 1994 to 2026, and the curve differs from the Court's overall docket. There is a spike in 1999, with 63 judgments, when Protocol 11 stood up the permanent Court and a backlog of Commission cases came through. After that the count settles into a fluctuating band of roughly ten to thirty a year, thinning to single figures since 2024. Referral is rare by design, and the bench has not grown with the caseload.

Figure 3: Grand Chamber judgments per year, 1994–2026. The 2026 bar is a partial year.

Respondent states

The United Kingdom leads with 68 Grand Chamber judgments, followed by Türkiye (58), Italy (49), and France (46). That ordering differs from the Court's overall docket, where Türkiye and Russia dominate by sheer volume. Referral to the Grand Chamber tracks legal novelty rather than case count, so a state can generate thousands of repetitive applications and very few referrals.

StateGC judgmentsShare
United Kingdom6813.0%
Türkiye5811.1%
Italy499.4%
France468.8%
Russia244.6%
Germany244.6%
Switzerland193.6%
Romania183.4%

Articles. Article 41, just satisfaction, appears in 307 judgments, for the mechanical reason that it is engaged whenever a violation is found. Among the substantive provisions Article 6 leads with 205, followed by Article 35 (admissibility) with 186, Article 8 with 123, Article 14 with 87, and Article 10 with 83.

IV. All the interesting things you can do with this

Temporal trajectories of doctrine. Does Article 6 jurisprudence follow a straight line, or does it reverse direction? When does a case move from obscure to central? Track a single decision's in-degree year by year and you get a curve rather than a single number.

Citation sentiment. A citation can build on a case, distinguish it into irrelevance, or overrule it outright, and the bare edge does not tell you which. Parse the surrounding sentence and the network acquires a sign.

Judge influence. Which judges write the decisions that later get cited? Do particular drafting styles or reasoning structures propagate through the network?

Network evolution. Does the graph get denser over time, or does it thin out? Are there structural breaks, moments where the citation pattern reorganises around a new anchor?

Article co-occurrence. Which articles are pleaded together, and does Article 6 always travel with Article 13? The unexpected pairings show where the interesting tensions are.

Dissent as a leading indicator. Do dissents in hub cases become majority doctrine later? If they do, dissent patterns forecast where the law is about to move.

State-level networks. Build a separate graph per respondent. Do Turkish and German cases cite different precedents for the same article?

The toolkit supplies the pipeline and HUDOC supplies the documents. The questions are yours.

Coda

Everything above came out of the package in a handful of commands: a search against HUDOC, a citation resolution against the Court's own reference concordance, and a graph export to NetworkX. The pipeline covers the parts that are tedious and easy to get wrong, including pinning the language so that nothing is counted twice, resolving a printed citation to an exact document with a paragraph pinpoint where the text supplies one, and keeping provenance attached to every row.

The resolution step is where a citation graph is usually won or lost, because a resolver that quietly guesses will produce a network that looks reasonable and measures very little. echr-py keeps the two halves apart: parse_scl_mentions records what the judgment actually printed, and resolve_citations matches those mentions against the Court's authority table and reports what it could not place. In this corpus it declined to resolve 10,602 of 15,020 references, nearly all of them pointing at judgments outside the Grand Chamber, and it says so rather than inventing an edge. The package is on PyPI and the source is on GitHub.