Skip to main content

User Analytics

Build live dashboards on your gateway traffic, share them across teams, and get notified the moment something is off — all natively inside Otoroshi.

User Analytics ships with a dedicated PostgreSQL data exporter, a curated catalogue of queries, a grid of beautiful charts, and a threshold-based alert engine. No external observability stack to plug, no extra UI to learn — it lives where your routes, APIs and apikeys already do.

What you get

  • Custom dashboards built from a rich grid of widgets — line, area, bar, pie, donut, big numbers, tables, heatmaps
  • A point-and-click widget editor — pick a query, set a threshold, drop it on the grid
  • Drag & drop reordering so dashboards stay tidy as they grow
  • Adaptive time ranges — pick a preset (1h / 6h / 24h / 7d / 30d / 90d) or any datetime window
  • Auto-refresh at the cadence you want, paused automatically when the tab is hidden
  • Drill-down on click — clicking a route in a top-N chart filters the whole dashboard on it
  • Deep links — every filter and time range lives in the URL, paste anywhere and the view comes back to life
  • Per-dashboard saved views — set defaults so a teammate opening the dashboard sees what you intended
  • Threshold alerts with conditions, AND/OR logic, severities, cooldown, and a full event log
  • Tenant-scoped — each team sees only its own traffic, end to end

Get going in three minutes

1. Plug a PostgreSQL store

Go to Data Exporters → Add → User Analytics (PostgreSQL), fill in your PG connection (host, db, user, password — or a connection URI), set a retention window, save. Otoroshi creates the schema, the indexes and the alert log table automatically.

2. Mark it as the active store

On the exporter page, click Set as active analytics exporter. From now on, every gateway event Otoroshi processes flows into your store. Five default dashboards are seeded for you to start exploring immediately.

3. Open the dashboards

Features → Analytics → User Analytics (or /bo/dashboard/user-dashboards). Pick Global Overview to see the firehose, then drill into the others:

  • Performance — latency percentiles, overhead, response-time heatmap
  • Errors — error rate, top failing routes, status classes over time
  • APIs & Routes — top consumers, traffic per API, domain breakdown
  • Consumers — top API keys, top users, top countries

That's it. You're live.

Building a dashboard your way

Click Edit mode on any dashboard to unlock the editing toolbar. From here you can:

  • Add a widget — pick a query from the catalogue, choose the visual style, set a width and height. Format hints (count / req/s / ms / bytes / percent) are auto-suggested but always overridable.
  • Drag & drop widgets to rearrange them — the grid auto-reflows around their size.
  • Edit a widget to tweak its title, query parameters, threshold colors, axis options, anything.
  • Save view as default — capture the current time range, filters and refresh interval as the dashboard's opening view. Anyone clicking the dashboard from the menu lands on that exact configuration.
  • Edit JSON for power users who want to copy-paste a dashboard to another instance or tweak fine-grained options not exposed in the form.

When you're done, click Done editing to lock the dashboard back. No risk of an accidental click during a demo.

The widget palette

Every widget renders independently with its own data fetch, loading state, error handling, and refresh button.

TypeWhen to use
Line / AreaTrends over time — RPS, latency, error rate
BarTop routes / APIs / consumers — sortable horizontally
Pie / DonutCategorical distribution — status codes, methods
Big numberHeadline KPIs — total requests, total errors
MetricLabelled value with optional thresholds
TableInline list of top-N items
HeatmapLatency × time density grid

All widgets adapt to the active theme (light/dark), respect tenant scoping, and inherit your global filters.

What you can measure

The query catalogue ships with everything most teams need, day one. Each one can be plotted in a widget AND used as the condition of an alert.

Volume

QueryWhat it tells you
requests_totalTotal number of requests over the time window
requests_per_secondRequest rate over time
requests_by_statusDistribution of HTTP status codes
requests_by_status_class_ts2xx / 3xx / 4xx / 5xx counts over time, stacked
requests_by_methodDistribution of HTTP methods
traffic_in_out_tsBytes in and out over time

Performance

QueryWhat it tells you
duration_avg_tsAverage response time over time
duration_percentiles_tsp50 / p75 / p95 / p99 latency over time
overhead_avg_tsAverage Otoroshi overhead over time
response_time_heatmapDensity of latency buckets over time (heatmap)

Errors

QueryWhat it tells you
errors_totalTotal errored requests over the window
error_rate_tsFraction of errored requests over time
top_error_routesTop routes by errored request count

Top consumers and entities

QueryWhat it tells you
requests_by_routeTop routes by request count
requests_by_apiTop APIs by request count
requests_by_apikeyTop API keys (most active integrators / customers)
requests_by_userTop end-users (when authenticated via private apps)
requests_by_domainTop hostnames hitting your gateway
requests_by_countryGeographic breakdown

Every query supports the same filters — route, API, API key, group, time window — so you can scope any of them to a specific slice of your traffic. Most timeseries queries also support the Compare period overlay for week-over-week or day-over-day visual checks.

