Skip to main content
The API dashboard groups requests by route: GET /accounts/{id} is one row, however many accounts there are. The route comes from the http.route attribute, the route template your framework matched, which OpenTelemetry’s HTTP instrumentations set on the request metric and the server span.

In the four examples

tests/otelapps sends a fixed load to each example and checks that every request is counted under exactly these routes, with no raw path left over.

When your framework does not set it

Set it yourself in a middleware that runs after routing, on the active server span. This is what the Go example does, because otelhttp puts the route on metrics but not on the span:
In other languages the pattern is the same: read the matched route template from your router and set http.route on the current span (and, where your instrumentation allows, on the metric attributes). Use the template, never the actual path. The span attribute matters when you export only traces, and for your own backend.

What the platform does with routes

Every route, whether you set it or not, goes through the same fixed normalization before it is stored:
  • No http.route: the platform uses the request path (url.path, or the legacy http.target) instead, without the query string.
  • Values become placeholders, in the template and in a path alike: numbers become {id}, UUIDs {uuid}, long hex strings and hashes {hex} or {hash}, dates {date}, tokens {token}, Stellar account, muxed account and contract keys {account}, {muxed}, {contract}, assets {asset}, email and federation addresses {email} and {federation}, and a segment longer than 64 bytes {long}. A secret seed in a path becomes {redacted-secret}, and the API traffic page warns you, because the seed was exposed in a URL.
  • At most 300 distinct routes and 50 services per project and UTC day (the service’s current settings). Routes beyond that are counted under {other}, so their requests are still in the totals, and the API traffic page shows a warning. A route that changes with every request (a slug, a name) fills the allowance quickly; set http.route to the template to avoid that.
The rules are hard coded and the same for every project; they cannot be configured (internal/routenorm lists them in order).