TypeScript library for parsing Car Scanner ELM OBD2 .brc recording files (npm: carscanner-parser) — the
internal data format exported by the Car Scanner app
(see "Data recording" → export as BRC).
The binary layout was reverse-engineered from real recordings (format version 2). Parsing is byte-exact: both test recordings parse 100 % with zero warnings.
import { parseBrc, series, sensorName, summarize } from "carscanner-parser";
const buffer = await Bun.file("2026-08-08 09-33-21.brc").arrayBuffer();
const record = parseBrc(buffer);
record.header; // { version, vin, carName, profile, adapter, session }
record.sensors; // Map<number, SensorDef> (type id -> name/shortName/y/time/firstValue)
record.samples; // Sample[] ({ time, type, value }, ~1 Hz per sensor)
record.warnings; // string[] (non-fatal parse problems)
// per-sensor time series
const boost = series(record, 237); // "Calculated boost"
console.log(sensorName(record, 237)); // "Calculated boost"
// min/max/last/count per sensor (non-finite values skipped)
for (const [type, stats] of summarize(record)) console.log(type, stats);parseBrc(data: ArrayBuffer | Uint8Array | DataView): BrcRecord— throws on an invalid header; malformed records mid-file producewarningsinstead.series(record, type): Sample[]— samples of one sensor (already time-ordered).sensorName(record, type): string— resolved sensor name ("sensor <id>"fallback).summarize(record): Map<number, { min, max, last, count }>— per-sensor stats.
- Header:
CARSCANNERRECORDmagic, format version, VIN, car name, profile name, adapter name, then 12 opaque session bytes. - The file is a stream of records:
- DEF — sensor definition + first sample, written the first time a sensor
produces data (the
cfgdouble is a per-sample timestamp in seconds, with an app-relative offset of ~17 s). - SAMPLE —
[cfgMagic u32][time f64][type u32][value f64], optionally followed by a constant marker u32.
- DEF — sensor definition + first sample, written the first time a sensor
produces data (the
timevalues are monotonic within a recording; treat them as relative seconds.- Values may be
Infinity/NaN(e.g. calculated fuel consumption before the calculation has data) — the parser preserves them as-is.
The package also ships a small CLI. Install globally (or run via the npm/bun scripts):
npm install -g carscanner-parser # or: bun add -g carscanner-parser
carscanner path/to/recording.brc [more.brc ...]Prints the header, sensor/sample counts, time span, per-sensor min/max/last and the
boost peak. Use carscanner --help for usage. In a checkout you can also run
bun run cli -- <file.brc>. The integration test also runs against any real .brc
files found next to the project and asserts a byte-complete, warning-free parse.
bun install
bun test
bunx tsc --noEmit