Observability

How SafeCircle measures the health of its services, which metrics exist, and how analytics collection works and can be turned off.

3 min read

SafeCircle measures two things: how healthy the backend is, and, anonymously, how the dashboard is used. Neither involves user IDs, emails or IP addresses.

 Dashboard ──(anonymous events)──┐
                                 ▼
 Every API request ───────►  Cloudflare D1  ◄── GET /api/telemetry/metrics
 (method, route, status,      (requests,            (Prometheus text,
  duration)                    events)               secret-protected)
                                                         │ scrape, every 60 s
                                                         ▼
                                              Prometheus ──► Grafana

What is collected

SourceStored inContents
Request metricsD1 table requestsTime, HTTP method, route path, status code, duration in milliseconds
Product eventsD1 table eventsEvent name, page route, up to 10 filtered properties, time

Telemetry requests (/api/telemetry/event and /api/model-feedback) are not counted in request metrics.

Events

The dashboard sends a small set of events:

EventWhen
page_viewA page is opened
filter_appliedA filter is used on a list
alert_readAn alert is opened, with its category, risk level and source app
mark_all_readAll alerts are marked read

The metrics endpoint also aggregates funnel and playground events (for example inference_run, sign_up, child_added, device_paired). Other SafeCircle clients, such as the AI Playground, can send these.

The backend removes any property whose key matches an identifier-like word (id, email, user, token, name, ip, phone) and keeps at most 10 properties per event. Events are batched in the browser and sent about every 10 seconds, and when the tab is hidden.

Opt out

In the dashboard, open Settings › Security › Privacy and switch off Share anonymous usage analytics. The choice is saved in your browser's local storage under sc_analytics_optout. When it is set, the dashboard sends no events and drops any that were queued.

If you build a client, call POST /api/telemetry/event only when the user has not opted out. See the API reference.

The metrics endpoint

GET /api/telemetry/metrics returns the aggregated data in Prometheus text format. It requires Authorization: Bearer <secret>, which only SafeCircle operators hold. All metrics are gauges whose names start with sc_.

GroupExamples
Worker healthsc_requests_total_24h, sc_error_rate_24h, sc_latency_p95_24h_ms, sc_requests_by_route, sc_requests_by_status
Product analyticssc_pageviews_total_24h, sc_feature_usage_24h, sc_funnel_signup_7d, sc_onboard_complete_7d
Playground analyticssc_playground_inferences_24h, sc_playground_inferences_by_model, sc_playground_ratings
Message analyticssc_alert_reads_24h, sc_alert_reads_by_category_24h, sc_alert_reads_by_risk_24h

Windows are 1 hour, 6 hours, 24 hours or 7 days. Alert metrics count alert-read events from the dashboard, not rows in the alerts table.

The Grafana stack

The observability repository is a Docker Compose stack:

ServiceRole
PrometheusScrapes the metrics endpoint every 60 seconds and keeps 30 days of history
GrafanaDashboards, provisioned automatically from files

Four dashboards are provisioned: Worker Health, Product Analytics, Message Analytics and Playground Analytics. Grafana sign-up is disabled.

To run it against your own deployment, put your metrics secret in the Prometheus scrape config, set the Grafana admin password through the GRAFANA_PASSWORD environment variable, and run:

docker compose up -d

Grafana is then on port 3000 and Prometheus on port 9090.

Logs

The backend Worker has Cloudflare's built-in observability enabled for logs and errors. Unhandled errors are logged on the server and never returned to clients. SafeCircle Search turns observability off entirely so that queries cannot reach logs.