GlucoGlance for Ubuntu
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.
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 (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.
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:
- 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"
autostart_enabled = true # start automatically at login (see below)
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 anEventBus.alerts/- placeholder for phase 2 threshold alarms.ui/- the tray display, built behind a smallDisplayinterface 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.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| glucoglance-0.3.1.tar.gz | 108.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| glucoglance-0.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 211.7 kB
Release files / glucoglance-0.3.1.tar.gz
| Download URL | glucoglance-0.3.1.tar.gz |
|---|---|
| Size | 108.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
544577c172ec4fbab641f39a7e8ee3d644eab0fe8c59a6f65ddc2edeb17c325b
|
|
BLAKE2b-256 checksum How to use checksums |
2fd8623eb2244894f4778067d84bb7d474e904a442f06931965f4525a6ad95bb
|
| 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 Sep 23, 2026.
Transparency logRelease files / glucoglance-0.3.1-py3-none-any.whl
| Download URL | glucoglance-0.3.1-py3-none-any.whl |
|---|---|
| Size | 103.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0772b5eeb55f9a3bf94603537574d9a9c0c172c97b10552d66d42a57814733af
|
|
BLAKE2b-256 checksum How to use checksums |
6872046fd70aeafb1b7f14b91bef29bfc6ddd89a163c02eff04ae2611b057fbf
|
| 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 Sep 23, 2026.
Transparency log