Skip to main content

GlucoGlance for Ubuntu

CI

A tray widget that shows your current glucose reading (from a FreeStyle Libre sensor, via LibreLinkUp) in the Ubuntu top bar. Phase 1: just the number and trend arrow, refreshed roughly every minute. Threshold alarms are planned as a phase 2.

Illustration of an Ubuntu desktop: the top bar shows GlucoGlance's reading of 133 mg/dL in green with a steady trend arrow, next to the usual system icons, above a frosted panel with the app name, tagline, and pipx install command

The reading and trend arrow sit in the top bar like any other tray icon. The color follows your configured range: green in range, yellow high, red low.

Compatibility - please check before installing. GlucoGlance only works with:

  • Ubuntu (developed and tested on Ubuntu 24.04 with GNOME Shell 46). Windows, macOS, and other Linux distributions/desktops are not supported.
  • FreeStyle Libre sensors whose readings are shared through LibreLinkUp. Other CGMs (Dexcom, Medtronic, Eversense, etc.) are not supported.
  • A LibreLinkUp account - see Requirements below.

⚠️ Disclaimer

GlucoGlance is not a medical device. It has not been reviewed or approved by the FDA, the EMA, or any other regulator.

  • It is an unofficial, independent project. It is not affiliated with, endorsed by, or supported by Abbott. FreeStyle Libre and LibreLinkUp are trademarks of Abbott, used here only to describe what the app works with.
  • Readings may be delayed, missing or wrong. Do not use this app to make treatment decisions (e.g. insulin dosing). Always confirm with your sensor's official app or a fingerstick blood glucose meter.
  • It relies on an undocumented LibreLinkUp API that Abbott can change or block at any time, so the app may stop working without warning.
  • It is provided "as is", without warranty of any kind (see LICENSE). Use it at your own risk.

Requirements

  • Ubuntu with the default GNOME desktop (see Compatibility above).
  • A FreeStyle Libre sensor whose wearer shares their readings to LibreLinkUp from the official Libre app.
  • A LibreLinkUp follower account that has accepted that share: you log in here with the follower account's email and password.

This app cannot talk to the sensor directly - it only reads what the official Libre app has already uploaded to LibreLinkUp.

Installing on Ubuntu

Quick install (.deb package)

Download glucoglance_X.Y.Z_all.deb from the latest release, then install it with apt (the ./ matters - it tells apt this is a local file, and apt then pulls in the GTK/AppIndicator dependencies itself):

sudo apt install ./glucoglance_*_all.deb

Then launch "GlucoGlance" from the Activities overview (or run glucoglance) and skip to "Running it for the first time" below. To upgrade, install a newer .deb the same way - it doesn't update itself through apt upgrade. Remove it with sudo apt remove glucoglance.

Quick install (from PyPI, with pipx)

sudo apt install pipx python3-gi python3-gi-cairo gir1.2-gtk-3.0 gir1.2-ayatanaappindicator3-0.1
pipx ensurepath
pipx install --system-site-packages glucoglance

--system-site-packages is required: it lets the app reuse the GTK bindings installed by apt, which PyPI doesn't distribute. Open a new terminal (so pipx ensurepath takes effect) and run glucoglance - then skip to "Running it for the first time" below. Upgrade later with pipx upgrade glucoglance.

From source

These steps assume a fresh Ubuntu machine with nothing set up yet - if you've already done part of this, skip ahead.

1. Get the code:

git clone https://github.com/toabm/glucoglance-ubuntu.git
cd glucoglance-ubuntu

