@paraspatankar/f1js
v1.0.3
Published
TypeScript SDK for Formula 1 data — race results, standings, and telemetry
Maintainers
Readme
f1js
TypeScript SDK for Formula 1 data — race results, standings, drivers, and live telemetry.
f1js wraps Jolpica-F1 and OpenF1 into a single ergonomic API with built-in disk caching, automatic rate limiting, and full TypeScript type safety. No API keys required.
Contents
- Installation
- Quick Start
- API Reference
- Caching
- Rate Limiting
- Type Reference
- Limitations
- Data Sources
- Contributing
- License
Installation
npm install @paraspatankar/f1jsRequires Node.js ≥ 18. Not browser-compatible in v1 — see Limitations.
Quick Start
import { f1 } from '@paraspatankar/f1js'
// Race results — historical data from 1950 to present
const results = await f1.races.getResults(2024, 1)
console.log(results[0])
// { position: 1, driverId: 'verstappen', driverCode: 'VER', points: 25, ... }
// Driver telemetry — sampled at ~3.7 Hz (2023+ only)
const carData = await f1.telemetry.getCarData(2024, 1, 'VER')
console.log(carData[0])
// { speed: 312, throttle: 100, brake: false, gear: 8, drs: 12, rpm: 11800, ... }
// Driver championship standings
const standings = await f1.standings.getDriverStandings(2024)
console.log(standings[0])
// { position: 1, driverId: 'verstappen', points: 575, wins: 19, ... }
// Lap time utilities
const gap = f1.utils.lapGap('1:23.456', '1:23.891') // → '+0.435'API Reference
All methods return Promises and are fully typed. Every data shape is exported from the package — see Type Reference.
Races
Data sourced from Jolpica-F1. Historical coverage from 1950 to present.
// All races in a season, ordered by round number
const races = await f1.races.getSeason(2024)
// → Race[]
// Full results for a specific race round
const results = await f1.races.getResults(2024, 1)
// → RaceResult[]Race fields: season, round, name, circuit, country, date
RaceResult fields: position, driverId, driverCode, constructorId, constructorName, grid, points, laps, status, fastestLapTime
Drivers
// All drivers who competed in a season
const drivers = await f1.drivers.getSeason(2024)
// → Driver[]
// A single driver by their Jolpica ID (lowercase slug)
const driver = await f1.drivers.getDriver('norris')
// → DriverDriver fields: driverId, firstName, lastName, code, number, nationality
Common driver IDs: 'verstappen', 'hamilton', 'norris', 'leclerc', 'sainz'
Standings
// Driver championship table for a season
const driverStandings = await f1.standings.getDriverStandings(2024)
// → DriverStanding[]
// Constructor championship table for a season
const constructorStandings = await f1.standings.getConstructorStandings(2024)
// → ConstructorStanding[]If called with the current season, returns standings as of the most recent race.
DriverStanding fields: position, points, wins, driverId, driverCode, firstName, lastName, constructorId, constructorName
ConstructorStanding fields: position, points, wins, constructorId, constructorName, nationality
Telemetry (2023+)
Data sourced from OpenF1 at ~3.7 Hz. All telemetry methods will throw if season < 2023.
The driver parameter accepts any of:
- Driver code:
'VER','HAM','NOR' - Last-name slug:
'verstappen','hamilton','norris' - Number:
1,44,4
// Car telemetry — ~8,000 samples per driver per race
const carData = await f1.telemetry.getCarData(2024, 1, 'VER')
// → CarData[]
// Lap-by-lap timing (omit driver for all drivers)
const laps = await f1.telemetry.getLapTimes(2024, 1, 'NOR')
// → LapTime[]
// Pit stop events with full pit lane duration
const pitStops = await f1.telemetry.getPitStops(2024, 1)
// → PitStop[]
// Tyre stints — compound, lap range, and tyre age
const stints = await f1.telemetry.getStints(2024, 1, 'HAM')
// → Stint[]
// Race position samples over time (for position-change charts / replays)
const positions = await f1.telemetry.getPositions(2024, 1, 1)
// → Position[]
// Weather readings (~1 per minute, no driver parameter)
const weather = await f1.telemetry.getWeather(2024, 1)
// → WeatherSample[]Note: The first call for a race fetches from the network and may take several seconds due to response size. All subsequent calls are instant (filesystem cache).
Utilities
Pure functions — no async, no network.
// Parse a lap time string to milliseconds
f1.utils.parseLapTime('1:23.456') // → 83456
// Format milliseconds back to a lap time string
f1.utils.formatLapTime(83456) // → '1:23.456'
// Calculate the gap between two lap times
f1.utils.lapGap('1:23.456', '1:23.891') // → '+0.435'
f1.utils.lapGap('1:23.891', '1:23.456') // → '-0.435'The expected format for parseLapTime and lapGap is M:SS.mmm (e.g. 1:23.456). An error is thrown for invalid formats.
Caching
Results are cached automatically to disk in .f1js-cache/ in your working directory. The cache is keyed by URL, so each unique request is only ever fetched once per policy window.
| Data type | Cache duration | |-----------|---------------| | Past seasons (before current year) | Forever — fetched once, never re-fetched even across restarts | | Current season | 5 minutes |
Add .f1js-cache/ to your .gitignore:
echo ".f1js-cache/" >> .gitignoreRate Limiting
OpenF1 enforces a hard limit of 3 requests/second. f1js handles this transparently with a built-in sliding-window queue — you don't need to add any delays or retry logic in your code.
Be aware that the first fetch of full-race telemetry (up to ~35,000 samples across all drivers) can take a meaningful amount of time as requests are queued. Subsequent calls are instant thanks to the cache.
Type Reference
All types are exported from the package top-level and can be imported directly:
import type {
Race,
RaceResult,
Driver,
DriverStanding,
ConstructorStanding,
CarData,
Stint,
Position,
} from '@paraspatankar/f1js'| Type | Source | Description |
|------|--------|-------------|
| Race | Jolpica | A scheduled race event |
| RaceResult | Jolpica | One driver's result in a race |
| Driver | Jolpica | Driver profile and metadata |
| DriverStanding | Jolpica | Championship position for a driver |
| ConstructorStanding | Jolpica | Championship position for a constructor |
| CarData | OpenF1 | A single telemetry sample (speed, throttle, brake, RPM, gear, DRS) |
| LapTime | OpenF1 | One lap's timing data for a driver |
| PitStop | OpenF1 | A pit stop event with full pit lane duration |
| Stint | OpenF1 | A tyre stint (compound, lap range, tyre age) |
| Position | OpenF1 | A race position snapshot for a driver at a point in time |
| WeatherSample | OpenF1 | Air temp, track temp, humidity, wind, rainfall |
Limitations
- Telemetry is 2023+ only. OpenF1 does not have data before the 2023 season. For historical lap times, use
f1.races.getResults()instead. - Node.js only in v1. The disk cache uses
fs/promises, which isn't available in browsers. Attempting to bundle f1js for the browser will fail at this import. A dual-build with an isomorphic in-memory cache fallback is planned for v2. - No live telemetry in v1. This library targets historical and completed sessions. Live race data (WebSocket streaming) is on the roadmap for v2.
- Not for data science. If you're doing lap time analysis in Python, FastF1 is a better fit. f1js targets web developers building Node.js applications.
Data Sources
Both APIs are free and require no authentication.
| Source | Coverage | Documentation | |--------|----------|---------------| | Jolpica-F1 | Results, standings, schedules (1950–present) | ergast.com/mrd | | OpenF1 | Car telemetry at ~3.7 Hz (2023–present) | openf1.org/documentation |
Contributing
# Install dependencies
npm install
# Run tests
npm test
# Type check
npm run typecheck
# Build (CJS + ESM + type declarations)
npm run build
# Watch mode for development
npm run devTests are written with Vitest. The test suite covers normalizers, lap time utilities, and basic setup.
