Read F1 game telemetry over UDP in Node.js. The package includes a client, packet parsers, TypeScript types, and game constants. It is free to use and needs no RaceHub account or subscription.
Release status: This README describes the 0.3.0 update in PR #107. The npm latest version is still 0.2.12. Use the source setup to try the new features before publication.
- F1 2018 through F1 25. Tests use recorded packets from each format.
- F1 25 2026 Season Pack: experimental. The layouts follow the EA specification. No recorded 2026 game data was available for tests.
The F1 24/25 recordings do not cover time trial, lap positions, lobby, or final classification. Those layouts were checked against the EA specifications.
Use Node.js 22 or later. CI runs on Node.js 22 and 24.
Install the latest published package:
npm install @racehub-io/f1-telemetry-clientVersion 0.3.0 adds F1 24/25 formats, experimental 2026 formats, UDP sender details, typed listeners, and parse-error events. It removes build/es5. The build/main entry stays the same. The build emits ES2020 JavaScript.
Enable UDP telemetry in the game. Set the destination IP to the computer that runs this client. Set the game port to the client port. The default is 20777.
const {
F1TelemetryClient,
constants,
} = require('@racehub-io/f1-telemetry-client');
const {PACKETS} = constants;
const client = new F1TelemetryClient({port: 20777});
client.on(PACKETS.carTelemetry, (packet, sender) => {
console.log(packet.m_carTelemetryData);
console.log(sender?.address, sender?.port);
});
client.on('raw', ({packetID, packetData, message}, sender) => {
console.log(packetID, packetData.data, message.length, sender?.address);
});
client.on('error', (error, message, sender) => {
console.error(error.message, message?.length, sender?.address);
});
client.start();
process.once('SIGINT', () => client.stop());In TypeScript, use import {F1TelemetryClient, constants} from '@racehub-io/f1-telemetry-client'. The on and once methods infer packet and sender types from the event name. Custom events remain available.
Packet events receive decoded data as their first argument. The raw event receives {packetID, packetData, message}. Its decoded data is in packetData.data; message is the original UDP buffer.
Both event types receive UDP sender details as their second argument: address, port, family, and size. Direct calls to handleMessage(buffer) have no sender details. The protocol header stays unchanged.
| Option | Default | Purpose |
|---|---|---|
address |
undefined |
Bind to all local IPv4 interfaces by default. Set a local IP to select one interface. |
port |
20777 |
UDP port to listen on. |
bigintEnabled |
true |
Include m_sessionUID as a bigint. Set to false to skip the field. |
forwardAddresses |
undefined |
Forward unchanged packets to an array of {port, ip} destinations. Set each destination IP explicitly. |
skipParsing |
false |
Disable packet and raw events. Packet forwarding still runs. |
Convert bigint values to strings before you serialize packet data with JSON.stringify. The shared header type marks m_sessionUID as optional because bigintEnabled: false skips it.
Listen with client.on(constants.PACKETS.<name>, handler). Events depend on the packet format and the packets sent by the game.
| First format | Added events |
|---|---|
| 2018 | motion, session, lapData, event, participants, carSetups, carTelemetry, carStatus |
| 2020 | finalClassification, lobbyInfo |
| 2021 | carDamage, sessionHistory |
| 2023 | tyreSets, motionEx |
| 2024 | timeTrial |
| 2025 | lapPositions |
| 2026, experimental | carTelemetry2 |
The error event receives a parse error, the failed UDP buffer, and optional sender details. Add a listener to handle malformed packets and continue receiving telemetry. Without a listener, Node.js throws the error. Exceptions in your packet or raw listeners still propagate.
Call F1TelemetryClient.parseBufferMessage(buffer, true) to parse a UDP packet without starting a socket listener. It returns {packetID, packetData, message} or undefined for an unknown packet ID. Read decoded data from packetData.data. This static method throws on malformed data.
The second argument controls bigint parsing. It defaults to false for this static method. Pass true to include m_sessionUID.
- For formats 2024 and later, use
constants.SESSION_TYPES_2024andconstants.TEAMS_2024. Use the legacySESSION_TYPESandTEAMStables for earlier formats. - Use
constants.TYRESwithm_tyreActualCompoundfor the C-number. Useconstants.VISUAL_TYRESwithm_tyreVisualCompoundfor the Soft/Medium/Hard label and color. For example, actual compound17is C4; visual compound17is Medium. - Use
constants.PIT_STATUSwithm_pitStatus. Nationality IDs 88-90 are available inconstants.NATIONALITIES. - Formats through 2020 use
m_lastLapTimeandm_currentLapTimein seconds. Formats 2021 and later use theInMSnames in milliseconds. The shared types include both sets as optional fields. - Time fields keep their raw units. Combine separate minute and millisecond fields in the consuming app when needed.
- Divide the experimental 2026 G-force values by
1000to get G-force units.
To try the 0.3.0 release branch:
git clone --branch maintenance/0.3.0 https://github.com/racehub-io/f1-telemetry-client.git
cd f1-telemetry-client
npm ci
npm test -- --runInBand
npm run build
npm startThe playground listens on port 20777. Set the game's UDP port to 20777. Press Ctrl+C to stop it.
npm test includes type and lint checks. npm run build creates the package files in build/main. The published package excludes tests, recordings, and the playground.
To record packets from the game on port 20777:
mkdir -p recordings
npm run recordThe recorder writes JSON lines to recordings/. Review recordings for private data before sharing them. See CONTRIBUTING.md.
F1 2018-2021 legacy references
These original Codemasters links may be unavailable.
Maintenance depends on community contributions and volunteer time. Open issues and pull requests to help maintain the client. See CONTRIBUTING.md and SECURITY.md.
RaceHub dedicates its own rights under CC0 1.0. Existing MIT terms and third-party notices remain in force. See LICENSING.md for the scope. Game software keeps its own terms.
Protocol updates and recorded F1 24/25 test data are adapted from z0mt3c/f1-telemetry-client, under the MIT License. Thanks to Phaturia for the sender-information request in PR #106.
Further updates adapt typed listeners from jayden-chan, optional network binding from mmertz, and the standard example port from Hotman75. Parse-error events and constant updates also follow the z0mt3c fork. Existing event payloads remain compatible.