Skip to content
Docs menu

Body composition & weight

Weigh-ins and body-composition records. Note the unit asymmetry: writes send the raw value in the unit you name, reads return GRAMS.

Every method below hangs off a Garmin instance. See Installation & setup for how to construct one:

import { GarminClient, Garmin, FileTokenStore } from "garminconnect-js";

const client = new GarminClient({ tokenStore: new FileTokenStore("./tokens") });
if (!(await client.loadTokens())) throw new Error("not connected to Garmin");
const garmin = new Garmin(client);

8 methods. The verification column says what has been confirmed against a live Garmin account, not merely unit-tested — AGENTS.md carries the full evidence per method.

MethodVerified
addBodyCompositionlive-verified
addWeighInlive-verified
addWeighInWithTimestampslive-verified
deleteWeighInlive-verified
deleteWeighInslive-verified
getBodyCompositionlive-verified
getDailyWeighInslive-verified
getWeighInslive-verified

addBodyComposition

garmin.addBodyComposition(weight: number, extra?: WeightScaleFields & { timestamp?: string }): Promise<unknown>
const result = await garmin.addBodyComposition(1);

Returns

unknown — Garmin's response is passed through unparsed. Cast it to whatever you need; this library does not model it.

builds a .fit binary in memory (src/util/fit.ts, a hand-rolled FIT encoder) and uploads it via client.upload to /upload-service/upload; weight validated positive/finite, throws GarminError otherwise; passes client.upload's result through unchecked

Verification: live-verified

addWeighIn

garmin.addWeighIn(weightValue: number, unitKey?: "kg" | "lbs", when?: Date): Promise<unknown>
const result = await garmin.addWeighIn(1);

Returns

unknown — Garmin's response is passed through unparsed. Cast it to whatever you need; this library does not model it.

defaults unitKey="kg", when=new Date()

Verification: live-verified

addWeighInWithTimestamps

garmin.addWeighInWithTimestamps(weightValue: number, unitKey?: "kg" | "lbs", dateTimestamp?: string, gmtTimestamp?: string, when?: Date): Promise<unknown>
const result = await garmin.addWeighInWithTimestamps(1);

Returns

unknown — Garmin's response is passed through unparsed. Cast it to whatever you need; this library does not model it.

same raw-value, no-conversion rule as addWeighIn; the two timestamps are COUPLED: the local instant resolves from dateTimestamp if given (naive strings read as LOCAL time) else from when (defaults new Date()), and gmtTimestamp, when omitted, is derived from THAT resolved instant — never independently from when. Both supplied strings are re-formatted rather than forwarded verbatim (a naive gmtTimestamp is read as UTC)

Verification: live-verified

deleteWeighIn

garmin.deleteWeighIn(cdate: string | Date, weightPk: number): Promise<null>
const result = await garmin.deleteWeighIn("2026-09-24", 1);

Returns

null

Verification: live-verified

deleteWeighIns

garmin.deleteWeighIns(cdate: string | Date, deleteAll?: boolean): Promise<number | null>
const result = await garmin.deleteWeighIns("2026-09-24");

Returns

number

no HTTP path of its own: calls getDailyWeighIns, then loops deleteWeighIn per entry; returns null (deletes nothing) if there are zero entries, or more than one entry and deleteAll is not true; otherwise deletes every entry that day and returns the count. IRREVERSIBLE — deletes ALL weigh-ins recorded on cdate when it proceeds

Verification: live-verified

getBodyComposition

garmin.getBodyComposition(startdate: string | Date, enddate?: string | Date): Promise<BodyCompositionRange | null>
const result = await garmin.getBodyComposition("2026-09-24");

Returns

BodyCompositionRange:

FieldTypeAlways present
startDatestringno
endDatestringno
dailyWeightSummariesRecord<string, unknown>[]no
totalAverageRecord<string, unknown>no

Plus every other field Garmin sends: this type carries an index signature because the real response is wider than the fields above, which are the ones this library relies on or has observed. Read an actual response before depending on a field that is not listed.

GETs /weight-service/weight/dateRange; enddate defaults to startdate; throws GarminError if startdate > enddate; passes through unchecked. getStatsAndBody (wellness service) now delegates to this instead of inlining its own copy of the same call

Verification: live-verified

getDailyWeighIns

garmin.getDailyWeighIns(cdate: string | Date): Promise<DailyWeighIns | null>
const result = await garmin.getDailyWeighIns("2026-09-24");

Returns

DailyWeighIns:

FieldTypeAlways present
dateWeightListWeighInEntry[]no
totalAverageRecord<string, unknown>no

Plus every other field Garmin sends: this type carries an index signature because the real response is wider than the fields above, which are the ones this library relies on or has observed. Read an actual response before depending on a field that is not listed.

GETs /weight-service/weight/dayview/{cdate}?includeAll=true; passes through unchecked

Verification: live-verified

getWeighIns

garmin.getWeighIns(startdate: string | Date, enddate: string | Date): Promise<WeighInRange>
const result = await garmin.getWeighIns("2026-09-24", "2026-09-24");

Returns

WeighInRange:

FieldTypeAlways present
dailyWeightSummariesRecord<string, unknown>[]no
totalAverageRecord<string, unknown>no

Plus every other field Garmin sends: this type carries an index signature because the real response is wider than the fields above, which are the ones this library relies on or has observed. Read an actual response before depending on a field that is not listed.

Verification: live-verified

Methods in this category