Feed CatalogAnalytics

Analytics

analytics

16 independently-subscribable analytics.* feeds — the real-time outputs of 14 production ML models and the algorithmic layer on top of them. Each feed answers one question and is delivered as its own stream, so you subscribe to exactly what your product needs. For how each model is built and calibrated, see the Models reference →

bash
# SSE — stream two analytics feeds together
curl -H "Authorization: Bearer $TOKEN" \
  "https://api.racehooks.io/v1/stream?feeds=analytics.strategy,analytics.race-odds"

# Webhook — register analytics.race-odds for a driver filter
curl -X POST "https://api.racehooks.io/v1/webhooks" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"feedId":"analytics.race-odds","webhookUrl":"https://example.com/hook","filters":{"driverNumbers":["1","4"]}}'
The driverNumbers filter works on analytics.strategy, analytics.race-odds, analytics.gap-projection, analytics.tire-strategy, and analytics.qualifying. For analytics.team-points the payload is small (10 constructors) — no filter needed.
Feed IDTierCadenceDescription
analytics.strategyanalyticsPer lapPer-driver strategy signals: pit stop probability, undercut threat, pace mode, LTOE, clean (fuel-corrected) pace, tire health, DNF risk; plus session-level safety car probability.
analytics.race-oddsanalyticsPer lapCTMC position distribution, podium/points odds, expected points, fastest-lap probability, H2H vs teammate, plus same-team pairs.
analytics.true-paceanalyticsPer lapWho's genuinely fastest: each car's session pace stripped of fuel load, tyre age, and traffic (dirty air), ranked — the public-data proxy for hidden long-run pace.
analytics.gap-projectionanalyticsPer lapProjected gap to the race leader at race end for every driver: five percentile bands (p10–p90) plus P(lapped) from Monte Carlo simulation.
analytics.winning-marginanalyticsPer lapSession-level race outlook: projected winning margin (P1–P2) with percentile bands, the probability the margin lands above 5s / 10s / below 3s, and the safety-car collapse risk that resets the lead.
analytics.race-previewanalyticsTwice per race weekend (post-final-practice, post-qualifying)Pre-race projections in two stages: post-final-practice (long-run pace ranking, circuit strategy priors, weather outlook) and post-qualifying (classification with measured pole margin, pace-vs-grid deltas, derived race distance, pre-race pit-stop-count distributions).
analytics.race-durationanalyticsPer lapProjected total race time with p10/p90 bands, expected winner lap time, red-flag probability, and P(race exceeds the 2-hour FIA limit).
analytics.tire-strategyanalyticsPer pit approachNext-compound probabilities for drivers approaching a pit window (pitStopProbability > 0.25). Sparse — fires only when relevant.
analytics.team-pointsanalyticsPer lapConstructor-level expected points from discrete joint position-distribution convolution, with P(both drivers score) and full points distribution.
analytics.championship-probabilityanalyticsOnce, post-racePost-race championship win probability for every driver (WDC) and constructor (WCC). afterRaceId identifies which race the data reflects.
analytics.qualifyinganalyticsPer lap improvementPer-sector fastest probabilities and per-driver pace deltas during qualifying, with pole-margin probability. Fires after each personal best.
analytics.sector-paceanalyticsOn sector anomalyPer-sector pace deltas with anomaly detection; fires when a sector-pace anomaly is detected.
analytics.battleanalyticsOn battle state changeOn-track battle status between a driver and the car directly ahead (closing, holding, defending).
analytics.pit-windowanalyticsOn window open/urgentPit-window status (OPEN / URGENT) combining pit probability, undercut viability, tyre cliff risk, and gap context.
analytics.track-conditionsanalyticsPer lapTrack evolution and grip-condition analytics derived from field pace trends.
analytics.pit-qualityanalyticsOn pit completionPit-stop execution quality assessment (stationary time vs. expected) after a stop completes.

Subscribe with the feedId via webhook or SSE. Tier shown is the minimum plan required.

analytics.strategyRace Strategy Analyticsanalytics

Per lap · Race, Sprint

Per-driver strategy signals: pit stop probability, undercut threat, pace mode, LTOE, clean (fuel-corrected) pace, tire health, DNF risk; plus session-level safety car probability.

Backed by: pit stop probability, overtake probability, undercut threat, pace normalization (LTOE), safety car probability, pit-stop count, DNF risk, pace mode, EKF tire health, competitor intelligence. How the models work →

