compere
Open source (MIT) · Python + FastAPI

Better rankings from fewer votes

compere is a Python library and FastAPI service for pairwise-comparison ranking. A multi-armed bandit picks which pair to compare next; Elo turns the verdicts into a leaderboard you can actually read.

$ pip install compere
GET /ratings
# entity elo n
1variant-b164231
2variant-d157828
3variant-a150326
4variant-c144124
5variant-e133623

5 entities ranked from 132 pairwise votes · UCB-selected

What is compere?

compere is a pairwise-comparison ranking engine written in Python. You show people (or a model) two things and ask “which is better?”. compere decides which pair to ask about next with a UCB1 multi-armed bandit, then converts the verdicts into Elo ratings — a single, sortable leaderboard. Run it as a FastAPI service or import it as a library.

1

Register entities

Add the things you want to rank — model outputs, headlines, designs, catalog items. Anything you can express as an entity with an id.

2

Vote on the pairs it picks

Ask /mab/next_comparison for the next matchup. UCB1 targets uncertain pairs so you spend votes where they change the ranking.

3

Read the leaderboard

Every verdict updates Elo ratings (K = 32, initial 1500). GET /ratings returns entities ordered by rating — a plain function of the votes.

compere uses exactly two algorithms: UCB1 and Elo. It does not implement Bradley-Terry, Thurstone Case V, TrueSkill, Glicko, or any neural ranker — both algorithms were chosen because they are interpretable end to end.

The problems compere solves

Ranking from human judgement is deceptively hard. compere targets the four places it usually goes wrong.

📊

Rating scales are noisy

The problem

Ask people to score items 1–5 and you get anchoring, drift, and different internal scales per rater. The numbers look precise but rank things badly.

How compere helps

Pairwise “A or B?” is a far easier judgement. compere aggregates those binary verdicts into a single Elo ranking that reflects real preference, not scale bias.

Why 50 votes beat 500 ratings →
🔢

Exhaustive comparison is quadratic

The problem

Comparing every pair is n(n-1)/2 judgements. For 50 items that is 1,225 comparisons — most of them between an obvious winner and an obvious loser.

How compere helps

The UCB1 bandit spends votes on the pairs whose outcome is genuinely uncertain and skips the settled ones, so you converge on a good ranking sub-quadratically.

How UCB pair selection works →
🎯

Elo alone leaves out the hard part

The problem

A 30-line Elo gist gives you the rating update. It says nothing about which pair to ask about next — the actual bottleneck in a comparison study.

How compere helps

compere pairs UCB selection with Elo rating in one package, plus persistence, an HTTP API, and a leaderboard. Selection and rating ship together.

compere vs plain Elo libraries →
🛑

You can’t tell when to stop

The problem

Collect too few votes and the ranking is unstable; too many and you burn annotator time. Most tools give you no signal either way.

How compere helps

Because ratings are a transparent function of votes, you can watch the leaderboard stabilise and apply an explicit stopping rule instead of guessing.

Stopping rules explained →

Install, run, vote

Same engine, two entry points. Run the FastAPI service for a frontend to hit, or import the modules directly for offline studies and notebooks.

As a service — HTTP + /docs
# 1. run the service (SQLite by default)
compere --port 8090

# 2. register the things you want to rank
curl -X POST localhost:8090/entities/ \
  -H "Content-Type: application/json" \
  -d '{"name": "headline-a"}'

# 3. ask UCB which pair to compare next
curl localhost:8090/mab/next_comparison
{"entity1_id": 3, "entity2_id": 7}

# 4. record the verdict
curl -X POST localhost:8090/comparisons/ \
  -d '{"entity1_id":3,"entity2_id":7,"selected_entity_id":3}'

# 5. read the leaderboard
curl localhost:8090/ratings
As a library — no server
# no server needed — use it as a library
from compere.modules import entity, comparison, rating

a = entity.create_entity(name="design-a")
b = entity.create_entity(name="design-b")

# record a pairwise verdict
comparison.create_comparison(
    entity1_id=a.id,
    entity2_id=b.id,
    selected_entity_id=a.id,
)

# Elo ratings, sorted high to low
for r in rating.get_ratings():
    print(r.name, r.rating)
# design-a 1516.0
# design-b 1484.0

Interactive OpenAPI docs are served at /docs. The full HTTP surface is eleven endpoints.

Everything a comparison study needs

Selection, rating, storage, and an HTTP surface — as one cohesive package, not a pile of scripts.

Fits your stack

One engine, several ways in. Ship a service, embed a library, or spin up a container.

FastAPI service
11 REST endpoints
run compere
Python library
compere.modules.*
import & call
OpenAPI /docs
interactive Swagger UI
auto-served
SQLite
default store
zero setup
PostgreSQL
via DATABASE_URL
when you scale
Docker
Dockerfile + compose
in the repo
Vue demo UI
compere-ui/
optional
PyPI
pip install compere
or uv add
2
algorithms
UCB1 + Elo, nothing more
11
REST endpoints
entities, comparisons, ratings, health
2
databases
SQLite default, PostgreSQL supported
MIT
license
open source, self-host anywhere

Start ranking with fewer votes

compere is open source (MIT). Install it, register your entities, and let UCB decide what to ask next.

Have a ranking problem in mind?

Tell us what you're comparing and how many votes you can realistically collect.

Get in touch