From 7d2012a82c3a1619f87553e2a51a836bd2cb445c Mon Sep 17 00:00:00 2001 From: phernandez Date: Mon, 2 Mar 2026 19:24:10 -0600 Subject: [PATCH] fix(cli): fix Umami analytics event delivery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three issues prevented CLI analytics from reaching the Umami dashboard: 1. Wrong API endpoint — cloud.umami.is rejects /api/send, the JS tracker uses api-gateway.umami.dev 2. Missing "type": "event" top-level field required by Umami v2 API 3. Non-browser User-Agent ("basic-memory-cli/...") triggers Umami's bot detection, which silently drops events with {"beep":"boop"} 🤖 4. Daemon thread was killed before HTTP request completed on fast commands Co-Authored-By: Claude Opus 4.6 Signed-off-by: phernandez --- src/basic_memory/cli/analytics.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/basic_memory/cli/analytics.py b/src/basic_memory/cli/analytics.py index 5b93a7cd..f1cd71c1 100644 --- a/src/basic_memory/cli/analytics.py +++ b/src/basic_memory/cli/analytics.py @@ -25,7 +25,7 @@ import basic_memory # Configuration — defaults baked in, overridable via environment # --------------------------------------------------------------------------- -_DEFAULT_UMAMI_HOST = "https://cloud.umami.is" +_DEFAULT_UMAMI_HOST = "https://api-gateway.umami.dev" _DEFAULT_UMAMI_SITE_ID = "f6479898-ebaf-4e60-bce2-6dc60a3f6c5c" @@ -76,7 +76,9 @@ def track(event_name: str, data: Optional[dict] = None) -> None: host = _umami_host() site_id = _umami_site_id() + # Umami v2 /api/send requires "type" at top level alongside "payload" payload = { + "type": "event", "payload": { "hostname": "cli.basicmemory.com", "language": "en", @@ -87,7 +89,7 @@ def track(event_name: str, data: Optional[dict] = None) -> None: "version": basic_memory.__version__, **(data or {}), }, - } + }, } def _send(): @@ -97,11 +99,16 @@ def track(event_name: str, data: Optional[dict] = None) -> None: data=json.dumps(payload).encode("utf-8"), headers={ "Content-Type": "application/json", - "User-Agent": f"basic-memory-cli/{basic_memory.__version__}", + # Umami's bot detection rejects non-browser User-Agents + "User-Agent": "Mozilla/5.0 (compatible; BasicMemoryCLI/" + f"{basic_memory.__version__})", }, ) urllib.request.urlopen(req, timeout=3) except Exception: pass # Never break the CLI for analytics - threading.Thread(target=_send, daemon=True).start() + # Non-daemon so the process waits for the request to complete. + # The 3s urllib timeout caps the worst-case exit delay. + t = threading.Thread(target=_send) + t.start()