The JMeter HTML Dashboard is the standard deliverable from a load test run — a self-contained, shareable report that every stakeholder in the JMeter ecosystem recognises. It is generated from the .jtl results file after the test completes, meaning it has zero impact on test execution performance.
Generating the report
During the test run (recommended):
jmeter -n -t test.jmx -l results.jtl -e -o report/The -e flag tells JMeter to generate the HTML dashboard when the test finishes. The -o report/ flag specifies the output directory. JMeter writes results.jtl as the test runs, then processes it into report/ at the end.
From an existing JTL file (regenerate at any time):
jmeter -g results.jtl -o report/This is useful for: regenerating a report with different settings, creating a report on a machine that did not run the test, or re-analysing historical results.
Important: the -o directory must not already exist, or must be empty. JMeter refuses to overwrite an existing report. Use timestamped directory names in scripts:
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
jmeter -n -t test.jmx -l "results-${TIMESTAMP}.jtl" -e -o "report-${TIMESTAMP}/"What the dashboard contains
HTML Dashboard sections — what each provides
Dashboard summary — the first panel shows aggregate KPIs for the entire test: total samples, average response time, minimum, maximum, 90th percentile, 95th percentile, 99th percentile, error rate, and throughput. This is the single number set that answers "did the test pass?"
APDEX scores — Application Performance Index rates user satisfaction per sampler on a 0–1 scale. APDEX categorises each request as Satisfied (response time ≤ T), Tolerating (≤ 4T), or Frustrated (> 4T), then computes a weighted score. A score of 1.0 means every user was satisfied. A score below 0.7 indicates significant user experience degradation.
Statistics table — a detailed per-sampler breakdown: count, fail count, error rate, average, median, 90th/95th/99th percentiles, min, max, throughput, and bandwidth. This is where you identify which specific endpoint is causing problems.
Errors table — lists every distinct error type: HTTP status codes, assertion failures, timeout errors. Shows count and percentage for each. Use this to distinguish between server errors (5xx), client errors (4xx, often data or correlation issues), and network errors (timeouts, connection refused).
Charts — response time over time, response time percentiles over time, throughput over time, active threads over time, APDEX over time. The time-series charts reveal patterns: does response time degrade after 10 minutes of sustained load? Does throughput drop when threads reach their peak?
APDEX threshold configuration
APDEX thresholds are configured in jmeter.properties or user.properties:
# Satisfied threshold: responses under this time count as Satisfied
apdex_satisfied_threshold=500
# Tolerated threshold: responses between satisfied and this count as Tolerating
apdex_tolerated_threshold=1500With these defaults, a 400ms response is Satisfied, a 1000ms response is Tolerating, and a 2000ms response is Frustrated. Set these thresholds to match your actual SLAs — if your SLA says "login must complete in under 800ms," set apdex_satisfied_threshold=800 for the login sampler.
Different thresholds per sampler are not supported in the standard configuration — all samplers share the same APDEX thresholds. If you need per-endpoint APDEX, post-process the JTL file with a custom script.
Customising the report
Add these to user.properties for report-wide customisation:
# Report title (appears in the browser tab and header)
jmeter.reportgenerator.report_title=SecureBank Load Test — Staging — 2026-05-08
# Time granularity for charts (milliseconds)
# 10000 = 10-second buckets (good for 30-minute tests)
# 60000 = 1-minute buckets (good for multi-hour tests)
jmeter.reportgenerator.overall_granularity=10000
# Filter samplers shown in the report (regex on sampler label)
jmeter.reportgenerator.sample_filter=
# Exclude Transaction Controller parent samples from statistics
jmeter.reportgenerator.report.transactions_filter_pattern=^((?!Transaction Controller).)*$Reading the report effectively
Start with the Dashboard summary — check the error rate first. If it is above your threshold, stop and investigate errors before looking at response times. A 5% error rate makes p95 response time meaningless.
If error rate is acceptable, check APDEX per sampler — find the lowest-scoring endpoints. These are where your users are experiencing the most frustration.
Open the Statistics table — look at the p95 and p99 columns against your SLAs. Averages are misleading; percentiles tell you what the worst-case user experience looks like.
Use the Response time over time chart to check for degradation patterns: does performance hold steady throughout the test, or does it degrade after ramp-up completes? Degradation under sustained load (not just at peak) indicates a resource leak or connection pool exhaustion.
Sharing the report
The HTML dashboard is self-contained — all CSS, JavaScript, and chart data are embedded. Copy the entire report/ folder to share it.
Options:
- CI/CD artefact: upload as a build artefact in Jenkins or GitHub Actions. Anyone with access to the build can download and open it.
- S3 or GCS: upload to a cloud storage bucket configured for static hosting. Share a URL.
- Confluence: upload the
.jtlfile as an attachment or screenshot the key charts into a Confluence page alongside your analysis. - PDF: open
report/index.htmlin Chrome and use File → Print → Save as PDF. Charts render as vector graphics in PDF.
⚠️ Common mistakes
- Running
-e -o report/whenreport/already exists. JMeter exits immediately with an error rather than overwriting. Script your runs to delete the old directory first (rm -rf report/) or use timestamped names. This frequently breaks CI/CD pipelines on the second run. - Setting time granularity too fine for long tests. The default 60,000ms (1-minute) granularity produces smooth charts for a 30-minute test. Changing it to 1,000ms (1-second) for a 30-minute test creates 1,800 data points per chart — charts become unreadable and the report file grows large. Match granularity to test duration: ~30–60 data points per chart is the readable target.
- Reading only the average response time. The average is dominated by the most common case. A single 30-second timeout in a 10,000-request test barely moves the average but shows clearly in p99. Always check p95 and p99 against your SLAs.
🎯 Practice task
Generate and analyse a full HTML dashboard.
- Run your test plan with 20 users for 60 seconds in CLI mode:
jmeter -n -t test.jmx -l results.jtl -e -o report/. - Open
report/index.html. Find the APDEX score for your main sampler. Is it above 0.9? - Look at the Statistics table. What is the difference between the Average and the 99th percentile? If the difference is large (>3×), there are occasional slow outliers — investigate the Max column.
- Open the Response Time Over Time chart. Does response time increase as the test progresses, or does it stay flat? A rising trend under constant load indicates a problem.
- Edit
user.properties: addjmeter.reportgenerator.report_title=My First Load Testandjmeter.reportgenerator.overall_granularity=5000. Regenerate the report:jmeter -g results.jtl -o report2/. Confirm the title change and the smoother time-series charts. - Delete
report/then re-run the test — confirm that without the old directory, the report generates correctly.