Problem & solution

Start List Matching in Cycling Photos — Bibs to Riders

Detection and identification are two different problems, and cycling makes the gap obvious. Reading "47" off the back of a jersey is the first half; deciding that 47 is a specific rider on a specific team — and noticing when 47 isn't in the race at all — is the half that determines whether your gallery is searchable or subtly wrong. This guide covers what the start list actually does in a cycling workflow, what happens when the number is unreadable but the kit isn't, and the failure modes we can't design away.

A wrong match is worse than a missing one. An unmatched photo is simply absent from a rider's gallery; a mismatched photo is filed under someone else's name, which is what generates the complaint, the refund, and the lost client. For sportive and gran fondo photographers selling to participants, roster accuracy is the difference between a searchable archive and one nobody trusts.

Understanding the problem

Start list integration is the step that converts a detected number into a named rider. You upload the event's participant list, and each number read from a photo is checked against it in turn — so the roster acts as both a lookup table and a validity check. In cycling this matters more than in most sports, because the number is frequently read at distance, at an angle, or from a partly obscured back bib, and a single misread digit produces a plausible-looking number that may well belong to someone else in the same race.

Cycling galleries are searched by number or by name, and the buyer is often the rider. That means the match is the product. It also means errors are visible to exactly the person most likely to notice: a rider who finds a photo of someone else under their own number. Matching against a real roster is what lets us treat a read as a claim to be verified rather than a fact to be written.

In this sport specifically

Cycling gives the matcher an unusually rich second channel: team kit. In a professional or club field, jersey design, team name, and sponsor text are visible even when the back bib is hidden behind a saddle bag or turned away from the camera — so a photo with no readable number is not necessarily a dead end. The flip side is that this channel is noisy. Series-wide sponsors appear on every rider in the race, and a matcher that leans on sponsor text alone can confidently attach the wrong rider. Field size compounds all of it: in a packed sportive, numbers that differ by one digit are common, so a plausible misread often lands on a real, wrong entry.

Where it shows up

Traditional approaches, and why they fall short

Manual lookup — reading the number off the photo, then finding it in a printed list or spreadsheet

Two context switches per photo: read the frame, search the sheet, type the name. It stays workable for a hand-picked selection and collapses across a full event folder. · Accurate while attention holds, then drifts. Transcription slips and off-by-one row errors are the usual failure, and they are invisible once the file is written.

The lookup cost is paid per photo, so it scales linearly with the shoot. It is also the step most often skipped under deadline, which is precisely when errors are most likely.

Basic OCR over the image, with the output pasted against the roster afterwards

Quick to run, but the verification pass is manual, because wrong reads have to be spotted rather than reported. · Workable on a flat, well-lit, front-facing number; unreliable on a curved jersey at distance, which describes most cycling frames.

Plain OCR transcribes any text it finds — sponsor names, bike brands, road signage — with no notion of which string is a bib number. It returns confident answers without distinguishing a valid entry from a hallucinated one, so the roster check has to happen entirely by hand afterwards.

Position and timing correlation — inferring identity from where a rider was on the road and when

Requires timing data from the organizer plus careful clock synchronization between your camera and their system. · Reasonable when riders pass a timing point strung out; ambiguous in a group, where many riders share a crossing window.

Only works near timing points, and a peloton crossing together leaves a long candidate list for every frame. Most of the best cycling photography happens away from the mats.

How RaceTagger handles it

You import the event's start list once as a CSV, and set the sport to cycling. A vision model reads what is visible in each photo — bib numbers on the back or hip, frame numbers, team name, and sponsor text — and each read is scored against the roster rather than trusted outright. The number carries the most weight; team and sponsor act as corroboration, and a candidate supported by more than one kind of evidence scores higher than one resting on a single read. When a detected number doesn't correspond to any entry in your list, that absence is treated as a signal: rather than accepting a number that isn't in the race, the matcher tests whether a near-miss reading would land on a rider who actually started.

Key advantage

The start list turns matching into a checked operation instead of an open-ended guess. A read that corresponds to no registered rider is treated as suspect, and a frame with no readable number can still be narrowed using team and sponsor evidence — which in cycling is often visible when the bib is not. Where the evidence is strong but not conclusive, the photo is set aside with its closest candidates attached, so a human decides rather than the tool guessing.

Good conditions
A clean back bib, shot square, on a rider whose number is in the start list — reads and matches cleanly, with team kit agreeing as a second signal
Challenging
Numbers at distance in a pack, partly hidden bibs, or a rider identified mainly by kit — often still matchable, but more of these frames land in the review queue with candidates attached rather than being resolved outright
Worst case
A misread that happens to correspond to another rider genuinely entered in the race. The roster check cannot catch this one, because the result is a valid entry — it is the failure mode we are most explicit about, and the reason we treat a review pass as part of the workflow rather than an optional extra

Import the start list once per event, from the Participants screen, where it becomes a preset for that event. The number column is the only hard requirement, and that importer answers to the header names your file is likely to already have — Number, Bib, race_number, numero — with rider name, team, and category picked up under their usual headers and carried through. You don't add a column for the tag text; it's composed from the fields you supplied. Check the rows rather than the headers before importing: a row with a different field count than the header line gets skipped, which is what an unquoted comma inside a team name will do to it. RaceTagger then processes the folder in batch, reading JPEG and RAW files via the embedded preview, and separates confident matches from frames that need a decision. Matches are written as EXIF/XMP/IPTC metadata — embedded in the file for JPEGs, but written to an XMP sidecar alongside RAW files rather than into the RAW itself, so forward a .NEF or .CR3 on its own and the names stay behind. Where the metadata does travel with the file, it lands in Photo Mechanic, Lightroom, or whichever gallery platform indexes standard fields. Frames carrying a review marker are written too — the marker is there so you can find them, not to hold the file back — which is why the review pass belongs before delivery, not after.

