> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apitraffic.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Performance Analytics

> Find the endpoint, query or connection that is costing you the most time

Once [APM is enabled](https://docs.apitraffic.io/apm/setup.md), the **Performance** section of a bucket answers two questions:
*is anything slow, and where does the time go* (Overview), and *which query or connection is
responsible* (Operations). Everything is scoped to the bucket, environment and time period
selected in the dashboard.

## Overview

The overview reads per-request rollups rather than individual spans, so it stays fast at any
traffic volume.

**Summary** — requests, error rate, median / p95 / p99 latency, total time consumed, the share of
time spent waiting on dependencies, and how many operations ran.

**Time Breakdown** — where request time went over the period, split into database, cache,
outbound HTTP, queue/RPC and application time. Application time is the residual: request duration
minus the instrumented families, floored at zero. Because dependency work can overlap, a heavily
parallel endpoint can show little or no application time.

**Endpoints By Time Consumed** — endpoints ranked by *total* time rather than average latency,
with requests, errors, average, p95, p99 and the same dependency split per endpoint. A 30 ms
endpoint called a million times costs more than a 4 s endpoint called twice, and this ranking is
what surfaces it.

**Regressions** — endpoints whose p95 or error rate moved against a baseline, ranked by the time
the change costs. Choose the baseline: the **previous window** (the period immediately before the
one selected) or the **same window a week ago**, which is the better comparison for traffic with a
weekly shape. Endpoints below a minimum request count are ignored so that noise from rarely called
routes does not crowd out real movement.

> [!NOTE]
>
> Regression detection is read-time and on-demand. Alert delivery (Slack, webhooks) is not part of
> it — use [events and workflows](https://docs.apitraffic.io/events.md) for notification today.

### Streams and long-lived connections

A streaming response stays open for as long as its client listens, so its duration is how long the
connection was open, not how long the server took to respond. Responses sent as
`text/event-stream` (Server-Sent Events, such as MCP's `GET /mcp/sse`) are marked as streams
automatically, and you can mark other long-held connections, such as long polling, with the
[**Long-lived connection**](https://docs.apitraffic.io/endpoint-handling.md#long-lived-connections) option on an endpoint rule.

Streams are counted everywhere requests are counted — request totals, throughput and error rates —
but are left out of response-time metrics: average, median, p95 and p99 latency, slow
operations and response-time charts. A single stream held open for five minutes
would otherwise outweigh thousands of ordinary requests.

The SDKs also record each request's **time to first byte**: how long the server took to start
responding. For a stream, that is the number that reflects how quickly it was served, and it is
shown alongside the open time in the request list and request detail.

## Operations

The Operations tab aggregates spans across requests. Choose what to group by:

| Group by | Answers |
| - | - |
| Query / Operation | Which individual query or command costs the most |
| Host / Connection | Which database host or external service you spend time on |
| Database | Which database or schema is hot |
| System | How much time goes to Postgres vs Redis vs Kafka |
| Type | The overall split by kind of work |
| Inbound Endpoint | Which of *your* endpoints issue the most dependency work |
| Outbound Endpoint | Which endpoint *on another service* you spend the most time calling |
| Outbound Path (All Hosts) | The same destination path across every host that serves it |
| Outbound Status | How outbound calls ended: 2xx/3xx/4xx/5xx, or no response at all |
| Code Location | Which line of your code issues the most dependency work |

The two endpoint groupings answer opposite questions and are never mixed. **Inbound Endpoint** is
your own endpoint — the request that made the calls. **Outbound Endpoint** is the endpoint on the
service you called, normalized the same way your own paths are and qualified by the host that served
it, so `POST api.stripe.com /v1/charges/{id}` never collapses into the same row as the identical path
on another vendor. Selecting either outbound grouping scopes the report to outbound HTTP, since a
database or cache span has no destination endpoint. Outbound
[endpoint rules](https://docs.apitraffic.io/endpoint-handling.md) scoped to a host apply here, so you control how a vendor's paths
are grouped.

### Upstream failures

Outbound groupings carry an extra **Upstream Failures** column and sort: the share of that group's
calls that returned 5xx or never got a response at all, with the 5xx, no-response and 4xx counts
underneath. 4xx is deliberately excluded from the rate — a 401 or a 404 is normally your request
being wrong rather than the dependency breaking, and folding it in hides a real outage inside a
steady stream of 404s. A call that timed out, was refused or failed DNS has no status at all; it is
reported as *no response* (status `0`), which is a different failure from a 5xx and is counted
separately.

Sort an outbound grouping by Upstream Failures to see which dependency is failing right now. Opening
a row flags an elevated rate and charts upstream failures over time next to runs, so a dependency
that just started failing shows up as a line lifting off zero while your own traffic stays flat.

On the API, `/spans/reports` and `/spans/timeseries` accept `outStatusClass` (`2xx`, `3xx`, `4xx`,
`5xx`, `none`) and `outStatusCode` for an exact status, and every row and bucket returns
`outCalls`, `outServerErrorCount`, `outNoResponseCount` and `outClientErrorCount`.

Each row shows runs, runs per request, average, p95, p99, total time and errors, and can be sorted
by any of them. **Total time is usually the right sort** — it is what actually costs your users.

Rows that run many times per request are badged **N+1**. That is the classic symptom of a query
issued inside a loop: individually fast, collectively ruinous. Because
[code location capture](https://docs.apitraffic.io/apm/capture-settings.md#code-location) is on by default, each row carries the
file, line and function that issued the operation, and **Code Location** is a grouping of its own —
ranking your own source lines by the time they spend waiting on dependencies. Opening a row also
shows a representative **stack trace**: the callers that led to the operation, innermost first.

Code locations only exist for spans recorded while capture was on, so a group from a bucket with it
switched off (or from before it existed) reads as *(no code location captured)*.

Selecting a row opens the operation, with:

* full statistics for the group (runs, distinct requests, runs per request, quantiles, total time,
  type, system, host, database, inbound endpoint, outbound endpoint, code location, last seen);
* a **trend** chart of that operation over time — runs, errors and latency quantiles — so you can
  see whether it has always been slow or started recently;
* the **requests it ran in**, so you can jump straight from a slow query to a real request that
  executed it and inspect the whole waterfall.

## Inside a request

Open any request in **Traffic** to see the same data from the other direction.

**Time breakdown** — a bar above the waterfall showing how this specific request's duration split
across database, cache, outbound, queue/RPC and application time.

**Waterfall** — every span on a timeline, positioned by when it started relative to the request
and sized by duration, with failed operations marked. Selecting a span opens its details:
duration, start offset, end offset, share of the request, and all metadata the instrumentation
provided — operation, method, status, system, database, table or collection, host, path, route,
URL, command, key, rows, user, connection pool, transport, span kind, instrumentation scope,
errors, and the code location when captured. Statements and parameters render as code blocks.
Anything an instrumentation attached that ApiTraffic does not have a label for is still shown
under its own key — the pane never hides data it received.

**Distributed Trace** — every request that shares this request's trace id, in time order, with
status, duration and span count. This is how a call that crosses several of your services reads
as a single timeline; see [how traces are resolved](https://docs.apitraffic.io/apm/overview.md#distributed-traces).

## Querying it yourself

Everything above is available over the API:

> **[APM API](https://docs.apitraffic.io/api-reference/apm.md)**
>
> Time breakdown, endpoint ranking, regressions and trace lookup

> **[Spans API](https://docs.apitraffic.io/api-reference/spans.md)**
>
> Operation reports, per-operation trends and drill-back to requests


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.