FieldTypeDescription
regulationsErastring"2026" or "pre-2026". All 2026 models have era-specific calibration applied.
safetyCarProbabilitynumberP(any SC/VSC deployment next lap). Session-level — same value for all drivers. Gradient-boosted classifier with a self-exciting component over historical incident data.
vscProbabilitynumber|nullP(virtual SC specifically). null when the 3-class SC model is not loaded.
fullScProbabilitynumber|nullP(full safety car). null when the 3-class SC model is not loaded.
competitorIntelligenceobjectField-level pit-window estimates. Omitted for the first few laps before the engine has data.
drivers[].pitStopProbabilitynumber0–1. Gradient-boosted-ensemble probability of a pit stop this lap, over a rolling multi-lap feature window.
drivers[].pitRecommendedbooleantrue when pitStopProbability clears the session's era-adjusted decision threshold.
drivers[].overtakeProbabilitynumber0–1. Gradient-boosted-ensemble probability of a position gain via overtake within 3 laps. Circuit overtake index applied.
drivers[].undercutThreatobjectPresent when the car ahead is within the strategic gap threshold: score, viable, gapToCarAheadSec, estimatedDeltaSec, probability.
drivers[].undercutThreat.callobjectCalibrated undercut-timing call (race only, target tyre age known): recommend ("UNDERCUT_NOW" | "WAIT" | "HOLD"), strikeInLaps, pSuccess, pNow. The recommendation gates on the worst case (target covers next lap); pSuccess/pNow are calibrated against realized outcomes with the target's reaction marginalized.
drivers[].paceModestring"PUSH" | "HOLD" | "MANAGE" | "WARM_UP" | "DELTA". Lap-time variance and LTOE-based pace classification.
drivers[].ltoeobjectLap Time Over Expected: ltoeSec (negative = faster than expected), expectedLapTimeSec, actualLapTimeSec, confidenceScale (1.0 once 3+ races of the season's data exist).
drivers[].tireHealthobjecttireHealth (0–1), degRateSecPerLap, stintLap. Derived from a Kalman filter on the lap-delta series.
drivers[].dnfRiskobjectdnfRiskScore (0–1 retirement hazard), constructorHazardRate, lapsTo50PctSurvival.
drivers[].pitStopCountobjectRace-level stop-count distribution: pOneStop, pTwoStop, pThreePlusStop (sum to 1.0) and expectedStops. Multiclass gradient-boosted model over circuit, grid, weather, and starting compound.
Sample payload
json
{
  "feed": "analytics.strategy",
  "sessionId": "9560",
  "raceId": "2026-monaco-r1",
  "lap": 35,
  "utc": "2026-06-08T14:32:18.441Z",
  "regulationsEra": "2026",
  "safetyCarProbability": 0.08,
  "vscProbability": 0.04,
  "fullScProbability": 0.04,
  "drivers": [
    {
      "driverId": "norris-lando",
      "constructorId": "mclaren",
      "number": "4",
      "tla": "NOR",
      "name": "Lando Norris",
      "team": "McLaren F1 Team",
      "pitStopProbability": 0.79,
      "pitRecommended": true,
      "overtakeProbability": 0.12,
      "paceMode": "PUSH",
      "ltoe": {
        "ltoeSec": -0.182,
        "expectedLapTimeSec": 87.594,
        "actualLapTimeSec": 87.412,
        "confidenceScale": 0.75,
        "expectedLapTimeP10Sec": 87.262,
        "expectedLapTimeP90Sec": 88.041,
        "paceUncertaintySec": 0.779
      },
      "tyreCliff": {
        "cliffProbability": 0.63,
        "cliffWithinLaps": 5,
        "cliffDetected": true,
        "lapsToCliff": 3.2
      },
      "ltoeConfidenceFlag": "2026_early",
      "tireHealth": {
        "tireHealth": 0.58,
        "degRateSecPerLap": 0.041,
        "stintLap": 14
      },
      "dnfRisk": {
        "dnfRiskScore": 0.012,
        "lapsTo50PctSurvival": null,
        "constructorHazardRate": 0.018
      }
    },
    {
      "driverId": "verstappen-max",
      "constructorId": "red-bull-racing",
      "number": "1",
      "tla": "VER",
      "name": "Max Verstappen",
      "team": "Red Bull Racing",
      "pitStopProbability": 0.06,
      "pitRecommended": false,
      "overtakeProbability": 0.34,
      "undercutThreat": {
        "score": 0.71,
        "viable": true,
        "gapToCarAheadSec": 4.218,
        "estimatedDeltaSec": 1.8,
        "probability": 0.62,
        "call": {
          "recommend": "WAIT",
          "strikeInLaps": 3,
          "pSuccess": 0.58,
          "pNow": 0.54
        }
      },
      "pitEquilibrium": {
        "action": "MEDIUM",
        "rivalResponse": "HARD",
        "equilibriumGapSec": 1.9,
        "rivalPosition": 5,
        "why": {
          "label": "PIT WINDOW OPTIMAL",
          "detail": "pitting for medium now is the equilibrium call; the car behind's best response is to cover (hard); projected duel gap at the flag +1.9s",
          "tone": "info"
        }
      },
      "paceMode": "HOLD",
      "ltoe": {
        "ltoeSec": 0.048,
        "expectedLapTimeSec": 88.055,
        "actualLapTimeSec": 88.103,
        "confidenceScale": 0.75
      },
      "ltoeConfidenceFlag": "2026_early",
      "tireHealth": {
        "tireHealth": 0.91,
        "degRateSecPerLap": 0.018,
        "stintLap": 8
      },
      "dnfRisk": {
        "dnfRiskScore": 0.009,
        "lapsTo50PctSurvival": null,
        "constructorHazardRate": 0.021
      }
    }
  ]
}

analytics.race-oddsRace Outcome Probabilitiesanalytics

Per lap · Race, Sprint

CTMC position distribution, podium/points odds, expected points, fastest-lap probability, H2H vs teammate, plus same-team pairs.

Backed by: CTMC win probability, fastest lap probability. How the models work →

FieldTypeDescription
drivers[].positionDistributionnumber[20]20-element CTMC probability vector. Index 0 = P(finish 1st). Sums to ≤1.0 (lower for retired drivers).
drivers[].mostLikelyPositionnumber1-based index of the highest-probability position slot.
drivers[].podiumProbabilitynumberP(finish P1–P3). Sum of positionDistribution[0..2].
drivers[].top10ProbabilitynumberSum of positionDistribution[0..9]. Equivalent to P(score points).
drivers[].expectedPointsnumberExpected F1 points from the distribution × points structure, plus fastest-lap bonus weighted by fastestLapProbability.
drivers[].lapsLedExpectednumberExpected race laps led from the current position. CTMC forward integration.
drivers[].fastestLapProbabilitynumberL1-normalised P(set the session fastest lap). Field sums to 1.0.
drivers[].positionChangeobjectCTMC forward projection at next3Laps/next5Laps/next10Laps: gainAtLeast1, loseAtLeast1, holdPosition.
drivers[].h2hVsTeammatenumber|nullP(this driver finishes ahead of team-mate). null when team-mate has no distribution.
drivers[].gridPositionnumberStarting grid slot. Present once real qualifying data is loaded — never a fallback value.
drivers[].expectedPlaceDifferentialnumberExpected places gained vs. grid (positive = gaining): grid − E[finish] from the position distribution. The fantasy place-differential projection.
pairs[]object[]Same-team H2H pairs: constructorId, driverA/B, pABeatsB, pBBeatsA, pTie.
Sample payload
json
{
  "feed": "analytics.race-odds",
  "sessionId": "9560",
  "raceId": "2026-monaco-r1",
  "lap": 35,
  "utc": "2026-06-08T14:32:18.441Z",
  "drivers": [
    {
      "driverId": "norris-lando",
      "constructorId": "mclaren",
      "number": "4",
      "tla": "NOR",
      "name": "Lando Norris",
      "team": "McLaren F1 Team",
      "position": 1,
      "positionDistribution": [
        0.47,
        0.25,
        0.16,
        0.07,
        0.03,
        0.01,
        0.01,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0
      ],
      "mostLikelyPosition": 1,
      "podiumProbability": 0.88,
      "top6Probability": 0.97,
      "top10Probability": 0.99,
      "expectedPoints": 18.9,
      "pointsFinishProbability": 0.99,
      "lapsLedExpected": 24.1,
      "fastestLapProbability": 0.28,
      "positionChange": {
        "next3Laps": {
          "gainAtLeast1": 0.03,
          "loseAtLeast1": 0.08,
          "holdPosition": 0.89
        },
        "next5Laps": {
          "gainAtLeast1": 0.05,
          "loseAtLeast1": 0.13,
          "holdPosition": 0.82
        },
        "next10Laps": {
          "gainAtLeast1": 0.08,
          "loseAtLeast1": 0.21,
          "holdPosition": 0.71
        }
      },
      "h2hVsTeammate": 0.61
    },
    {
      "driverId": "verstappen-max",
      "constructorId": "red-bull-racing",
      "number": "1",
      "tla": "VER",
      "name": "Max Verstappen",
      "team": "Red Bull Racing",
      "position": 2,
      "positionDistribution": [
        0.38,
        0.28,
        0.19,
        0.09,
        0.04,
        0.01,
        0.01,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        0
      ],
      "mostLikelyPosition": 1,
      "podiumProbability": 0.85,
      "top6Probability": 0.96,
      "top10Probability": 0.99,
      "expectedPoints": 17.1,
      "pointsFinishProbability": 0.99,
      "lapsLedExpected": 18.4,
      "fastestLapProbability": 0.41,
      "positionChange": {
        "next3Laps": {
          "gainAtLeast1": 0.11,
          "loseAtLeast1": 0.06,
          "holdPosition": 0.83
        },
        "next5Laps": {
          "gainAtLeast1": 0.17,
          "loseAtLeast1": 0.1,
          "holdPosition": 0.73
        },
        "next10Laps": {
          "gainAtLeast1": 0.26,
          "loseAtLeast1": 0.16,
          "holdPosition": 0.58
        }
      },
      "h2hVsTeammate": 0.39
    }
  ],
  "pairs": [
    {
      "constructorId": "mclaren",
      "driverA": {
        "driverId": "norris-lando",
        "constructorId": "mclaren",
        "number": "4",
        "tla": "NOR",
        "name": "Lando Norris",
        "team": "McLaren F1 Team"
      },
      "driverB": {
        "driverId": "piastri-oscar",
        "constructorId": "mclaren",
        "number": "81",
        "tla": "PIA",
        "name": "Oscar Piastri",
        "team": "McLaren F1 Team"
      },
      "pABeatsB": 0.61,
      "pBBeatsA": 0.38,
      "pTie": 0.01
    }
  ]
}

analytics.true-paceTrue Pace Rankinganalytics

Per lap · Race, Sprint

Who's genuinely fastest: each car's session pace stripped of fuel load, tyre age, and traffic (dirty air), ranked — the public-data proxy for hidden long-run pace.

Backed by: True-pace deconvolution. How the models work →

FieldTypeDescription
drivers[].truePaceSecnumberDeconvolved lap pace (s): the session's trailing clean-lap mean with fuel load, tyre age and traffic (dirty air) stripped — the car's fresh-tyre clean-air pace.
drivers[].truePaceRelSecnumberTrue pace relative to the FIELD MEDIAN (s/lap); negative = faster than the field. Comparable across sessions. Compute gap-to-fastest from truePaceSec if needed.
drivers[].ranknumber1 = genuinely fastest. Field-relative true pace predicts finish position ~2× better than raw fuel-corrected pace.
Sample payload
json
{
  "feed": "analytics.true-pace",
  "sessionId": "9560",
  "raceId": "2026-monaco-r1",
  "lap": 35,
  "utc": "2026-06-08T14:32:18.441Z",
  "drivers": [
    {
      "driverId": "verstappen-max",
      "constructorId": "red-bull-racing",
      "number": "1",
      "tla": "VER",
      "name": "Max Verstappen",
      "team": "Red Bull Racing",
      "truePaceSec": 87.412,
      "truePaceRelSec": -0.31,
      "rank": 1
    },
    {
      "driverId": "norris-lando",
      "constructorId": "mclaren",
      "number": "4",
      "tla": "NOR",
      "name": "Lando Norris",
      "team": "McLaren F1 Team",
      "truePaceSec": 87.523,
      "truePaceRelSec": -0.199,
      "rank": 2
    },
    {
      "driverId": "leclerc-charles",
      "constructorId": "ferrari",
      "number": "16",
      "tla": "LEC",
      "name": "Charles Leclerc",
      "team": "Scuderia Ferrari",
      "truePaceSec": 87.706,
      "truePaceRelSec": -0.016,
      "rank": 3
    }
  ]
}

analytics.gap-projectionGap to Leader Projectionanalytics

Per lap · Race, Sprint

Projected gap to the race leader at race end for every driver: five percentile bands (p10–p90) plus P(lapped) from Monte Carlo simulation.

Backed by: Monte Carlo gap projection. How the models work →

FieldTypeDescription
drivers[].currentGapToLeaderSecnumberCurrent gap to the race leader (seconds).
drivers[].expectedGapToLeaderSecnumberMonte Carlo mean projected gap at race end.
drivers[].p10GapSecnumber10th-percentile projected gap — optimistic scenario.
drivers[].p50GapSecnumberMedian projected gap.
drivers[].p90GapSecnumber90th-percentile projected gap — pessimistic scenario.
drivers[].probabilityLappednumberP(driver is lapped by race end). Typically < 0.05 for active drivers.
Sample payload
json
{
  "feed": "analytics.gap-projection",
  "sessionId": "9560",
  "raceId": "2026-monaco-r1",
  "lap": 35,
  "utc": "2026-06-08T14:32:18.441Z",
  "drivers": [
    {
      "driverId": "verstappen-max",
      "constructorId": "red-bull-racing",
      "number": "1",
      "tla": "VER",
      "name": "Max Verstappen",
      "team": "Red Bull Racing",
      "currentGapToLeaderSec": 0,
      "expectedGapToLeaderSec": 0,
      "p10GapSec": 0,
      "p25GapSec": 0,
      "p50GapSec": 0,
      "p75GapSec": 0,
      "p90GapSec": 0,
      "probabilityLapped": 0
    },
    {
      "driverId": "norris-lando",
      "constructorId": "mclaren",
      "number": "4",
      "tla": "NOR",
      "name": "Lando Norris",
      "team": "McLaren F1 Team",
      "currentGapToLeaderSec": 3.6,
      "expectedGapToLeaderSec": 5.8,
      "p10GapSec": 2.1,
      "p25GapSec": 3.9,
      "p50GapSec": 5.6,
      "p75GapSec": 7.8,
      "p90GapSec": 10.2,
      "probabilityLapped": 0
    },
    {
      "driverId": "leclerc-charles",
      "constructorId": "ferrari",
      "number": "16",
      "tla": "LEC",
      "name": "Charles Leclerc",
      "team": "Scuderia Ferrari",
      "currentGapToLeaderSec": 12.4,
      "expectedGapToLeaderSec": 18.1,
      "p10GapSec": 12.7,
      "p25GapSec": 15.2,
      "p50GapSec": 17.9,
      "p75GapSec": 21,
      "p90GapSec": 24.6,
      "probabilityLapped": 0.02
    },
    {
      "driverId": "russell-george",
      "constructorId": "mercedes",
      "number": "63",
      "tla": "RUS",
      "name": "George Russell",
      "team": "Mercedes-AMG Petronas F1 Team",
      "currentGapToLeaderSec": 58.3,
      "expectedGapToLeaderSec": 81.5,
      "p10GapSec": 66.4,
      "p25GapSec": 74.1,
      "p50GapSec": 81,
      "p75GapSec": 88.9,
      "p90GapSec": 97.2,
      "probabilityLapped": 0.41
    }
  ]
}

analytics.winning-marginWinning Margin Projectionanalytics

Per lap · Race, Sprint

Session-level race outlook: projected winning margin (P1–P2) with percentile bands, the probability the margin lands above 5s / 10s / below 3s, and the safety-car collapse risk that resets the lead.

Backed by: Monte Carlo winning margin. How the models work →

FieldTypeDescription
leadBattle.leader / leadBattle.runnerUpobjectCurrent P1 and P2 (each a full DriverRef: number, driverId, tla, name, team).
leadBattle.currentMarginSecnumberCurrent P1–P2 gap in seconds.
leadBattle.expectedFinalMarginSecnumberExpected P1–P2 gap at race end. Mixture of the no-SC linear drift and the post-SC reset distribution.
leadBattle.p10MarginSec / p50MarginSec / p90MarginSecnumberPercentile bands from 5,000 Monte Carlo samples.
leadBattle.probabilityMarginAbove5 / Above10numberP(final margin > 5s) / P(> 10s).
leadBattle.probabilityMarginBelow3numberP(final margin < 3s) — close-finish probability.
leadBattle.scCollapseRisknumberP(safety car before race end) — the dominant driver of margin collapse. Gaps reset toward ~1.5s at an SC restart.
Sample payload
json
{
  "feed": "analytics.winning-margin",
  "sessionId": "9560",
  "raceId": "2026-monaco-r1",
  "lap": 40,
  "utc": "2026-06-08T14:32:18.441Z",
  "leadBattle": {
    "leader": {
      "driverId": "verstappen-max",
      "constructorId": "red-bull-racing",
      "number": "1",
      "tla": "VER",
      "name": "Max Verstappen",
      "team": "Red Bull Racing"
    },
    "runnerUp": {
      "driverId": "norris-lando",
      "constructorId": "mclaren",
      "number": "4",
      "tla": "NOR",
      "name": "Lando Norris",
      "team": "McLaren F1 Team"
    },
    "currentMarginSec": 4.8,
    "expectedFinalMarginSec": 7.2,
    "p10MarginSec": 1.9,
    "p50MarginSec": 6.8,
    "p90MarginSec": 13.4,
    "probabilityMarginAbove5": 0.71,
    "probabilityMarginAbove10": 0.28,
    "probabilityMarginBelow3": 0.14,
    "scCollapseRisk": 0.22
  }
}

analytics.race-previewPre-Race Previewanalytics

Twice per race weekend (post-final-practice, post-qualifying) · Practice, Qualifying

Pre-race projections in two stages: post-final-practice (long-run pace ranking, circuit strategy priors, weather outlook) and post-qualifying (classification with measured pole margin, pace-vs-grid deltas, derived race distance, pre-race pit-stop-count distributions).

Backed by: Practice long-run pace summary, Circuit priors, pit-stop count. How the models work →

FieldTypeDescription
stagestring"practice" (final practice ended) or "grid" (qualifying ended).
circuitIdstringCanonical RaceHooks circuit slug (e.g. "monaco").
drivers[]objectEach entry is a full DriverRef (number, driverId, tla, name, team) plus the stage-specific fields below.
drivers[].practicePaceobjectrelPacePct (lower = faster), longRunDone, primaryCompound, lapsCompleted, sessionType, paceRank. Long-run drivers rank ahead of short-run-only drivers — long-run pace is the race-pace signal.
strategy.compoundDeg[]objectPer-compound degradation prior (sec/lap) for this circuit, from the post-weekend prior pipeline.
strategy.pitLaneDeltaSecnumberCircuit pit-lane time loss in seconds.
strategy.scTimeCostSecPerLapnumberTime cost of a safety-car lap at this circuit vs green pace.
strategy.redFlagBaseRatenumberFraction of sessions at this circuit with at least one red flag (2018–2025).
qualifyingobjectGrid stage: session classification (order with segments), pole lap, and the MEASURED pole margin in ms. The official grid may differ after penalties.
drivers[].paceVsGridDeltanumberGrid stage: practice pace rank minus qualifying position — positive = raced faster in practice than qualified (a classic recovery-drive signal).
drivers[].pitStopCountobjectGrid stage: pre-race stop-count distribution (pOneStop/pTwoStop/pThreePlusStop/expectedStops) assuming a medium-compound start; race distance derived from the FIA 305 km rule.
scheduledRaceLapsnumber|nullGrid stage: derived race distance in laps (FIA 305 km rule; Monaco 260 km). null when circuit length is unknown.
Sample payload
json
{
  "feed": "analytics.race-preview",
  "stage": "grid",
  "eventId": "2026-monaco",
  "raceId": "2026-monaco-r1",
  "circuitId": "monaco",
  "utc": "2026-06-08T14:32:18.441Z",
  "scheduledRaceLaps": 78,
  "qualifying": {
    "poleLapMs": 70123,
    "poleMarginMs": 84,
    "order": [
      {
        "driverId": "norris-lando",
        "constructorId": "mclaren",
        "number": "4",
        "tla": "NOR",
        "name": "Lando Norris",
        "team": "McLaren F1 Team",
        "position": 1,
        "lapTimeMs": 70123,
        "segment": "Q3"
      },
      {
        "driverId": "verstappen-max",
        "constructorId": "red-bull-racing",
        "number": "1",
        "tla": "VER",
        "name": "Max Verstappen",
        "team": "Red Bull Racing",
        "position": 2,
        "lapTimeMs": 70207,
        "segment": "Q3"
      },
      {
        "driverId": "leclerc-charles",
        "constructorId": "ferrari",
        "number": "16",
        "tla": "LEC",
        "name": "Charles Leclerc",
        "team": "Scuderia Ferrari",
        "position": 3,
        "lapTimeMs": 70298,
        "segment": "Q3"
      }
    ]
  },
  "drivers": [
    {
      "driverId": "norris-lando",
      "constructorId": "mclaren",
      "number": "4",
      "tla": "NOR",
      "name": "Lando Norris",
      "team": "McLaren F1 Team",
      "qualifyingPosition": 1,
      "practicePaceRank": 1,
      "paceVsGridDelta": 0,
      "pitStopCount": {
        "pOneStop": 0.72,
        "pTwoStop": 0.26,
        "pThreePlusStop": 0.02,
        "expectedStops": 1.3
      }
    },
    {
      "driverId": "verstappen-max",
      "constructorId": "red-bull-racing",
      "number": "1",
      "tla": "VER",
      "name": "Max Verstappen",
      "team": "Red Bull Racing",
      "qualifyingPosition": 2,
      "practicePaceRank": 3,
      "paceVsGridDelta": -1,
      "pitStopCount": {
        "pOneStop": 0.68,
        "pTwoStop": 0.3,
        "pThreePlusStop": 0.02,
        "expectedStops": 1.34
      }
    },
    {
      "driverId": "leclerc-charles",
      "constructorId": "ferrari",
      "number": "16",
      "tla": "LEC",
      "name": "Charles Leclerc",
      "team": "Scuderia Ferrari",
      "qualifyingPosition": 3,
      "practicePaceRank": 2,
      "paceVsGridDelta": 1
    }
  ]
}

analytics.race-durationRace Duration Projectionanalytics

Per lap · Race, Sprint

Projected total race time with p10/p90 bands, expected winner lap time, red-flag probability, and P(race exceeds the 2-hour FIA limit).

Backed by: Race-finish-time formula (LTOE + SC cost + red-flag base rates). How the models work →

FieldTypeDescription
expectedRaceTimeMinutesnumberExpected total race duration in minutes: elapsed + remaining racing time + expected SC and red-flag time loss.
p10RaceTimeMinutes / p90RaceTimeMinutesnumber10th/90th percentile race-duration band.
expectedWinnerLapTimeSecnumberExpected winner average lap time over the remaining laps (degradation-adjusted).
probabilityRedFlagnumberRule-based P(red flag before race end): circuit base rate boosted by wet running, lap-1 chaos, SC history, and retirements.
probabilityOvertimeSessionnumberP(race exceeds the 2-hour FIA time limit).
scDeployedCountnumberSafety-car deployments so far this race.
Sample payload
json
{
  "feed": "analytics.race-duration",
  "sessionId": "9560",
  "raceId": "2026-monaco-r1",
  "lap": 40,
  "utc": "2026-06-08T14:32:18.441Z",
  "expectedRaceTimeMinutes": 98.4,
  "p10RaceTimeMinutes": 95.1,
  "p90RaceTimeMinutes": 104.7,
  "expectedWinnerLapTimeSec": 74.812,
  "probabilityRedFlag": 0.11,
  "probabilityOvertimeSession": 0.03,
  "scDeployedCount": 1
}

analytics.tire-strategyTire Strategy Probabilityanalytics

Per pit approach · Race, Sprint

Next-compound probabilities for drivers approaching a pit window (pitStopProbability > 0.25). Sparse — fires only when relevant.

Backed by: tyre compound. How the models work →

FieldTypeDescription
drivers[].pitProbabilitynumberCurrent pit-stop probability — why the driver is in the sparse set.
drivers[].nextCompoundProbability.softnumberP(next compound = soft).
drivers[].nextCompoundProbability.mediumnumberP(next compound = medium).
drivers[].nextCompoundProbability.hardnumberP(next compound = hard).
drivers[].nextCompoundProbability.wetWeathernumberHigh-recall merged Inter+Wet class. Zeroed on a dry track; elevated when a weather event is approaching.
drivers[].nextCompoundProbability.dryCompoundProbabilitiesobjectDry-only renormalised view { soft, medium, hard } summing to 1 — use on a dry track where wetWeather is 0.
Sample payload
json
{
  "feed": "analytics.tire-strategy",
  "sessionId": "9560",
  "raceId": "2026-monaco-r1",
  "lap": 33,
  "utc": "2026-06-08T14:32:18.441Z",
  "drivers": [
    {
      "driverId": "hamilton-lewis",
      "constructorId": "ferrari",
      "number": "44",
      "tla": "HAM",
      "name": "Lewis Hamilton",
      "team": "Scuderia Ferrari",
      "pitProbability": 0.68,
      "nextCompoundProbability": {
        "soft": 0.72,
        "medium": 0.24,
        "hard": 0.04,
        "wetWeather": 0,
        "dryCompoundProbabilities": {
          "soft": 0.72,
          "medium": 0.24,
          "hard": 0.04
        }
      }
    }
  ]
}

analytics.team-pointsTeam Points Analyticsanalytics

Per lap · Race, Sprint

Constructor-level expected points from discrete joint position-distribution convolution, with P(both drivers score) and full points distribution.

Backed by: CTMC win probability, constructor points convolution. How the models work →

FieldTypeDescription
constructors[].constructorIdstringTeam identifier (e.g. "red-bull", "ferrari", "mclaren").
constructors[].expectedConstructorPointsnumberExpected combined points from both drivers, via discrete convolution of joint position distributions — analytically exact.
constructors[].scoringBothDriversProbabilitynumberP(both drivers finish top 10). Joint probability from the distribution product.
constructors[].podiumBothDriversProbabilitynumberP(both drivers finish on the podium). Same independence product over P1–P3.
constructors[].pointsDistributionnumber[]P(team scores exactly K combined points) for K = 0…44.
Sample payload
json
{
  "feed": "analytics.team-points",
  "sessionId": "9560",
  "raceId": "2026-monaco-r1",
  "lap": 40,
  "utc": "2026-06-08T14:32:18.441Z",
  "constructors": [
    {
      "constructorId": "red-bull",
      "expectedConstructorPoints": 33.1,
      "scoringBothDriversProbability": 0.88,
      "podiumBothDriversProbability": 0.19,
      "pointsDistribution": [
        0,
        0,
        0.01,
        0.02,
        0.04,
        0.07
      ]
    },
    {
      "constructorId": "mclaren",
      "expectedConstructorPoints": 27.6,
      "scoringBothDriversProbability": 0.82,
      "podiumBothDriversProbability": 0.11,
      "pointsDistribution": [
        0,
        0.01,
        0.02,
        0.03,
        0.05,
        0.08
      ]
    }
  ]
}

analytics.championship-probabilityChampionship Win Probabilityanalytics

Once, post-race · Season

Post-race championship win probability for every driver (WDC) and constructor (WCC). afterRaceId identifies which race the data reflects.

Backed by: season simulator (infer_scwp). How the models work →

FieldTypeDescription
seasonYearnumberChampionship season the projection covers.
afterRaceIdstringThe most recent official race the probabilities are computed through.
simulationsRunnumberMonte Carlo iterations behind the projection.
drivers[]objectWDC row — a full DriverRef (number, driverId, tla, name, team) plus the fields below.
drivers[].scwpnumberP(this driver wins the WDC). Field sums to ≤1.0.
drivers[].scwpTop3numberP(this driver finishes top-3 in the championship).
drivers[].expectedFinalPointsnumberExpected end-of-season points total.
drivers[].championshipDeficitnumberPoints behind the current championship leader (0 for the leader).
constructors[].constructorIdstringCanonical team slug (e.g. "mclaren").
constructors[].ccwpnumberP(this team wins the WCC). Field sums to ≤1.0.
constructors[].ccwpTop3numberP(this team finishes top-3 in the constructors' championship).
constructors[].expectedFinalPointsnumberExpected end-of-season combined points.
constructors[].championshipDeficitnumberPoints behind the leading constructor.
Sample payload
json
{
  "feed": "analytics.championship-probability",
  "seasonYear": 2026,
  "afterRaceId": "2026-monaco-r1",
  "simulationsRun": 10000,
  "utc": "2026-06-08T14:32:18.441Z",
  "drivers": [
    {
      "driverId": "norris-lando",
      "constructorId": "mclaren",
      "number": "4",
      "tla": "NOR",
      "name": "Lando Norris",
      "team": "McLaren F1 Team",
      "scwp": 0.41,
      "scwpTop3": 0.93,
      "expectedFinalPoints": 421.5,
      "championshipDeficit": 0
    },
    {
      "driverId": "verstappen-max",
      "constructorId": "red-bull-racing",
      "number": "1",
      "tla": "VER",
      "name": "Max Verstappen",
      "team": "Red Bull Racing",
      "scwp": 0.36,
      "scwpTop3": 0.9,
      "expectedFinalPoints": 409.2,
      "championshipDeficit": 12
    },
    {
      "driverId": "leclerc-charles",
      "constructorId": "ferrari",
      "number": "16",
      "tla": "LEC",
      "name": "Charles Leclerc",
      "team": "Scuderia Ferrari",
      "scwp": 0.14,
      "scwpTop3": 0.71,
      "expectedFinalPoints": 372.8,
      "championshipDeficit": 41
    }
  ],
  "constructors": [
    {
      "constructorId": "mclaren",
      "ccwp": 0.58,
      "ccwpTop3": 0.98,
      "expectedFinalPoints": 742,
      "championshipDeficit": 0
    },
    {
      "constructorId": "red-bull",
      "ccwp": 0.31,
      "ccwpTop3": 0.94,
      "expectedFinalPoints": 705.4,
      "championshipDeficit": 36
    }
  ]
}

analytics.qualifyingQualifying Analyticsanalytics

Per lap improvement · Qualifying

Per-sector fastest probabilities and per-driver pace deltas during qualifying, with pole-margin probability. Fires after each personal best.

Backed by: qualifying pace, calibrated qualifying distribution. How the models work →

FieldTypeDescription
segmentstringActive segment: "Q1", "Q2", or "Q3".
poleLeaderstringDriver number currently projected to take pole (lowest sum of sector deltas).
poleMarginAbove100msnumberP(gap between pole and P2 > 0.1s). From the calibrated margin model.
sectors.s1.drivers[].pFastestnumberP(this driver sets fastest S1). L1-normalised across drivers with pace data.
sectors.s1.drivers[].predictedDeltaMsnumberPredicted S1 delta vs. session median (ms). Negative = faster.
drivers[].sector1DeltaMsnumber|nullPredicted S1 delta vs. session median (ms). null when the qualifying pace model is not loaded.
drivers[].eliminationobjectQ1/Q2 only, once most of the field has predictions: pEliminatedQ1, pEliminatedQ2, pReachesQ3, projectedFinalQualifyingPosition — rank-based order statistics over the predicted field.
Sample payload
json
{
  "feed": "analytics.qualifying",
  "sessionId": "9560",
  "raceId": "2026-monaco-r1-q",
  "utc": "2026-06-08T14:32:18.441Z",
  "segment": "Q3",
  "circuitId": "monaco",
  "poleMarginAbove100ms": 0.71,
  "poleMarginAbove300ms": 0.31,
  "poleLeader": {
    "driverId": "verstappen-max",
    "constructorId": "red-bull-racing",
    "number": "1",
    "tla": "VER",
    "name": "Max Verstappen",
    "team": "Red Bull Racing"
  },
  "sectors": {
    "s1": {
      "drivers": [
        {
          "driverId": "verstappen-max",
          "constructorId": "red-bull-racing",
          "number": "1",
          "tla": "VER",
          "name": "Max Verstappen",
          "team": "Red Bull Racing",
          "pFastest": 0.43,
          "predictedDeltaMs": -12.4,
          "sigma": 0.032
        },
        {
          "driverId": "norris-lando",
          "constructorId": "mclaren",
          "number": "4",
          "tla": "NOR",
          "name": "Lando Norris",
          "team": "McLaren F1 Team",
          "pFastest": 0.31,
          "predictedDeltaMs": -8.1,
          "sigma": 0.032
        }
      ]
    },
    "s2": {
      "drivers": [
        {
          "driverId": "norris-lando",
          "constructorId": "mclaren",
          "number": "4",
          "tla": "NOR",
          "name": "Lando Norris",
          "team": "McLaren F1 Team",
          "pFastest": 0.38,
          "predictedDeltaMs": -10.2,
          "sigma": 0.029
        },
        {
          "driverId": "verstappen-max",
          "constructorId": "red-bull-racing",
          "number": "1",
          "tla": "VER",
          "name": "Max Verstappen",
          "team": "Red Bull Racing",
          "pFastest": 0.36,
          "predictedDeltaMs": -9.8,
          "sigma": 0.029
        }
      ]
    },
    "s3": {
      "drivers": [
        {
          "driverId": "verstappen-max",
          "constructorId": "red-bull-racing",
          "number": "1",
          "tla": "VER",
          "name": "Max Verstappen",
          "team": "Red Bull Racing",
          "pFastest": 0.49,
          "predictedDeltaMs": -14.1,
          "sigma": 0.034
        },
        {
          "driverId": "norris-lando",
          "constructorId": "mclaren",
          "number": "4",
          "tla": "NOR",
          "name": "Lando Norris",
          "team": "McLaren F1 Team",
          "pFastest": 0.29,
          "predictedDeltaMs": -8.3,
          "sigma": 0.034
        }
      ]
    }
  },
  "drivers": [
    {
      "driverId": "verstappen-max",
      "constructorId": "red-bull-racing",
      "number": "1",
      "tla": "VER",
      "name": "Max Verstappen",
      "team": "Red Bull Racing",
      "sector1DeltaMs": -12.4,
      "sector2DeltaMs": -9.8,
      "sector3DeltaMs": -14.1
    },
    {
      "driverId": "norris-lando",
      "constructorId": "mclaren",
      "number": "4",
      "tla": "NOR",
      "name": "Lando Norris",
      "team": "McLaren F1 Team",
      "sector1DeltaMs": -8.1,
      "sector2DeltaMs": -10.2,
      "sector3DeltaMs": -8.3
    }
  ]
}

analytics.sector-paceSector Pace Analyticsanalytics

On sector anomaly · Race, Sprint

Per-sector pace deltas with anomaly detection; fires when a sector-pace anomaly is detected.

Backed by: sector pace analyzer. How the models work →

FieldTypeDescription
data.driverobjectThe driver the anomaly is for (full DriverRef: number, driverId, tla, name, team).
data.s1 / s2 / s3object|nullPer-sector reading: deltaSec vs the rolling median baseline, baselineMs, currentMs, cleanLapCount.
data.anomalyDetectedbooleantrue when a sector departs its baseline beyond the warning threshold.
data.anomalySector / anomalyLevelnumber|stringWhich sector (1–3) and severity ("WARNING" | "CRITICAL").
data.classifiedCausestring|null"RAIN" | "TIRE_CLIFF" | "INCIDENT" | "UNKNOWN" — rule-based cause classification.
data.rainConfidencenumber0–1 confidence the anomaly is rain-driven.
data.crossDriverCorrelatedbooleantrue when ≥3 cars show the same-sector anomaly on the same lap (weather, not car-specific).
data.driversAffectedSameSectorobject[]Other cars flagged in the same sector this lap — a full DriverRef each.
Sample payload
json
{
  "feed": "analytics.sector-pace",
  "sessionId": "9560",
  "lap": 33,
  "utc": "2026-06-08T14:32:18.441Z",
  "data": {
    "driver": {
      "driverId": "norris-lando",
      "constructorId": "mclaren",
      "number": "4",
      "tla": "NOR",
      "name": "Lando Norris",
      "team": "McLaren F1 Team"
    },
    "raceLap": 33,
    "s1": {
      "deltaSec": 0.08,
      "baselineMs": 28450,
      "cleanLapCount": 6,
      "currentMs": 28530
    },
    "s2": {
      "deltaSec": 2.13,
      "baselineMs": 31210,
      "cleanLapCount": 6,
      "currentMs": 33340
    },
    "s3": null,
    "anomalyDetected": true,
    "anomalySector": 2,
    "anomalyLevel": "WARNING",
    "classifiedCause": "RAIN",
    "rainConfidence": 0.78,
    "crossDriverCorrelated": true,
    "driversAffectedSameSector": [
      {
        "driverId": "leclerc-charles",
        "constructorId": "ferrari",
        "number": "16",
        "tla": "LEC",
        "name": "Charles Leclerc",
        "team": "Scuderia Ferrari"
      },
      {
        "driverId": "hamilton-lewis",
        "constructorId": "ferrari",
        "number": "44",
        "tla": "HAM",
        "name": "Lewis Hamilton",
        "team": "Scuderia Ferrari"
      }
    ]
  }
}

analytics.battleStrategy Battle Alertanalytics

On battle state change · Race, Sprint

On-track battle status between a driver and the car directly ahead (closing, holding, defending).

Backed by: strategy battle tracker. How the models work →

FieldTypeDescription
data.attacker / defenderobjectThe two cars in the on-track fight (each a full DriverRef: number, driverId, tla, name, team).
data.currentGapSecnumberCurrent gap between the pair (seconds).
data.catchRateSecPerLapnumberPositive = attacker closing; negative = defender pulling away.
data.lapsToStrikingDistancenumber|nullProjected laps until the attacker is in range; null when not catching or already there.
data.battleStatusstringLifecycle of the battle (forming, in-range, resolved…).
Sample payload
json
{
  "feed": "analytics.battle",
  "sessionId": "9560",
  "lap": 41,
  "utc": "2026-06-08T14:32:18.441Z",
  "data": {
    "attacker": {
      "driverId": "verstappen-max",
      "constructorId": "red-bull-racing",
      "number": "1",
      "tla": "VER",
      "name": "Max Verstappen",
      "team": "Red Bull Racing"
    },
    "defender": {
      "driverId": "norris-lando",
      "constructorId": "mclaren",
      "number": "4",
      "tla": "NOR",
      "name": "Lando Norris",
      "team": "McLaren F1 Team"
    },
    "currentGapSec": 1.62,
    "catchRateSecPerLap": 0.31,
    "lapsToStrikingDistance": 2,
    "battleStatus": "APPROACHING",
    "forecast": {
      "passProbabilityPerLap": 0.22,
      "pPassWithinHorizon": 0.526,
      "horizonLaps": 5
    }
  }
}

analytics.pit-windowPit Window Alertanalytics

On window open/urgent · Race, Sprint

Pit-window status (OPEN / URGENT) combining pit probability, undercut viability, tyre cliff risk, and gap context.

Backed by: pit window alert, pit stop probability, EKF tire health. How the models work →

FieldTypeDescription
data.driverobjectThe driver the alert is for (full DriverRef: number, driverId, tla, name, team).
data.statusstringPit-window state for the driver (survival-model window plus overrides).
data.pitProbabilitynumber0–1 pit-stop probability from the pit stop model.
data.undercutViablebooleanWhether an undercut on the car ahead is currently viable.
data.cliffRiskstringTyre-cliff proximity classification feeding the window call.
data.overrideReasonstring|null"VSC_WINDOW" | "SC_WINDOW" | "LEADER_PITTED" — event overrides that open a window early.
data.vscNetDeltaSecnumber|nullEstimated time saved by pitting under the current VSC/SC, when applicable.
data.pitCountnumberThe driver's current pit-stop count.
Sample payload
json
{
  "feed": "analytics.pit-window",
  "sessionId": "9560",
  "lap": 34,
  "utc": "2026-06-08T14:32:18.441Z",
  "data": {
    "driver": {
      "driverId": "leclerc-charles",
      "constructorId": "ferrari",
      "number": "16",
      "tla": "LEC",
      "name": "Charles Leclerc",
      "team": "Scuderia Ferrari"
    },
    "raceLap": 34,
    "status": "URGENT",
    "pitProbability": 0.81,
    "undercutViable": true,
    "cliffRisk": "BLISTERING_RISK",
    "overrideReason": null,
    "vscNetDeltaSec": null,
    "pitCount": 1
  }
}

analytics.track-conditionsTrack Conditions Analyticsanalytics

Per lap · Race, Sprint

Track evolution and grip-condition analytics derived from field pace trends.

Backed by: track conditions model. How the models work →

FieldTypeDescription
data.sector1 / sector2 / sector3stringPer-sector surface condition classification.
data.fullCircuitWetbooleanAll three sectors classified wet.
data.intermediateWindowOpenbooleanAny sector wet AND slick runners losing more than ~2s — the inter window.
data.crossoverRecommendedbooleanSlick cars now faster than intermediates in at least one sector — the crossover call.
data.lastUpdatedLapnumberRace lap this classification was last updated.
Sample payload
json
{
  "feed": "analytics.track-conditions",
  "sessionId": "9560",
  "lap": 28,
  "utc": "2026-06-08T14:32:18.441Z",
  "data": {
    "sector1": "DRYING",
    "sector2": "WET",
    "sector3": "DRYING",
    "fullCircuitWet": false,
    "intermediateWindowOpen": true,
    "crossoverRecommended": false,
    "lastUpdatedLap": 28
  }
}

analytics.pit-qualityPit Quality Alertanalytics

On pit completion · Race, Sprint

Pit-stop execution quality assessment (stationary time vs. expected) after a stop completes.

Backed by: pit quality model. How the models work →

FieldTypeDescription
data.driverobjectThe driver whose stop this grades (full DriverRef: number, driverId, tla, name, team).
data.stationaryTimeSecnumberMeasured stationary time for the completed stop.
data.teamSessionAverageSecnumberThe team's rolling average stationary time this session (before this stop).
data.vsTeamSessionAverageSecnumberThis stop minus the team average — positive = slower than the crew's norm.
data.qualitystringGrade for the stop relative to session norms.
data.stopNumbernumberNth stop this session for this driver.
Sample payload
json
{
  "feed": "analytics.pit-quality",
  "sessionId": "9560",
  "lap": 24,
  "utc": "2026-06-08T14:32:18.441Z",
  "data": {
    "driver": {
      "driverId": "leclerc-charles",
      "constructorId": "ferrari",
      "number": "16",
      "tla": "LEC",
      "name": "Charles Leclerc",
      "team": "Scuderia Ferrari"
    },
    "raceLap": 24,
    "stationaryTimeSec": 4.1,
    "teamSessionAverageSec": 2.7,
    "vsTeamSessionAverageSec": 1.4,
    "fieldSessionAverageSec": 3,
    "vsFieldSessionAverageSec": 1.1,
    "fieldRank": 14,
    "totalFieldStopsSoFar": 16,
    "quality": "SLOW",
    "stopNumber": 2
  }
}
TelemetryResults & Standings