8000 feat(analytics): built-in usage analytics with churn and retention, and optional Google Analytics export by adeelahmad · Pull Request #274 · adeelahmad/lense · GitHub
[go: up one dir, main page]

Skip to content

feat(analytics): built-in usage analytics with churn and retention, and optional Google Analytics export - #274

Merged
adeelahmad merged 10 commits into
mainfrom
claude/project-thread-ktxyn6
Oct 15, 2026
Merged

adeelahmad merged 10 commits into
mainfrom
claude/project-thread-ktxyn6

Conversation

@adeelahmad
@adeelahmad adeelahmad commented Oct 10, 2026 •
Copy link
Copy Markdown
Owner

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:

    • daily, weekly and monthly active users, and stickiness;
    • churn rate (the previous period compared with this one), retained and returning users;
    • weekly retention cohorts by sign-up week;
    • feature use, and a chart of daily active users;
    • the event log.

    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) and lens_return. They are stored in usage_event and served at GET /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.py contains the metrics, the event catalog and a daily tick. The tick runs from routines.run_due and is claimed by one process per day. It is followed by the GA sender. The setup assistant always asks before changing analytics.

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

  • New feature (non-breaking change which adds functionality)

Checklist:

  • The title is a Conventional Commit.
  • My code follows the code style of this project (pre-commit passes).
  • I added or updated tests (tests/api/test_analytics.py, __tests__/analyticsPage.test.tsx, __tests__/setupWizard.test.tsx).
  • My change requires documentation updates, and I have updated docs/ accordingly.
  • Users need more than the title to understand it, so I wrote it under ## Unreleased in CHANGELOG.md.

Done questions (AGENTS.md)

  • Goal: GA telemetry with churn and other events computed and configured, plus built-in analytics. Merged on green CI.
  • Agents: everything is available through the API (/admin/analytics, /admin/analytics/events, /settings/analytics/*), and the setup assistant can change analytics (always with approval).
  • Zero setup: the numbers and the event log work right after install; GA needs only an id and a secret, entered in the web app.
  • Fewest clicks: one nav item; the period is a single segmented choice.
  • Configurable: every 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.
  • Light: no new dependency; it is one small query a day plus on-demand queries over the existing ledger.
  • Private and secure: GA is off by default and sends counts only, under a random install id; the API secret is sealed; the threat model is updated.
  • Cost: no model calls.
  • User decides: nothing leaves the machine until an admin turns GA on; existing defaults are unchanged.
  • Upgrades: only a new usage_event table and an app_service:analytics row, both created on first use; no change to existing data.
  • Honest: docs/analytics.md labels it built and lists what to refine later.
  • Tests, docs and generated files (make openapi) updated.
  • Open standards: plain HTTP, MIT unchanged.
  • Result reported in the project thread; "Refine later" is in docs/analytics.md.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HsT2KQQsLmAyBFPRxw1VVH

…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
@adeelahmad adeelahmad self-assigned this Oct 10, 2026
…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
@adeelahmad adeelahmad changed the title feat(analytics): usage metrics with churn and retention, and opt-in Google Analytics events feat(analytics): built-in usage analytics with churn and retention, and optional Google Analytics export Oct 10, 2026
…-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
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HsT2KQQsLmAyBFPRxw1VVH
@adeelahmad
adeelahmad enabled auto-merge (squash) October 15, 2026 07:40
@adeelahmad
adeelahmad merged commit 3c13ba4 into main Oct 15, 2026
6 of 17 checks passed
@adeelahmad
adeelahmad deleted the claude/project-thread-ktxyn6 branch October 15, 2026 07:41
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

0