What Is Apdex (Application Performance Index)?
Last verified on Nov 8, 2026.
A response-time chart says a lot to an engineer and almost nothing to a manager. Apdex squeezes a set of timings into one number between 0 and 1, so that application performance can be reported the way uptime is: a single figure, comparable week to week.
Definition
Apdex, short for Application Performance Index, is an open standard published by the Apdex Alliance as a technical specification. The specification says the index does not need new measurements. It is a different way of representing measurements you already collect, by counting samples in each of three performance zones. You choose one number, the target threshold T, in seconds.
- Satisfied: response time at or below T.
- Tolerating: response time above T and at or below F, where F = 4T.
- Frustrated: response time above 4T.
The Formula
Apdex_T = (satisfied + tolerating / 2) / total samplesFrustrated samples count in the denominator and add nothing to the numerator. The specification's own example: 80% satisfied, 10% tolerating, and 10% frustrated give an index of 0.85, since (80 + 5) / 100. A score of 1.00 requires every user to be satisfied. As the specification puts it, if some users see tolerating or frustrating performance, the index dips below 1.00 quickly.
Errors and Aborts
The specification says what to do with failures, and it is stricter than an ordinary latency chart:
- Server-generated aborts, such as a TCP close within a task, count as frustrated no matter how long the task took.
- If a tool can detect task errors, such as a 404 reply, these count as frustrated too.
- A user-initiated abort stops the timer and falls in whichever zone its elapsed time lands in.
This matters when you compute it from logs. A fast error is not a satisfied request.
Rating Bands
The specification also gives tools a fixed set of words for ranges of the index, so a score can be shown as a label or color:
The bands are only meaningful for the T you report, which is why the specification insists the two travel together.
Reporting Rules
The specification sets some presentation rules. They are what let two tools compare scores:
- The index is shown to two decimals: 0.85, 0.94, 1.00. Results of 0.995 or higher round up to 1.00.
- T always appears with the score, either as
0.85 [4.0]or as a subscript,0.85with T of 4 seconds. - The recommended default T is 4 seconds, and tools may change it.
- The minimum sample size for normal reporting is 100 samples in a report group. Smaller groups must be marked with an asterisk, and an empty group is reported as NS.
A score with no T is meaningless: 0.90 with a T of 10 seconds describes much worse performance than 0.90 with a T of 0.5 seconds.
Computing Apdex from Logs
With request_logs(ts, route, status, duration_ms) and T = 500 ms (so F = 2,000 ms), PostgreSQL's FILTER makes it one query:
SELECT route,
count(*) AS samples,
round(
(count(*) FILTER (WHERE status < 400 AND duration_ms <= 500)
+ count(*) FILTER (WHERE status < 400 AND duration_ms > 500 AND duration_ms <= 2000) / 2.0)
/ count(*), 2) AS apdex_500ms
FROM request_logs
WHERE ts >= now() - interval '1 hour'
GROUP BY route
HAVING count(*) >= 100
ORDER BY apdex_500ms;Requests with a status of 400 or higher fall into neither counted zone, so they are frustrated, and the HAVING clause enforces the specification's minimum sample size. Whether a 4xx from a caller's mistake should count is a judgment call. The specification's example is a 404 counted as a task error.
Computing It in Prometheus
Prometheus's histogram guide documents an Apdex calculation with T = 0.3 s and F = 1.2 s, using the cumulative buckets of a classic histogram:
(
sum by (job) (rate(http_request_duration_seconds_bucket{le="0.3"}[5m]))
+
sum by (job) (rate(http_request_duration_seconds_bucket{le="1.2"}[5m]))
) / 2
/ sum by (job) (rate(http_request_duration_seconds_count[5m]))It works because buckets are cumulative: the le="0.3" bucket holds the satisfied requests and the le="1.2" bucket holds satisfied plus tolerating, so their average gives satisfied plus half of tolerating. Your T and 4T must match bucket boundaries, or the result is an estimate.
Where Apdex Falls Short
- T is a choice. The score is only as meaningful as your T, and two teams with different T values cannot compare numbers.
- It hides the shape. A 0.85 can be 85% perfect and 15% frustrated, or 70% satisfied and 30% tolerating. Keep the zone breakdown next to the score.
- Fixed zone widths. F = 4T is a convention, not a measurement of user behavior.
- Not an alert by itself. A slow decline in the score may hide a bad tail. Pair it with a view of p95 latency, which shows the tail that the score smooths over.
If you already track SLIs, a ratio such as "requests under 500 ms" is the satisfied zone of an Apdex, without the tolerating credit. For what slow responses look like before the score moves, see performance degradation and latency spikes.
Frequently Asked Questions
What is a good Apdex score?
The specification's qualitative bands call 0.94 to 1.00 excellent, 0.85 to 0.93 good, 0.70 to 0.84 fair, 0.50 to 0.69 poor, and below 0.50 unacceptable, always relative to the T you report.
How is Apdex calculated?
Count samples at or under T as satisfied and samples between T and 4T as tolerating. Apdex is satisfied plus half of tolerating, divided by all samples.
What should the Apdex threshold T be?
It is set per application. The specification recommends a default of 4 seconds, and permits tools to change it. Pick a value from what your users need, then keep it fixed so the score stays comparable.
How does Apdex differ from an SLO?
Apdex is a score of how satisfied users were, using three zones. An SLO is a target for a ratio of good events. Both start from the same response-time measurements.
Sources
- Apdex Technical Specification V1.1: satisfied, tolerating, and frustrated zones, F = 4T, the formula, default T of 4 seconds, sample-size and reporting rules, error handling (accessed Nov 8, 2026)
- Prometheus documents an Apdex score calculation from histogram buckets (accessed Nov 8, 2026)
- The FILTER clause restricts which rows an aggregate sees (accessed Nov 8, 2026)