A TypeScript library for the Dexcom Share API. Port of pydexcom.
Published as an ES module with bundled type definitions.
Node.js 22 or later.
npm install cgm.jsVersion 4.0.0 rewrites the library in TypeScript and publishes it as an ES module only. Runtime behavior is unchanged, but packaging changed:
- Node.js 22 or later is required, up from Node.js 18.
- The package is ESM-only. Use
import { Dexcom } from "cgm.js". CommonJS code on Node.js 22.12 or later can stillrequire("cgm.js"), because Node.js can load ES modules synchronously. On older 22.x releases, use dynamicimport(). - Imports go through the package
exportsmap.cgm.js,cgm.js/errorsandcgm.js/constantsare the supported entry points. Deep imports such ascgm.js/cgm.jsorcgm.js/errors.jsnow fail withERR_PACKAGE_PATH_NOT_EXPORTED. - Everything is exported from the package root. Error classes, error enums,
and constants can now be imported from
cgm.jsdirectly, alongsideDexcom,GlucoseReadingandRegion. - Type definitions are included. Remove any hand-written
declare module "cgm.js"shims. See TypeScript.
Version 3.0.0 hardens HTTP requests and response parsing. Calls that succeeded in v2 can now throw:
- Glucose readings are validated strictly.
Valuemust be a nonnegative integer or a string of decimal digits ("120.5"and"120mg"are rejected), andDTmust be a valid date. Malformed readings throwArgumentErrorwithArgumentErrorEnum.GLUCOSE_READING_INVALID. - Unknown trends are rejected, matching pydexcom. Trends must be one of the
known direction strings or integer codes 0-9. In v2, unknown strings mapped to
trend 0 and unknown integers kept their code with direction
"None". - Requests time out after 30 seconds by default, including reading the
response body, and throw
ServerErrorwithServerErrorEnum.TIMEOUT. PassrequestTimeout(milliseconds) to the constructor to change it. - Redirects are not followed. A redirect response throws
ServerErrorwithServerErrorEnum.REDIRECT, so credentials are never sent to another URL. - Non-array reading responses throw
ServerErrorwithServerErrorEnum.UNEXPECTEDinstead of failing with aTypeError. - The exported
HEADERSconstant changed. It now sendsAccept: application/jsoninstead of the incorrectAccept-Encoding: application/json. - Tests that assert exact
fetchoptions may need updating. Each request now also passesredirect: "manual"and anAbortSignalassignal.
Constructor options, exports, reading methods, and error classes are otherwise unchanged. Concurrent calls on one client now share a single login instead of each authenticating separately.
Version 2.0.0 changes the runtime requirements and HTTP implementation:
- Node.js 18 or later is required, up from Node.js 14. Update your local runtime, CI configuration, and deployment environment before upgrading.
- Requests use the built-in global
fetch. Theisomorphic-fetchdependency and its automatic polyfill have been removed. Environments without globalfetchmust supply their own compatible implementation. - Tests that mock
isomorphic-fetchmust mock globalfetchinstead. For example, replacejest.mock("isomorphic-fetch", () => mockFetch)withjest.spyOn(globalThis, "fetch").mockImplementation(mockFetch), and restore the spy after each test withjest.restoreAllMocks().
The v1 constructor options, exports, reading methods, and error classes are unchanged in the 2.0.0 release. Applications using the public API generally only need to update their runtime and any HTTP mocks.
import { Dexcom } from "cgm.js";
const dexcom = new Dexcom({ username: "username", password: "password" });
const reading = await dexcom.getCurrentGlucoseReading();
if (reading) {
console.log(reading.value); // 120
console.log(reading.mmolL); // 6.7
console.log(reading.trendDirection); // "Flat"
console.log(reading.trendDescription); // "steady"
console.log(reading.trendArrow); // "→"
console.log(reading.time); // 2025-08-07T20:40:58.000Z
} else {
console.log("No recent glucose reading available");
}import { Dexcom, Region } from "cgm.js";Type definitions ship with the package, so no @types package is needed.
Besides the classes, the package exports these types:
import {
Dexcom,
type DexcomOptions, // constructor options
type GlucoseReading, // reading class (also usable as a value)
type GlucoseReadingJson, // raw reading shape from the Share API
type Region, // "us" | "ous" | "jp"
type Trend, // numeric trend code, 0-9
type TrendDirection, // "Flat" | "SingleUp" | ...
} from "cgm.js";
const options: DexcomOptions = { username: "user", password: "pass" };
const dexcom = new Dexcom(options);
const readings: GlucoseReading[] = await dexcom.getGlucoseReadings(60, 12);Each error class narrows error.enum to its own enum. For example,
AccountError["enum"] is AccountErrorEnum | null. Use moduleResolution
"nodenext" or "bundler" so TypeScript reads the package exports map.
By username (email, phone number, or account name):
const dexcom = new Dexcom({ username: "user@email.com", password: "password" });
const dexcom = new Dexcom({ username: "+11234567890", password: "password" });By account ID (found in the URL after logging in to Dexcom Account Management):
const dexcom = new Dexcom({ accountId: "12345678-90ab-cdef-1234-567890abcdef", password: "password" });// United States (default)
const dexcom = new Dexcom({ username: "user", password: "pass" });
const dexcom = new Dexcom({ username: "user", password: "pass", region: Region.US });
// Outside US
const dexcom = new Dexcom({ username: "user", password: "pass", region: Region.OUS });
// Japan
const dexcom = new Dexcom({ username: "user", password: "pass", region: Region.JP });// Most recent reading within the last 10 minutes
const current = await dexcom.getCurrentGlucoseReading();
// Most recent reading within the last 5 minutes
const latest = await dexcom.getLatestGlucoseReading();Both return a single GlucoseReading or null if no reading is available in the time window.
Each HTTP request has a 30-second timeout, including reading the response body.
Set requestTimeout in milliseconds to change it:
const dexcom = new Dexcom({
username: "user",
password: "pass",
requestTimeout: 15000,
});Timeouts throw ServerError with ServerErrorEnum.TIMEOUT. HTTP redirects are
never followed, to prevent forwarding credentials to another destination; they
throw ServerError with ServerErrorEnum.REDIRECT. Concurrent
calls on the same client share session creation; expired sessions are refreshed
with at most one retry per reading request.
// Last 24 hours of readings (defaults)
const readings = await dexcom.getGlucoseReadings();
// Last 60 minutes, up to 12 readings
const readings = await dexcom.getGlucoseReadings(60, 12);
// Last 24 hours of readings, convenience method
const readings = await dexcom.getLatestGlucoseReadings();
// Last 24 hours, up to 5 readings
const readings = await dexcom.getLatestGlucoseReadings(5);The API returns the minimum of the two parameters (minutes and maxCount), so if readings occur every 5 minutes and you request 30 minutes with maxCount: 3, you'll get 3 readings.
const reading = await dexcom.getCurrentGlucoseReading();
reading.value // 120 (mg/dL)
reading.mgdL // 120 (alias for value)
reading.mmolL // 6.7 (converted)
reading.trend // 4 (numeric code)
reading.trendDirection // "Flat" (raw API string)
reading.trendDescription // "steady"
reading.trendArrow // "→"
reading.time // Date object
reading.json // raw API response objectimport {
AccountError,
AccountErrorEnum,
DexcomError,
ServerError,
} from "cgm.js"; // also available from "cgm.js/errors"
try {
const dexcom = new Dexcom({ username: "user", password: "pass" });
const reading = await dexcom.getCurrentGlucoseReading();
} catch (error) {
if (error instanceof AccountError) {
if (error.enum === AccountErrorEnum.MAX_ATTEMPTS) {
console.log("Too many attempts, try again later");
} else {
console.log("Authentication failed:", error.message);
}
} else if (error instanceof ServerError) {
console.log("Server error:", error.message);
} else if (error instanceof DexcomError) {
console.log("Dexcom error:", error.message);
}
}See API.md for complete API reference including all classes, methods, enums, constants, and error types.
npm test # run unit and type tests (Vitest)
npm run test:coverage # run tests with coverage; fails below 100%
npm run typecheck # type-check sources, tests and examples
npm run build # compile to dist/See examples/example.ts for a runnable example. After
npm run build, run it with node examples/example.ts.
Why is my password not working?
- Verify your credentials at your region's Dexcom Account Management site:
- US: uam1.dexcom.com
- Outside US: uam2.dexcom.com
- Japan: uam.dexcom.jp
- Make sure you're using the correct
regionparameter. - Format phone numbers with country code:
"+11234567890". - Use your Dexcom Share credentials, not the follower's.
- Ensure at least one follower is set up on Dexcom Share.
- Try authenticating with your
accountIdinstead ofusername.
MIT