Need something the catalogue doesn't have? Any Otoroshi extension can register additional queries — they show up in the dashboard widget picker and the alert conditions editor with no further work.

Filters that follow you everywhere

Every dashboard has a control bar with:

  • From / To datetime pickers for absolute ranges
  • Preset buttons1h, 6h, 24h, 7d, 30d, 90d for quick relative windows that stay alive in shared links
  • Last refresh indicator12s ago (14:35:50) so you always know how fresh the data is
  • Manual refresh plus an Auto toggle (10s / 30s / 1m / 5m)
  • Entity filters — search any route, API, API key or service group with autocomplete
  • Compare toggle to overlay the previous period on every time series

Click any bar in a "Top routes / APIs / API keys" chart and the whole dashboard reroutes onto that entity. Keep diving.

Sharing and bookmarking

The full state of what you're looking at lives in the URL. Hit Copy link, paste it in chat, in an incident ticket, in your runbook. Anyone with access to your tenant lands on the exact same view, including the relative time range — now-1h stays alive on tomorrow's reload.

You can also link directly from a route, API or API key detail page into a pre-filtered analytics view, by using query params. Power users build deep links from anywhere.

Alerts

Threshold alerts ride on the same query catalogue as your dashboards.

Define an alert

User Alerts → New Alert. Give it a name, a severity (info / warning / critical), a time window (e.g. last 5 minutes), and one or more conditions. Each condition is a one-liner:

Take query error_rate_ts, reduce with max, and fire if the result is > 0.05

You can scope a condition to a specific route, API, API key or group. Combine multiple conditions with AND or OR.

The visual conditions editor lets you build it without writing a line of JSON. Power users can flip to JSON view at any time.

Tune the noise

  • Evaluation interval — how often we re-check (e.g. every 60s)
  • Cooldown — minimum time between two consecutive firings (don't spam your inbox)
  • Window — how far back the condition looks

Where alerts land

Alerts emit standard Otoroshi AlertEvents with a recognizable signature (alert: "UserAnalyticsAlert"). Configure a Data Exporter of any type — mailer, webhook, Slack via webhook, Kafka, anything Otoroshi already speaks — and filter on that signature. The User Alerts page reminds you to do it the first time you create one and offers a one-click shortcut that pre-fills the filter.

The alert log

Every firing is also persisted, so you have a permanent searchable log per alert. Click 🔔 next to an alert to open it:

  • See every firing with its severity, message, and a snapshot of the matched conditions (with the actual value vs the threshold)
  • Filter by unseen / seen / all
  • Mark an event as seen — or Mark all seen to wipe the inbox in one click

Click any firing to open a detailed breakdown of the conditions that fired it, with the observed value next to the configured threshold:

Tenant-aware by design

A tenant-admin sees only the traffic, dashboards, alerts and events of their own tenant. The injected SQL filter ensures one tenant's data never leaks to another. Super-admins switch tenants from the standard Otoroshi tenant dropdown — the analytics views follow.

Dashboards and alerts are normal Otoroshi entities, so they participate in your usual export / import / GitOps workflows.

Power-user features

A query catalogue you can extend

Every query the dashboards and alerts can reference is exposed at:

GET /api/analytics/_schema

This returns a typed catalogue of queries — id, human name, expected shape, default widget, parameters, whether it supports a "compare period" overlay.

Add your own queries from an admin extension

If you ship a custom Otoroshi extension (WAF, MCP, billing, anything), you can register your own analytics queries that show up in the dashboard widget picker AND can be referenced by alerts:

override def analyticsQueries(): Seq[AnalyticsQuery] = Seq(
MyExtensionQuery1,
MyExtensionQuery2
)

Prefix the query id with your extension namespace (waf.blocked_per_route, billing.cost_per_apikey) — they're fully integrated everywhere queries appear in the UI.

Bring your own delivery

Alerts go through the standard Otoroshi alert pipeline, so any data exporter type can deliver them: webhooks for PagerDuty / Opsgenie / generic services, mailer for email, Kafka for downstream pipelines, a custom WASM exporter for anything bespoke.

Tips for healthy dashboards

  • Keep dashboards focused. A dashboard with one clear purpose ("checkout traffic", "platform errors") beats a 20-widget kitchen sink.
  • Use the saved-view defaults. If your team always opens a dashboard on a 24h window, save it. Less ceremony, more signal.
  • Drill, don't filter. It's faster to click a bar than to hunt the right entity in a dropdown.
  • Set up alerts for the obvious. 5xx rate over a few percent, p95 over your SLO, daily request count dropping unexpectedly — three alerts cover a surprising amount of ground.
  • Pair alerts with a runbook link in the alert message. Future you will thank present you.

Where to next

  • Install your first dashboard now: head to Features → Analytics → User Analytics.
  • Plug your first delivery channel: Data Exporters → Add → Mailer / Webhook / Slack with a filter on { "alert": "UserAnalyticsAlert" }.
  • Tune the defaults of a dashboard you use daily — your team will notice.