Docker container for exporting Dexcom G6 blood sugar data to Prometheus + a Grafana dashboard
  • Python 84%
  • Makefile 12%
  • Dockerfile 4%
Find a file
Karl E. Jorgensen 975ecea238
All checks were successful
Standard Build / build (push) Successful in 7m35s
README.md: better prometheus query
2026-01-22 09:49:20 +00:00
.forgejo/workflows
.github/workflows
config
.dockerignore
.gitignore
docker-compose.yaml
Dockerfile
LICENSE.txt
main.py
Makefile
README.md README.md: better prometheus query 2026-01-22 09:49:20 +00:00
requirements.txt
sample.env

Dexcom Exporter Container

A container for exporting glucose data from a Dexcom blood glucose monitor via the Dexcom API to Prometheus

It should support all the Dexcom supported by the underlying pydexcom library.

This was initially forked from https://github.com/downtime-industries/dexcom-dashboard, and has undergone multiple modifications since. It should generally be compatible with the upstream container, but this is not guaranteed.

Each time it is scraped it will only report newer data: old data will never be repeated. The exporter tracks the timestamp of the last glucose reading taken (upon startup it may report older readings to "catch up"). This also works to "catch up" if e.g. the user loses connectivity for a while.

As a result: If the exporter is being scraped by multiple prometheus instances, each prometheus instance will see "gaps" in the data (although the "total picture" will be correct). If you need the redundancy of multiple prometheuses: run multiple instances of the collector too.

Environment Variables

The container expects a few environment variables to be set:

  • DEXCOM_USERNAME: username for the Dexcom Share user (not the follower)
  • DEXCOM_PASSWORD: password for the Dexcom Share user. For more info about diagnosing authentication issues see the pydexcom FAQ
  • DEXCOM_REGION: (optional - defaults to us) the region to use: one of us, ous or jp. Note that using the wrong region will result in authentication failing
  • PROMETHEUS_PORT: (optional - defaults to 8000) TCP port number to listen on. Prometheus is expected to request metrics from here.

Re: Regions: Dexcom seems to split the world into 3 regions:

  • us: the USA
  • jp: Japan
  • ous: Everthing else ("outside the US"?, but Japan is neither inside nor outside the US?)

I.e. their naming is not consistent and does not follow commonly used standards.

Metrics Exposed

Since the exporter is written in Python, it will also expose some metrics about the python process itself. The client_python should document those...

The exact name of the glucose metrics have changed over time; the current preferred metric names include the full unit in which the data is represented. The old names have been kept for backward compatibility, but will eventually be removed.

Regardless of the frequency of scraping, the actual frequency of new data points becoming available is completely dependent on how often the underlying Dexcom API provides new data from the Dexcom servers (which in turn depends on whether the data reach the Dexcom servers from the user). This appears to be one data point every 5 minutes, but may vary between different device models.

Every request for metrics will result in a call to the Dexcom API to query for new data, so scraping for data every 30 seconds is probably excessive. It is far more reasonable to scrape every 60 or 120 seconds: This will still give usable data without undue delay and avoids excessive strain on the Dexcom servers.

When the exporter is scraped but no new data is available from the Dexcom servers: this will be logged from the container:

Dexcom just repeated the last reading. Either no new actual readings, or scrape interval too tight.

which can be used as a hint for decreasing the scraping frequency.

glucose_value

Gauge: Current glucose value in mg/dl (OBSOLETE: Use glucose_mg_dl instead)

glucose_mg_dl

Gauge: Current glucose value in units of mg/dl

glucose_mmol

Gauge: Current glucose value in mmol/L (OBSOLETE: Use glucose_mmol_l instead)

glucose_mmol_l

Gauge: Current glucose value in mmol/L

trend_direction

Gauge: Current trend direction as numeric value (not obsolete, but inconvenient)

In prometheus terms, this is an oddball metric trying to represent the "trend arrow" as seen in the Dexcom App:

  • 0: None
  • 1: DoubleUp
  • 2: SingleUp
  • 3: FortyFiveUp
  • 4: Flat
  • 5: FortyFiveDown
  • 6: SingleDown
  • 7: DoubleDown
  • 8: NotComputable
  • 9: RateOutOfRange

Unfortunately, the dexcom API documentation is vague about over which timeframe the trend arrow is calculated and exactly which conditions result in which arrow.

We recommend to use prometheus queries to calculate the trend over the desired interval instead. A prometheus query like

(avg by (dexcom_username) (glucose_mmol_l)) - (avg by (dexcom_username) (glucose_mmol_l offset 5m))

will give the change of glucose level over the previous 5 minutes (in units of mmol/litre). Try out the expression in the Prometheus web console first.

Note that a simple query like:

glucose_mmol_l - (glucose_mmol_l offset 5m)

would mostly work too - but it will result in multiple series in the result if e.g. the container is replaced (as Prometheus usually add pod, container and endpoint labels), and a "break" between the two series at the time the container was replaced.

Running with docker-compose

To start it you will need to copy the sample.env to a file called .env. Put in your Dexcom login credentials and run docker compose up

This will start 3 services.

  1. Dexcom-Monitor - A container that runs the the main.py file that reads glucose levels every 5 minutes
  2. Prometheus - Service that collects the glucose measurements from Dexcom-Monitor and stores them
  3. Grafana - Visualization for the data with thresholds

Running in Kubernetes

See https://code.jorgensen.org.uk/karl/dexcom-exporter