FIT Parser - v6.2.7
    Preparing search index...

    Install with npm install fit-file-parser in your project. Node examples require Node 20 or newer. Save the following as parse.mjs, place a FIT file at ./activity.fit, and run node parse.mjs:

    import { readFile } from 'node:fs/promises'
    import FitParser from 'fit-file-parser'

    const content = await readFile('./activity.fit')
    const parser = new FitParser({
    force: false,
    })

    const data = await parser.parseAsync(content)

    console.log({
    sessions: data.sessions?.length ?? 0,
    laps: data.laps?.length ?? 0,
    records: data.records?.length ?? 0,
    })

    This example checks CRCs while retaining the default compatible decoding policy. The library default is force: true, which skips CRC checks. Choose deliberately using Configure parsing; strict is a separate structural policy. Default output uses root lists, metres and metres per second.

    The parser APIs accept:

    • Node.js Buffer
    • ArrayBuffer

    Supply decompressed FIT bytes. Unpack gzip or ZIP containers before parsing. Pass a Node Buffer directly so its byte offset and length are respected. For another typed-array view, an exact copy avoids passing unrelated backing-buffer bytes:

    const arrayBuffer = Uint8Array.from(view).buffer
    const parsed = await new FitParser({ force: false }).parseAsync(arrayBuffer)

    Use your application's bundler to resolve the npm import. A browser File provides the ArrayBuffer expected by the parser:

    import FitParser from 'fit-file-parser'

    export async function parseFitUpload(file: File) {
    const content = await file.arrayBuffer()
    return new FitParser({ force: false }).parseAsync(content)
    }

    The library uses the buffer package for string decoding. Browser builds must resolve its browser implementation rather than externalize it as a Node builtin.

    Some exports append several complete FIT files into one input. Use parseFilesAsync() to return a ParsedFit[] in file order:

    const files = await new FitParser({ force: false }).parseFilesAsync(content)
    for (const file of files) {
    console.log(file.sessions?.length ?? 0)
    }

    Each result has independent message definitions, developer descriptions, timestamps, and activity collections. Results are never merged. A single FIT file returns a one-element array. All parsing APIs share the same force and strict options. By default, complete fields in a partial final record can be recovered, and a non-FIT suffix after parsed files is ignored. With force: true, missing CRC bytes are also accepted, including when the next FIT header starts at the declared data boundary or after one CRC byte. The parser never scans record payloads for guessed file boundaries.

    Use { force: false, strict: true } to require complete files and records, valid checksums, and no trailing bytes. { force: true, strict: true } enforces the same structure while skipping checksum validation. Any file that cannot be parsed rejects the whole call with an Error. Empty input, invalid headers, and declared data beyond the available input remain errors in every mode.

    The existing parseAsync() and callback APIs return the first FIT file only. With strict: true, they require exactly one file; use parseFilesAsync() for strict validation of concatenated input.

    import { readFile } from 'node:fs'
    import FitParser from 'fit-file-parser'

    readFile('./activity.fit', (readError, content) => {
    if (readError) {
    console.error(readError)
    return
    }

    const parser = new FitParser({ force: false })
    try {
    parser.parse(content, (parseError, data) => {
    if (parseError) {
    console.error(parseError)
    return
    }

    console.log(data)
    })
    }
    catch (decoderError) {
    console.error(decoderError)
    }
    })

    The callback reports validation errors as strings. parseAsync() rejects with those values; decoder failures can reject with an Error. parseFilesAsync() consistently rejects with an Error.

    The mode controls where sessions, laps, records, and related activity collections are exposed.

    Mode Root lists Nested under activity Default
    list Yes No Yes
    cascade No Yes No
    both Yes Yes No

    In cascade output, sessions contain their laps and laps contain their records and lengths. Other parsed FIT message collections remain available where the parser exposes them.

    Every recognized message is also retained in file order in data.messages. This additive index is useful for message kinds that historically exposed only the last value at the root:

    const workoutSteps = data.messages?.workout_step ?? []
    const diveSummaries = data.messages?.dive_summary ?? []

    Existing root lists, cascade nesting, and last-message root properties remain unchanged.

    These collection descriptions apply to decoded output. rawMessagesOnly: true omits decoded collections, including messages; see Read raw and developer data. The messages object groups observations by message name; each array preserves that name's file order. It is not one interleaved chronological list. Use raw_messages or readFitMessages() when interleaved wire order matters. These collections are alternate views of observations: choose one view for aggregation instead of adding root lists, nested collections and messages together.

    Activity, course and monitoring files can all contain valid FIT messages. Inspect available file_ids metadata when your application needs a particular file type; a successful decode alone does not establish that the input is a workout.

    The package includes TypeScript declarations and exports FitParserOptions, FitEncoderField, and FitEncoderOptions.

    ESM:

    import FitParser, { FitBaseType, FitEncoder } from 'fit-file-parser'
    

    CommonJS:

    const {
    default: FitParser,
    FitBaseType,
    FitEncoder,
    } = require('fit-file-parser')

    See Configure parsing for validation and unit options, and Handle errors for decoder exceptions.