Repository navigation
feat(analytics): built-in usage analytics with churn and retention, and optional Google Analytics export - #274
Merged
Merged
Conversation
…oogle Analytics events Lens works out daily, weekly and monthly active people, stickiness, churn, retention by sign-up week and feature use from the activity ledger and sign-ins (GET /api/v1/admin/analytics). Google Analytics 4 is off by default: with a measurement id and API secret (Settings, the setup wizard's telemetry step, or .env) one process sends a documented set of counted events once a day for the install, never personal content. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsT2KQQsLmAyBFPRxw1VVH
…ogle Analytics opt-in Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsT2KQQsLmAyBFPRxw1VVH
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsT2KQQsLmAyBFPRxw1VVH
… locally The daily events are counted and kept on the server whether or not Google Analytics is on; GA is an optional export of them. A new Analytics page (admins) shows active people, churn, retention, feature use and the event log for 7 to 180 days. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsT2KQQsLmAyBFPRxw1VVH
…-ktxyn6 # Conflicts: # fastapi_backend/app/domain/settings.py # mkdocs.yml
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsT2KQQsLmAyBFPRxw1VVH
…-ktxyn6 # Conflicts: # CHANGELOG.md # docker-compose.prod.yml # docs/configuration.md # fastapi_backend/.env.example # fastapi_backend/app/api/v1/routes/admin.py # fastapi_backend/app/domain/ops_tools.py # fastapi_backend/app/domain/routines.py # fastapi_backend/app/domain/settings.py # fastapi_backend/app/schemas/admin.py # mkdocs.yml # nextjs-frontend/app/openapi-client/index.ts # nextjs-frontend/app/openapi-client/sdk.gen.ts # nextjs-frontend/app/openapi-client/types.gen.ts # nextjs-frontend/components/settings/bodies.tsx # nextjs-frontend/components/settings/model.ts # nextjs-frontend/components/settings/settings-shell.tsx # nextjs-frontend/openapi.json # threat-model.md # threat-model.yaml
…-ktxyn6 # Conflicts: # CHANGELOG.md # fastapi_backend/app/domain/ops_tools.py # nextjs-frontend/components/settings/model.ts # threat-model.yaml
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsT2KQQsLmAyBFPRxw1VVH
Merged
16 of 22 tasks
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HsT2KQQsLmAyBFPRxw1VVH
adeelahmad
enabled auto-merge (squash)
October 15, 2026 07:40
Merged
16 of 22 tasks
adeelahmad
added a commit
that referenced
this pull request
Oct 15, 2026
…pages and notes as built (#424) Move usage analytics (#274) and assets and people (#273) out of the README's In progress list, and add what merged since #383: a namespace's own MCP server, chat completions and one-namespace API keys; editing and merging entities and topics with undo, from agents too; entity pages at wiki addresses; Connect with Google and rclone sign-in on the server; the notes tree, today's note, pins, search and Recently deleted; backups that keep Lens's files; and grouped, searchable settings. In progress now lists the open feature PRs (#398, #400, #402, #408, #419), and the docs index links usage analytics. Claude-Session: https://claude.ai/code/session_01HDx7PPUauyjMn1LZs8JAsS Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Adeel · project thread
Description
Before: Lens had opt-in OpenTelemetry only. Nothing told an admin how many people use Lens, who stopped using it, or which features get used.
After:
Built-in Analytics page (
/analytics, admin-only, in the nav). For 7, 30, 90 or 180 days it shows:The numbers come from the activity ledger and sign-ins (
GET /api/v1/admin/analytics). Nothing new is collected for them.Daily events kept locally, whether or not GA is on:
lens_install,lens_setup_done,lens_daily_active,lens_feature_used,lens_upgrade,lens_inactive(the uninstall-like signal) andlens_return. They are stored inusage_eventand served atGET /api/v1/admin/analytics/events.Google Analytics 4 is an optional export, off by default. Turn it on in Settings → Usage analytics, in the setup wizard's telemetry step, or with
LENS_ANALYTICS/LENS_GA_MEASUREMENT_ID/LENS_GA_API_SECRET. The events are then also sent through the Measurement Protocol. They carry counts only, never personal content. Settings lets you choose which events are sent, EU-only collection, and the number of days before an install counts as inactive. It also shows the status of the last send and has a test that uses GA's validation server. A failed send is retried 10 minutes later. Events kept while GA was off are never sent later.How:
app/domain/analytics.pycontains the metrics, the event catalog and a daily tick. The tick runs fromroutines.run_dueand is claimed by one process per day. It is followed by the GA sender. The setup assistant always asks before changinganalytics.Motivation and Context
Adeel asked for Google Analytics telemetry with churn rate and other events configured and calculated, then for built-in analytics. Docs:
docs/analytics.md.Types of changes
Checklist:
tests/api/test_analytics.py,__tests__/analyticsPage.test.tsx,__tests__/setupWizard.test.tsx).docs/accordingly.## UnreleasedinCHANGELOG.md.Done questions (AGENTS.md)
/admin/analytics,/admin/analytics/events,/settings/analytics/*), and the setup assistant can changeanalytics(always with approval).analytics.*setting is in Settings with a default. The wizard's opt-in is part of the existing telemetry step and is off by default.usage_eventtable and anapp_service:analyticsrow, both created on first use; no change to existing data.docs/analytics.mdlabels it built and lists what to refine later.make openapi) updated.docs/analytics.md.🤖 Generated with Claude Code
https://claude.ai/code/session_01HsT2KQQsLmAyBFPRxw1VVH