About CrossLab
CrossLab takes a cyclocross race from your head unit, lines every lap up against a clean median lap, and tells you where the time went — which barriers, which run-up, which sand pit, and whether the problem is that you are slow there every lap or that you are slow there sometimes.
It runs entirely in your browser. There is no CrossLab server, no account, and no upload. Races you load are stored in this browser's IndexedDB and go nowhere else. It is the cyclocross sibling of CritLab, and the two share their settings and intervals.icu key.
Why a file can't do this on its own
A criterium is an aerodynamics problem, and CritLab can model it: speed, gradient and wind give the power it should have taken, and your meter says what it did take. A cross race is not like that. The time goes in places the file does not know about — a set of planks, a flight of stairs, a greasy off-camber — and the signals it does have (speed drops, cadence reads zero, power reads zero) look the same whether you were hopping barriers or waiting behind a crash.
So CrossLab asks you to do the one thing it cannot: say where the features are. Click twice on the course map, once where a feature starts and once where you are back up to speed after it. That is the whole input. Everything else is worked out from the repetition.
What it actually computes
Laps
Laps are found the way CritLab finds them: repeated passes of a start anchor, gated on heading, with the anchor searched forward from where the recording began so lap 1 is the lap that started at the line. Head-unit lap presses are used instead when they look like a circuit, with the extra check that every lap starts in the same place, since an auto-lap every 5 km produces evenly sized laps that are not laps at all.
The mean lap, and lining the laps up against it
Every lap is stacked onto a 2 m grid and the median position taken at each point, which cuts GPS noise by roughly √n and shrugs off the one lap you took through the pit. That gives one clean copy of the course.
Then each lap is snapped to it by geography, not by fraction of lap distance. The distinction matters: a 2% difference in measured lap distance, which a wide line produces routinely, moves a point 60 m, and a set of barriers is 8 m long. Each sample is matched to the nearest course point within a window around where it should be, moving forward only, with a penalty for pointing the wrong way so a parallel lane four metres away cannot steal it. The result is, for every lap, the moment you passed every metre of the course. Every number on the site is a difference of two of those moments, which is why sector times always sum to the lap time exactly.
Features
A feature is a start point and an end point on the course, stored as latitude and longitude so it survives moving the start line and transfers to another race on the same course. For each lap it gets:
- Time through the zone, and the best, median and worst across laps.
- Left on the table — the sum over laps of how much slower each pass was than your best pass. Time you have already shown you can save.
- Cost per pass — how much longer a typical pass took than simply riding the same metres at your approach speed. The price of the feature itself, which only technique can cut.
- Approach and exit speed (three seconds either side), the slowest point, and how long it took to get back to approach speed. Braking early and slow remounts are the two classic leaks, and they look different.
- On foot and stopped seconds, from speed thresholds you can set in the rail.
- A verdict: steady, a few bad laps (named), or erratic. Steady-but-slow is a technique to learn; erratic is a technique that has not settled; one bad lap is an incident.
Unplanned stops
Anywhere you came nearly to a halt with no feature marked. Each is costed against the speed you were carrying into it, and drawn on the course map. If one of them is a feature you have not placed yet, place it and it moves from the bobble list to the feature list.
Suggestions
Places where your median speed over all laps dropped to running pace for several metres, and no feature covers them, are marked with a ? and offered as features. Gradient decides whether it is called a run-up. They are offered, never applied: you know whether that was a set of barriers or a corner everybody walked because it was a bog.
The delta trace
Seconds behind your best lap, plotted along the lap, one line per lap. Where a line steps up is exactly where that lap lost time. A gentle slope is being a little slower everywhere; a vertical jump is a feature or a bobble. This is the one chart to look at if you only look at one.
Fade
The second half of the race against the first, split into time inside the features and time riding between them. "You faded 20 s a lap, and 88% of that was the riding" and "you faded 20 s a lap, and 70% of that was the features" call for different training.
Race trimming
A cross file is rarely just the race: it is the pre-ride, ten minutes on the grid, the race, and a cool-down lap. Pre-ride laps pass every geometric test for "a lap" and then sit at the top of every worst-lap list. CrossLab finds the longest run of laps at race pace with no long stop inside them, treats a long stand at the start of a lap as the grid, and offers to trim to that.
Heart rate
Most people racing cross have a strap and no power meter, so the heart is the effort signal CrossLab leans on. It is read through a mask first: a strap that has not wetted reads low and flat, and a racer's heart does not sit at 60% of its maximum for a minute at race pace, so stretches like that are thrown out and named, rather than averaged into every number on the page. A lap counts for heart-rate purposes only if most of it was read.
- Along the lap — one line per lap against distance into the lap, not shifted for the heart's lag, so the peaks sit on the course where they happen: after the run-up, in the sector you have to ride it off.
- Per feature — heart rate just before the entry, the peak between the entry and 40 s after the exit (the heart trails the legs by 15 to 30 s, so the peak for an 8 m set of barriers lands well after them), the rise, and how long it took to settle back. A rise that never settles is the bill for running, paid on the bike afterwards.
- Metres per heartbeat — lap speed over lap heart rate. On the same course, more metres per beat is fitter; across the race, fewer in the second half than the first is decoupling, and the fade finding says whether the heart was still pinned when the speed fell (fitness) or came down with it (legs, grip, or the head).
- On foot against riding, with the lag applied so the beats are charged to the legs that caused them; the start, as seconds to 95% of max from the line; and the drop in the minute after the finish, when the recording ran that long.
Threshold and maximum come from the activity when intervals.icu supplies them, from the rail when you set them, and otherwise the maximum is the highest reading in the race and the threshold stays unknown — a percentage of max is honest, an invented threshold is not. Zones are shown only with the activity's own boundaries.
Power
Not required. If a power meter was on the bike you get lap power, normalised power, work, W′ balance (Skiba's differential model, with CP and W′ from the activity or from the shared rider settings), and the split between power while riding and power inside features — the latter is low by construction, since the meter reads zero while you carry the bike.
Weather
From Open-Meteo, for the race's rounded coordinates and date: temperature, wind, rain during the race, and rain in the 24 hours before the start, which is what decided whether the course was a bog. It is context, not a model input.
What it shares with CritLab
Both tools live on the same site, so the browser storage is one bag for both. The settings blob, the intervals.icu key, your mass, FTP, CP and W′, and the weather and map caches are the same entries with the same names; threshold and max heart rate are CrossLab's own keys in the same blob. Paste the key once and both tools see it. Races are kept in a database of CrossLab's own, with the same layout, so a race exported as JSON from either tool loads in the other; CritLab will simply not know what to do with a feature list, and CrossLab will not try to model drafting.
Privacy
CrossLab is a static page. No server, no backend, no database, no account, no analytics. Your intervals.icu key is sent only to intervals.icu, directly from your browser, and kept in its own storage entry with a lifetime you choose. Open-Meteo is sent the rounded coordinates and date of a race; Overpass is sent the bounding box of the course. Neither is told who you are, because CrossLab does not know.
License
MIT. Source on GitHub.