Manual vs OCR vs AI vision

MetricManualBasic OCRRaceTagger
How a read becomes a named riderYou look the number up in a spreadsheet and type the nameText is extracted, then reconciled against the roster by hand afterwardsEach read is scored against the imported start list as part of the same pass
A number that isn't in the start listYou notice it's missing, and stop to work out whyWritten out as-is; nothing checks it against the fieldTreated as suspect — a near-miss reading is tested against riders who actually started
Bib hidden, team kit visibleYou recognize the kit and narrow it down yourselfNo number, no outputTeam and sponsor evidence can still narrow the candidates
Ambiguous or contested readsResolved on the spot, or guessed under deadlineReturned with the same confidence as a clean readHeld back with the closest candidates attached, for a person to decide
Cost modelYour hours, or a paid tagging assistantCompute is cheap; the manual reconciliation after it is notCredits — 1 credit per photo analyzed

Practical tips

  1. 1

    Ask the organizer for the start list on race morning, not the entry export from the week before

    Late entries, transfers, and withdrawals all move numbers. A number read perfectly from a photo still can't be matched if it isn't in your file, and stale entries leave empty numbers for a misread to land on. The freshest export the organizer can give you does more for match quality than anything else you control.

  2. 2

    Include a team column in your CSV even when you only care about numbers

    Team is the evidence that survives when the bib doesn't. With a team column present, a rider photographed from the front or with a saddle bag across the number can still be narrowed, and a number read correctly gets a second signal agreeing with it. Without the column, that channel simply isn't available to the match.

  3. 3

    Shoot where the field is strung out rather than where it is densest

    Climbs, exits from technical corners, and the closing kilometers of a sportive separate riders. Separation does two things at once: it makes each bib physically readable, and it removes the near-identical neighbors that make a misread plausible. A pack shot is the hardest frame to match and often the least saleable per rider.

  4. 4

    Treat the review queue as the place where a wrong match gets caught, and clear it before delivery

    Frames with candidates attached are the ones the matcher deliberately declined to resolve. That queue is short by design and concentrated on exactly the ambiguous cases, so working it is a focused pass rather than a re-check of the whole shoot. Skipping it doesn't remove the uncertainty — it just ships it.

  5. 5

    Spot-check a handful of matched photos against riders you can identify yourself before publishing the gallery

    The failure mode a roster can't catch is a misread that lands on a real entry, and it will look completely normal in the output. A short sample check — a few riders you recognize, or numbers you noted on the day — is the cheapest way to detect a systematic problem, such as one digit being consistently misread across a whole session.

The takeaway

In cycling, the start list is not a convenience feature — it is what separates a detected number from an identified rider, and what lets a read that corresponds to nobody in the race be treated as suspect rather than written into your files. It is not a guarantee: a misread that lands on another genuine entry will pass the check, which is exactly why the review queue and a quick spot-check belong in the workflow before the gallery goes live.

Match your next cycling gallery against the real start list

You get free credits when you sign up — 1 credit per photo after that. Import a start list, run a folder from your last race, and see which frames match cleanly and which ones we hand back to you.

Try it free →

Questions photographers ask

What format does the cycling start list need to be in?

A plain CSV, and the only column it truly requires is the rider's number. Import it from the Participants screen, where the start list becomes a preset for the event: that importer recognizes the names the number column usually already has — Number, Bib, race_number, bib_number, numero — ignoring case and treating a space like an underscore, so most organizer exports go in as they stand. Rider name, team, and category are picked up the same way, under headers like Driver, Name, Team, Category, or Class, and carry through into the photo metadata. There is no separate column to write for the tag text: when you don't supply one, it's assembled from the name, category, and team you did. The one thing worth a glance before importing is row shape rather than headers — a row that carries a different number of fields than the header row, which is what an unquoted comma inside a team name produces, is skipped without complaint. If nothing at all maps to a number, the import stops and tells you which headers it found. (There is a second, older CSV slot on the analysis screen, and it behaves differently: that one does insist on columns named numero and metatag. For a start list, use the Participants import.)

What happens when a rider's number isn't in the start list?

There is nobody to match it to, so no name is attached and there are no candidates to review — that outcome is recorded distinctly from an ambiguous read. It usually means the roster is out of date rather than that the read was wrong, which is why a race-morning export matters more than it sounds.

Can a photo be matched when the bib number can't be read at all?

Sometimes. Team and sponsor text are treated as real evidence in cycling, so a rider photographed with the number hidden can still be narrowed — and if the evidence is strong enough, matched. It works best when your CSV includes a team column and the field contains several distinguishable teams; in a single-club event, kit stops discriminating between riders.

Can it tag a wrong rider, and how would I know?

Yes, in one specific way: if a digit is misread and the resulting number belongs to another rider who genuinely entered, the result is a valid roster entry and the check passes. We'd rather state that plainly than promise it can't happen. The practical defense is the review queue plus a short spot-check of recognizable riders before you publish.

Does the sponsor text on every jersey confuse the matching?

It can, and that's a known weakness of leaning on kit. Text shared by the whole field — a series title sponsor, an event partner — carries no discriminating power even though it looks like evidence. Team-specific identifiers are the useful signal; race-wide branding is the noise.

Do I need a separate list for each stage or each event?

One list per event is the normal case, imported once and used across the whole folder. In series where numbers stay with the rider from stage to stage, a single list can carry the whole event — but check with the organizer rather than assuming, because some series reissue numbers between stages, and a roster that has quietly gone stale is the failure mode worth avoiding.

Keep reading

← All guides