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).
  • Show in Applications menu - checkbox, off by default (see "Adding it to your Applications menu" below). Not shown if you installed the .deb, which already adds GlucoGlance there.
  • 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: GlucoGlance normally starts by itself at login, and this adds a launcher for starting it by hand instead (e.g. after choosing Quit). It shows up in GNOME's Activities overview and app search, and from there you can drag it onto the Dock to pin it.

To add it, right-click the tray icon and tick Show in Applications menu; untick it to remove the launcher again. Search for "GlucoGlance" in the Activities overview (press the Super/Windows key and start typing) to find it.

(This writes ~/.local/share/applications/glucoglance.desktop, the standard location for per-user apps. Its Exec= line is the absolute path to the installed glucoglance script rather than the bare command, since a graphical launcher doesn't necessarily have your venv on its PATH. The app refreshes these paths on every start, so the launcher keeps working after a reinstall into a different place.)

If you installed the .deb, you don't need this - it already adds GlucoGlance to the Applications menu, so the checkbox isn't shown.

Only one copy runs at a time: launching GlucoGlance while it's already running just shows a short "GlucoGlance is already running" notice pointing at the icon in the top bar.

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.5.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.5.0
File Size Uploaded
glucoglance-0.5.0.tar.gz 90.7 kB Details

Built distribution (wheel)

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

Total release size: 174.5 kB

Release files / glucoglance-0.5.0.tar.gz

Download URL glucoglance-0.5.0.tar.gz
Size 90.7 kB
Tags Source
SHA-256 checksum
How to use checksums
16ca8f66e7ca81bad572cd969d00114008c93766808c396e952a46f19e10e899
BLAKE2b-256 checksum
How to use checksums
5590af741960d897a672578fd8729922357aa517778d8a34e173d98eaf1bbf22
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 13, 2026.

Transparency log

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

Download URL glucoglance-0.5.0-py3-none-any.whl
Size 83.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bb02f0ae9eb51425a638b315f46df4b008fe5ad16ef0f64ede9be1062df4a701
BLAKE2b-256 checksum
How to use checksums
93c3ba2a49fab7bf69cf1384fc7a421ce687edc7c795259d75faaab2900185f2
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 13, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files

0.4.0

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