GET /users/1042, GET /users/1043, GET /users/1044 are one endpoint. The dashboard has to know that, or the endpoint list becomes a list of every user id you have ever served โ thousands of rows with one request each, and no way to say "the users endpoint is slow."
So paths are templated: segments that look like identifiers are collapsed to a placeholder, and /users/1042 becomes /users/:id. Every monitoring tool does this. The interesting part is deciding what "looks like an identifier" means, because the two ways to get it wrong are opposite and both silent.
Too loose
Collapse too eagerly and real path segments disappear. If any segment longer than a few characters is treated as an id, /api/facade/render becomes /api/:id/render, and the facade endpoint merges with every other seven-letter word in your routing table. You cannot find it any more. The metrics for two unrelated endpoints are averaged together, and the p95 you are looking at belongs to neither.
Too strict
Collapse too cautiously and the list explodes. Our first rule only collapsed long tokens โ UUIDs, and anything past twelve characters. It missed 8-character hex ids, which a customer used everywhere. Fifty of their requests to one route produced fifty endpoints.
The test that pins the fix is named for the failure: fifty distinct ids on one route create exactly one endpoint.
The rule
A segment is treated as an identifier when it is eight characters or longer and contains at least one digit, or when it matches an unambiguous shape โ a UUID, a long hex string, a pure number.
The digit requirement is the whole trick. facade, decade, profile, settings, render โ English words are long enough to trip a length check and contain no digits. Identifiers, with rare exceptions, do. 3f9a1c2e has digits. a1b2c3d4 has digits. 01HZX8K4 has digits. Words do not.
Lowering the threshold from twelve to eight without the digit rule would have turned every route word of eight letters or more into a wildcard. Adding the digit rule let the threshold drop safely.
Where it happens
The plugin does this on the client before sending, so the API and the store never see the raw path as the endpoint key โ the raw path is still stored on the request row, so you can always see exactly what was called, but the endpoint the request is counted against is the template. The mobile SDKs apply the same rule to the URLs they record, so a phone calling /orders/8841 and the backend serving it agree on what the endpoint is called.
The exceptions we know about
A pure-word identifier โ a slug like /posts/hello-world โ is not collapsed, because nothing about it says "id". Those endpoints will list per slug. The fix, when it matters, is a route template from your framework, which the plugin prefers over its own guess whenever the framework exposes one: Elysia's route pattern is used directly, and the heuristic only runs where no pattern exists.
And a numeric segment shorter than eight โ /v2/, /2024/ โ is treated as an id only when it is all digits, so /v2/users keeps its version and /reports/2024/03 collapses the date.
The rule fits in a dozen lines. The two silent failures it prevents are the kind you discover from a customer, which is the wrong way to discover them.