2. Install the system packages the tray icon needs (these come from apt, not pip - they're GTK/AppIndicator bindings that Python's package index doesn't distribute):

sudo apt install python3-venv python3-gi python3-gi-cairo gir1.2-gtk-3.0 gir1.2-ayatanaappindicator3-0.1

(If your Ubuntu/distro version ships classic AppIndicator3 instead of the Ayatana fork, install gir1.2-appindicator3-0.1 instead - the app tries Ayatana first and falls back automatically, so either works.)

3. Create a Python virtual environment and install the app into it. --system-site-packages is required here - it lets the venv reuse the python3-gi bindings you just installed with apt, instead of trying (and failing) to build them from PyPI:

python3 -m venv --system-site-packages .venv
source .venv/bin/activate
pip install .

That's the whole install. The glucoglance command now exists at .venv/bin/glucoglance (and on your PATH while the venv is activated).

Running it for the first time

With the venv activated (source .venv/bin/activate, if you're in a new terminal):

glucoglance

A small dialog pops up asking for your LibreLinkUp email and password (see Requirements above). Enter them and press OK. The email is saved to ~/.config/glucoglance/config.toml; the password is stored in your system keyring (GNOME Keyring), never in plaintext. A number should then appear in your top bar within a few seconds - that's your current glucose reading. Until then, the top bar shows GlucoGlance's own eye icon.

If no current reading is available, no number is shown: the icon turns into the same eye with a red eye white, and the top of the right-click menu says why - LibreLinkUp can't be reached, the login needs renewing, or there's no recent reading from the sensor.

You won't need to repeat this - the credentials are remembered, and (see below) the app is set to start automatically at every login by default.

Right-click the tray icon for:

  • GlucoGlance - the About dialog (version, links, disclaimer). While there's no current reading, a greyed line below it gives the reason.
  • Stop blinking (middle-click) - only shown while the icon is blinking, which it does when your reading leaves the configured range. After 20 minutes it stops blinking by itself but keeps the colored background, and this item becomes Clear highlight (middle-click). Middle-clicking the icon does the same without opening the menu. The highlight also clears by itself once the reading is back in range.
  • Start at login - checkbox, on by default (see "Running automatically at login" below).
  • Restart - reloads the app, e.g. after editing config.toml.
  • Quit.

Adding it to your Applications menu

This is separate from "start at login" below: this makes GlucoGlance show up as a proper icon in GNOME's Activities overview and app search (so you can launch it manually, or pin it to the Dock), rather than only starting silently in the background. Run this once, from the repo directory, with the venv already created as above:

test -x .venv/bin/glucoglance || { echo "Run this from the glucoglance-ubuntu directory (the venv wasn't found here)"; exit 1; }
ICON_PATH=$(.venv/bin/python3 -c "from glucoglance.ui.app_icon import app_icon_path; print(app_icon_path())")
mkdir -p ~/.local/share/applications
cat > ~/.local/share/applications/glucoglance.desktop <<EOF
[Desktop Entry]
Type=Application
Name=GlucoGlance
Exec=$(pwd)/.venv/bin/glucoglance
Icon=$ICON_PATH
Comment=Shows current blood glucose reading in the top bar
Terminal=false
Categories=Utility;
EOF

It should now appear if you search for "GlucoGlance" in GNOME's Activities overview (press the Super/Windows key and start typing). From there you can drag it onto the Dock to pin it.

(This installs into ~/.local/share/applications, the standard location for manually-installed apps - not /usr/share/applications, which is where apt/snap-installed apps land since that directory is shared across all users on the machine. GNOME scans both identically, so this works the same either way; no need to move it.)

(The Exec= line uses an absolute path to the venv you just created, rather than the bare glucoglance command, since a graphical launcher doesn't necessarily have your venv on its PATH. If you ever move the glucoglance-ubuntu folder, re-run the command above to update it.)

Configuration

Settings live at ~/.config/glucoglance/config.toml (created with defaults on first run). Notable options:

interval_seconds = 60      # how often to poll, in seconds
unit = "mgdl"               # "mgdl" or "mmol"
low_threshold_mgdl = 80     # below this, the icon turns red
high_threshold_mgdl = 180   # above this, the icon turns yellow (green in between)
color_low = "#ED4343"
color_normal = "#4DCC66"
color_high = "#F5D334"
highlight_pulse = true         # highlight (blink, then steady) after leaving the range, until acknowledged (see above)
range_hysteresis_mgdl = 5      # must come this far back inside a threshold to count as in range
autostart_enabled = true   # start automatically at login (see below)

The out-of-range highlight is purely visual - no sound, no popups - and is meant as a glanceable cue, not an alarm. range_hysteresis_mgdl stops it flickering on and off while a value hovers right at a threshold.

Edit the file and restart glucoglance for changes to take effect.

Running automatically at login

Enabled by default - on every startup the app installs (or removes) a ~/.config/autostart/glucoglance.desktop entry to match the autostart_enabled setting. That path is the standard XDG autostart location on Ubuntu (and GNOME/most other Linux desktops generally), but this project is only built and tested against Ubuntu - see "Installing on Ubuntu" above. Toggle it anytime from the tray icon's right-click menu ("Start at login"), or by editing autostart_enabled in config.toml and restarting.

That autostart entry always waits 6 seconds before actually launching the app (only on this path - running from a terminal or the Applications-menu icon starts immediately). This isn't configurable, and it's not about sensor timing: it exists purely to influence where the icon lands in the top bar. GNOME Shell's AppIndicator extension inserts each new tray icon at a fixed position rather than appending, so indicators that register later tend to end up ahead of ones that registered earlier. The delay gives your other autostart tray apps a head start, with the goal of landing this icon at the left edge of the right-side icon group (i.e. immediately after the clock, ahead of things like wifi/bluetooth/volume) - though the exact result depends on how many other apps you have and how long they take to start, so it may need tuning (edit _STARTUP_DELAY_SECONDS in config/autostart.py) to get exactly there.

Tests & linting

Tests and linting need the extra dev dependencies, which the regular install above skips:

pip install -e ".[dev]"
ruff check .                                          # lint
pytest --cov=glucoglance --cov-report=term-missing # tests + coverage

Overall coverage sits around 49% by design, not by accident: GTK/keyring- dependent code (main.py, ui/tray.py, ui/credential_prompt.py, ui/display.py, config/credentials.py) is deliberately manual-only - see CLAUDE.md's "Testing philosophy" section.

Coverage includes branches ([tool.coverage.run] branch = true in pyproject.toml, applied automatically - no extra flag needed), not just lines: a line can show as "covered" while one of its branches (e.g. one side of an if) was never actually exercised, so branch coverage catches real gaps line coverage hides.

If your IDE flags gi.repository symbols (e.g. GLib, Gtk) as unresolved, that's expected - PyGObject generates those modules dynamically from typelibs at runtime, not from real .py files, so static analyzers can't see them without type stubs. Install those separately from dev (pip otherwise tries to rebuild the real PyGObject/pycairo from source to satisfy this package's declared dependency, and fails without cairo/girepository dev headers):

pip install --no-deps PyGObject-stubs

Continuous integration

Every push to develop/master and every pull request runs ruff and the full test suite (.github/workflows/ci.yml), publishing a test report and a coverage summary (including diff/patch coverage on PRs) as a PR comment. master is protected: it only accepts changes through a pull request, and the "Lint & Test" check must pass before merging.

For PRs opened from a fork, the test/coverage report job is skipped - GitHub gives fork PRs a read-only token, so it couldn't post its comment anyway. "Lint & Test" still runs, and its log shows the full results.

Project layout

  • client/ - talks to the LibreLinkUp API.
  • domain/ - plain data types (readings, trend, unit conversion), no I/O.
  • poller/ - background polling loop; publishes events on an EventBus.
  • alerts/ - placeholder for phase 2 threshold alarms.
  • ui/ - the tray display, built behind a small Display interface so other frontends (e.g. a floating window) can be added later.
  • config/ - settings (TOML) and credentials (system keyring).

Why the number is drawn as an icon, not a tray label

AppIndicator has a built-in feature for showing text next to the tray icon (a "label"). On this project's target environment (GNOME Shell 46 + ubuntu-appindicators), that feature silently doesn't render anything, even though the app publishes it correctly - a Shell-extension bug, not something fixable from the app side. Instead, ui/icon_renderer.py draws the reading as a small bitmap and that image becomes the tray icon itself, which does render reliably. If a future Shell/extension update fixes label rendering, this could be simplified back to set_label().

Privacy

  • Your LibreLinkUp password is stored only in your system keyring (GNOME Keyring), never in a plain file. Your email is stored in ~/.config/glucoglance/config.toml.
  • The app talks only to Abbott's LibreLinkUp servers. It has no server of its own, no analytics and no telemetry, so your readings and credentials never go anywhere else.
  • Tray menu → Log out deletes the stored password and email.

Contributing

Bug reports and pull requests are welcome - see CONTRIBUTING.md.

License

MIT - see LICENSE.

Metadata

Release files for glucoglance 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for glucoglance 0.4.0
File Size Uploaded
glucoglance-0.4.0.tar.gz 119.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for glucoglance 0.4.0
File Interpreter ABI Platform
glucoglance-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 232.6 kB

Release files / glucoglance-0.4.0.tar.gz

Download URL glucoglance-0.4.0.tar.gz
Size 119.7 kB
Tags Source
SHA-256 checksum
How to use checksums
79717a227489e67fb11b825c970599635958b2b1724a7b7d6128f512cbd70535
BLAKE2b-256 checksum
How to use checksums
782967c0dcf4487cde04370cd08f1c3d3612294f8a14f330ff46164802e9498c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release files / glucoglance-0.4.0-py3-none-any.whl

Download URL glucoglance-0.4.0-py3-none-any.whl
Size 112.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8953efe29932b425a7a2111ada7289b45f1bb8d907395b8837ea7d9cf69c338d
BLAKE2b-256 checksum
How to use checksums
d79812a7852f220c7d398d03aedcd77f774de429312f4ee026eb73239877b839
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release history Release notifications | RSS feed

0.5.0

2 release files

This release

0.4.0 This release

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page