Skip to content

Add anonymous usage telemetry (Homebrew-style opt-out) #477

@phernandez

Description

@phernandez

Summary

Add anonymous usage telemetry to Basic Memory using OpenPanel. Following the Homebrew analytics model: on by default with easy opt-out.

Motivation

We want to understand:

  • What versions are in use
  • What features are being used (MCP tools, CLI commands)
  • What errors users encounter
  • OS/Python version distribution

PyPI stats are unreliable, and we have no visibility into actual usage patterns.

Design Decisions

Decision Choice Rationale
Backend OpenPanel Cloud Open source, privacy-first, Python SDK, $20/mo for 5K-100K events
Default ON (opt-out) Homebrew model - get meaningful data, easy to disable
Identification Random UUID Stored locally at ~/.basic-memory/.install_id, user can delete
First run One-time notice Not a prompt - just inform, then never show again

What We'll Track

Events

Event Properties Purpose
app_started mode: "cli" | "mcp" Active usage
mcp_tool_called tool: str Feature popularity
cli_command command: str CLI usage patterns
sync_completed entity_count, duration_ms Performance baseline
error type, message (sanitized) Bug prioritization
import_completed source: str Import feature usage

Global Properties (every event)

  • app_version
  • python_version
  • os (darwin/linux/windows)
  • arch (arm64/x86_64)
  • install_id (random UUID)

What We NEVER Collect

  • Note content
  • File names or paths
  • Personal information
  • IP addresses (OpenPanel doesn't store these)

User Experience

First Run Notice (shown once)

Basic Memory collects anonymous usage statistics to help improve the software.
This includes: version, OS, feature usage, and errors. No personal data or note content.
To opt out: bm telemetry disable
Details: https://memory.basicmachines.co/telemetry

CLI Commands

bm telemetry disable  # opt out
bm telemetry enable   # opt back in  
bm telemetry status   # show current state + what's collected

Environment Variable

export BASIC_MEMORY_TELEMETRY_ENABLED=false  # disable via env

Implementation

Files to Create

File Description
src/basic_memory/telemetry.py Core telemetry module (client, track function, notice)
src/basic_memory/cli/commands/telemetry.py CLI commands (enable/disable/status)
tests/test_telemetry.py Unit tests

Files to Modify

File Changes
pyproject.toml Add openpanel dependency
src/basic_memory/config.py Add telemetry_enabled (default True), telemetry_notice_shown fields
src/basic_memory/cli/commands/__init__.py Register telemetry module
src/basic_memory/cli/main.py Import telemetry commands
src/basic_memory/mcp/server.py Add startup tracking + show notice
src/basic_memory/cli/app.py Add startup tracking + show notice
MCP tool files Add track() calls
CLI command files Add track() calls

Core Module (telemetry.py)

"""Anonymous telemetry for Basic Memory (Homebrew-style opt-out)."""

import platform
import uuid
from pathlib import Path

from openpanel import OpenPanel

from basic_memory import __version__
from basic_memory.config import ConfigManager

_client: OpenPanel | None = None

def get_install_id() -> str:
    """Get or create anonymous installation ID."""
    id_file = Path.home() / ".basic-memory" / ".install_id"
    if id_file.exists():
        return id_file.read_text().strip()
    install_id = str(uuid.uuid4())
    id_file.parent.mkdir(parents=True, exist_ok=True)
    id_file.write_text(install_id)
    return install_id

def track(event: str, properties: dict | None = None) -> None:
    """Track an event. Fire-and-forget, never raises."""
    try:
        get_client().track(event, properties or {})
    except Exception:
        pass  # Telemetry must never break the app

Documentation

Create a page at https://memory.basicmachines.co/telemetry documenting:

  • Exactly what we collect
  • What we never collect
  • How to disable
  • How to delete your data (delete ~/.basic-memory/.install_id)

Testing Strategy

  1. Unit tests for telemetry module (mock OpenPanel client)
  2. Verify opt-out disables tracking
  3. Verify notice only shows once
  4. Test env var override works
  5. Integration test for CLI commands

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions