Backend Telemetry¶
OpenContracts backend uses PostHog to collect anonymous usage telemetry. This data helps guide development priorities by understanding how the platform is used.
What We Collect¶
Backend telemetry records the following events:
Periodic Events¶
| Event | Description | Frequency | Properties |
|---|---|---|---|
usage_heartbeat | Aggregate usage statistics | Daily | See below |
The usage_heartbeat event includes: - user_count — Active users - document_count — Non-deleted documents - corpus_count — Total corpuses - annotation_count — User annotations (excludes structural) - conversation_count — Active conversations/threads - message_count — Active messages - version — OpenContracts version - installation_age_days — Days since installation
Real-time Events¶
| Event | Description | Properties |
|---|---|---|
user_created | A new user account is created | user_count (total users) |
document_uploaded | A document is uploaded | user_id, env |
All events include: - installation_id — Unique anonymous identifier for your installation - timestamp — When the event occurred - package — Always opencontracts
What We Do NOT Collect¶
- Document contents or filenames
- User identities, emails, or personal information
- Extracted data or annotations
- Query contents or search terms
- IP addresses or location data
Configuration¶
Backend telemetry is controlled by environment variables in your Django settings:
| Variable | Default | Description |
|---|---|---|
TELEMETRY_ENABLED | True | Master switch for backend telemetry |
POSTHOG_API_KEY | (set) | PostHog project API key |
POSTHOG_HOST | https://us.i.posthog.com | PostHog API endpoint |
Disabling Telemetry¶
To disable backend telemetry, set the environment variable:
TELEMETRY_ENABLED=False
Or in your .env file:
TELEMETRY_ENABLED=False
When disabled, no events are sent to PostHog and no data leaves your server.
Technical Details¶
- Location:
config/telemetry.py - Singleton client: PostHog client is lazily initialized and reused
- Async sending: Events are queued and sent asynchronously by a background thread
- Graceful shutdown: An
atexithandler ensures pending events are flushed on process exit - Test mode: Telemetry is automatically disabled when
MODE=TEST
Periodic Task Setup¶
The daily usage_heartbeat task is automatically configured when you run migrations:
python manage.py migrate
This creates a PeriodicTask entry in django-celery-beat's database scheduler. The task: - Runs daily at midnight UTC - Is only created if TELEMETRY_ENABLED=True at migration time - Can be managed via Django admin under "Periodic Tasks"
Requirements: Celery Beat must be running for periodic tasks to execute:
celery -A config.celery_app beat --loglevel=info
Implementation¶
Events are recorded via the record_event() function:
from config.telemetry import record_event
# Record an event with properties
record_event("my_event", {"property": "value"})
The function returns True if the event was queued successfully, False otherwise. It never raises exceptions to avoid disrupting normal operations.