↖️ Blog Archive

Dexcom Unfollow

Bradley Gannon

2025-12-11

TL;DR: I figured out how to extract real-time blood glucose data from the Dexcom Follow app. The solution involves running a virtual Android device under Waydroid and using adb to pull the current glucose measurement directly out of the UI. I also set up a ntfy.sh server on my VPS so I can send push notifications to my phone when the sugar measurement is above or below certain thresholds.

By the way, please don’t rely on this system to keep anyone alive. I built this in a week for fun.

The Problem

A person I care about has type 1 diabetes (T1D). (From now on I’ll refer to them as The Subject.) T1D is a medical condition where, in their case, the immune system decides to destroy the pancreas. The pancreas is an organ that produces insulin, which is vital for processing sugar. Since T1Ds can’t produce insulin on their own, they need to inject insulin periodically or they die. Fortunately, The Subject has a continuous glucose monitor (CGM) and an automatic insulin pump, which respectively measure their blood glucose level every five minutes and inject small amounts of insulin to compensate for food intake and activity.

The CGM is made by a company called Dexcom, and they have a system in place where the CGM’s data can make it to the web via the user’s phone. Then, the user can choose to share a live feed of their CGM data with trusted people via a phone app called Dexcom Follow. The Subject has chosen to share their CGM data with me, so I can run the Follow app and get notifications when their sugar is outside a safe range. This is important because it allows me to help them recover if their hypo- or hyperglycemic episode incapacitates them or they’re sleeping.

So far, none of this is a problem, except insofar as a chronic autoimmune disorder is problematic. The system mostly works fine and is an acceptable, if annoying, approximation of the real thing. The “problem” is due to my own technology choices and values. You see, fair reader, the Follow app runs on Android, but only on those Android devices that have Google Play Services (GPS) available. I run GrapheneOS on my phone, which doesn’t ship GPS by default but can enable them as a sandboxed app. I have a few apps that I want to be able to run with GPS enabled, but I don’t like the idea of GPS running all the time, so I sequester these apps in their own special profile with GPS enabled. This is fine, but it’s inconvenient to receive the notifications in my main profile, and the GPS profile drains my phone’s battery much more quickly, so I tend to leave it logged out.

What I really want is for the app to not require GPS. But, failing that, I would be happy with a way to get the data out of Dexcom Follow so I can do whatever I want with it. That’s what this project is about.

My Solution

I have a mostly-working solution to this problem. I set up a system where a virtual Android device runs on one of my servers in a headless configuration, and every minute I use adb to dump the current view as an XML document. The UI element that contains the latest glucose measurement has a particular location and key in this document, so I can reliably extract it with xq. Then I feed the measurement into a Schmitt trigger-style state machine to determine whether a notification is needed. If so, then the script pushes a notification to my phone using my own ntfy.sh server.

The script that does most of it is here with sensitive information replaced with TODOs. As for system setup, there’s a lot more to it. Here’s an informal list of steps:

  1. Install Waydroid. This solution probably works with any Android system that can run GPS and support an adb connection, although it might not be headless. If you do use Waydroid, be sure to install the GAPPS image using waydroid init -s GAPPS. For configuration, it’s fine to run Waydroid in normal GUI mode. The headless setup is just for convenience.
  2. Register your device with your Google account. This is unavoidable, but at least this arrangement helps to separate Google from your personal data a bit.
  3. Sign in to your Google account to install Dexcom Follow or source an APK from elsewhere and install it.
  4. Configure Waydroid to use a virtual screen that’s taller than it is wide. Dexcom Follow doesn’t play nicely with landscape screens when it expects to be running in portrait mode.
  5. Install Weston and start it with the headless backend and a custom socket name (e.g., weston --backend=headless --socket=wayland-waydroid --width=576 --height=1024).
  6. Restart Waydroid and set the WAYLAND_DISPLAY environment variable to the socket name from the previous step.
  7. Run the script linked above or your own logic. The script as written requires adb, bash, curl, and xq and writes all glucose data to $script_dir/data.csv.

At some point I’ll probably wrap all this up into a systemd service. For now it’s just running in a few panes under tmux. The hard part of making it into a service is probably going to be managing multiple processes at the same time. bash might not be the best choice for that.

Also Tried

My original plan was to intercept traffic between the app and its server to try to reverse-engineer the API. That would have allowed me to run a completely independent client by replicating the app’s behavior. There has been lots of work on this already, but I discarded the idea for three reasons:

  1. This approach violates the ToS for the Dexcom platform (see section 5.11), which normally I wouldn’t care about. However, this could potentially make someone at Dexcom upset enough to mess up service for The Subject, which is an unacceptable risk. My current solution also probably violates the ToS, but it’s harder to detect and is less intrusive, so The Subject and I agree that it’s a reasonable way to go.
  2. Intercepting Android traffic is pretty complicated and annoying. I guess that’s a good thing, but in this case it’s frustrating. I did manage to intercept and decrypt some traffic from a Waydroid container using mitmproxy, but this required rooting the device to install a new root certificate in the system store. Dexcom Follow has root detection, though, and refused to operate after I completed the cert installation. I suppose this is defensible behavior, but again frustrating. I might have been able to root the phone, install the cert, and then unroot, but meh.
  3. It’s likely that the API will change over time, which would probably break my workflow periodically. I’d have to repeat this entire process again in that case. Using the app makes it much less likely that a breaking change will happen, and when it does it’ll be easier to fix. In the worst case, I’d probably just need to reidentify the XML node that contains the glucose measurement if the app updates its UI.

I briefly set up a solution where I used adb to dump a screenshot of the current view. Then I cropped it with ImageMagick and ran OCR with Tesseract to try to extract the glucose measurement. This worked most of the time but would sometimes fail in weird ways, which in hindsight isn’t too surprising. Using adb to dump the view as semantic data rather than pixels was the final improvement that made the system reliable enough for normal use.