PRACTICAL GUIDE / debug Playwright missing network trace evidence
Your Playwright trace is missing the request you need
Learn why a failed Playwright run can lose network evidence, how to capture the right attempt, and how to diagnose gaps without exposing secrets.
In this guide6 sections
What you will learn
- Why a real failure can leave an empty evidence trail
- Capture the attempt that can actually explain the bug
- Tell capture failure from application failure
- Check who actually owns the request
The checkout test fails in CI, but its artifact folder contains screenshots and no usable network trace. A retry passes, and the trace from that attempt shows a healthy 200 response, which tells you nothing about the first failure. The application may be broken, but the immediate problem is that the failing attempt was not recorded or retained.
Why a real failure can leave an empty evidence trail
A trace is not a packet capture that exists independently of the test. Playwright has to start recording before the browser action, observe the request, finish the recording, and retain the resulting archive. A gap at any one of those points looks like “the request is missing,” but each gap has a different fix.
The most common mistake is a mismatch between the trace policy and the retry policy. With trace: 'on-first-retry', Playwright records only the first retry. It does not record the original attempt. If retries are disabled, no qualifying run occurs. If the retry passes, you get an excellent record of the passing path and no record of the failure that triggered it.
retain-on-failure has different semantics. Playwright starts a trace for every run, deletes it after a pass, and keeps it after a failure. That costs more during execution because passing tests are recorded temporarily, but it preserves the original failure even when a later retry succeeds. For a short-lived investigation, trace: 'on' removes retention ambiguity by keeping every run. It is too expensive and too revealing to leave enabled casually across a large suite.
Manual tracing introduces another failure mode. context.tracing.start() and context.tracing.stop() record browser operations and network activity, but they do not add Playwright Test assertions to the trace. A thrown exception can also skip tracing.stop() when it is not protected by cleanup logic. Playwright Test configuration is the safer choice for test-runner projects because the runner owns the recording lifecycle.
Finally, the request may never have happened. A disabled button, failed navigation, JavaScript error, or earlier assertion can stop execution before the trigger. No trace setting can manufacture a request that the page did not send. Check the action timeline before blaming network capture.
Capture the attempt that can actually explain the bug
Start with a failure-retention policy and an explicit assertion around the business request. The trace then supplies context, while the test still decides whether the product worked.
// playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
retries: process.env.CI ? 1 : 0,
outputDir: 'test-results',
use: {
baseURL: process.env.BASE_URL ?? 'http://127.0.0.1:3000',
trace: 'retain-on-failure',
},
});The test below starts waiting before it clicks. That ordering matters. If the response is fast, registering waitForResponse after the click creates a race and can turn good network evidence into a timeout.
// tests/orders.spec.ts
import { test, expect } from '@playwright/test';
test('shows the submitted order', async ({ page }, testInfo) => {
await page.goto('/checkout');
const responsePromise = page.waitForResponse((response) => {
const url = new URL(response.url());
return url.pathname === '/api/orders' &&
response.request().method() === 'POST';
});
await page.getByRole('button', { name: 'Place order' }).click();
const response = await responsePromise;
const summary = {
method: response.request().method(),
path: new URL(response.url()).pathname,
status: response.status(),
servedByServiceWorker: response.fromServiceWorker(),
};
await testInfo.attach('order-response-summary', {
body: Buffer.from(JSON.stringify(summary, null, 2)),
contentType: 'application/json',
});
expect(response.ok(), JSON.stringify(summary)).toBeTruthy();
await expect(page.getByRole('heading', { name: 'Order confirmed' }))
.toBeVisible();
});This is deliberately not a dump of request headers or the response body. A status, method, path, and service-worker flag answer the first triage questions without copying authorization headers, cookies, personal data, or payment details into CI artifacts. Add a carefully redacted field only when it distinguishes competing causes.
There is a trade-off in retain-on-failure. Every attempt must be traced until its result is known, so a large suite will use more CPU and temporary disk than on-first-retry. Teams with reliable retries often keep on-first-retry as the normal policy and switch the affected project to retain-on-failure while investigating a first-attempt-only failure.
Tell capture failure from application failure
Run the smallest failing test once with tracing forced on:
npx playwright test tests/orders.spec.ts --trace on
npx playwright show-trace test-results/path-to-result/trace.zipUse the actual archive path printed by the reporter or linked from the HTML report. Do not assume the first trace.zip found belongs to the failed attempt, especially when retries, projects, and shards write artifacts concurrently.
Then inspect the evidence in this order:
- Confirm the attempt. Match the project, browser, test title, retry number, and failure message. A trace from retry 1 cannot explain a timeout on the initial run unless both attempts reached the same point.
- Find the trigger action. In the Actions view, locate the click, navigation, or evaluation that should cause the request. If it is absent, move backward to the first failed action. The problem is execution flow, not network recording.
- Open the Network view. Filter by the path, not a full URL containing volatile query values. Compare method and status. A
401,404, or500is a received response, not a missing request. - Look for an unfinished transport. A request may be present without a response because DNS, TLS, a proxy, or the server connection failed. A
page.on('requestfailed')listener can record the browser’s failure text, but the text is a symptom. Correlate it with proxy, server, or platform logs. - Check the final assertion. A successful API response does not prove the UI consumed it. If the response is healthy but the heading never appears, inspect the DOM snapshots and console errors around that transition.
If forcing --trace on creates a complete archive, capture works and the normal retention policy is wrong for this incident. If the archive opens but the action is absent, the test never reached the request. If the action exists and another observer, such as the application server, proves the call happened while the trace lacks it, investigate ownership of the traffic.
Check who actually owns the request
Page events cover requests associated with the page, but modern applications may add another network owner. A service worker can serve a cached response, proxy a fetch, or issue its own request. In Chromium, Playwright exposes service-worker requests through BrowserContext network events, and response.fromServiceWorker() tells you when a page response came through one.
For tests whose purpose is direct browser-to-server behavior, setting serviceWorkers: 'block' removes that layer. The cost is realism. An offline-capable application, push workflow, or cache update path must be tested with service workers allowed. Use separate projects when both contracts matter, rather than changing the setting until the failure disappears.
Also separate browser traffic from calls made through the Playwright request fixture or another HTTP client in test code. A browser trace is best at explaining page actions and browser network activity. If setup code creates an order through an API client before opening the page, attach a small sanitized record from that setup call. Do not expect a page’s Network view to tell the complete story of non-page work.
Routing can create a different kind of false confidence. A broad page.route() or browserContext.route() handler may fulfill the request locally, so the trace shows a clean response while the real backend was never contacted. Inspect the test’s routing setup and make the assertion explicit about whether it is validating UI behavior with a mock or an integrated backend path.
Keep useful evidence without creating a secret archive
Traces can contain DOM snapshots, screenshots, source snippets, URLs, and attachments. Network-focused debugging often adds headers and bodies on top. That is enough to expose session tokens, customer data, internal hostnames, or credentials if artifacts are uploaded unchanged.
Collect the smallest record that can disprove a hypothesis. Path, method, status, duration, request ownership, and a server correlation ID are usually more useful than an entire body. Strip query strings unless a particular parameter is under test. Allowlist safe headers instead of trying to blacklist every possible secret. Keep artifact access narrow and apply a retention period in CI.
HAR recording is useful when you need a transport archive or deterministic replay, but it is not a substitute for a trace. A HAR does not show which locator action ran, which assertion failed, or what the DOM looked like. It also increases the amount of network content you must protect. Add it for a specific question, then remove it when that question is answered.
The cost of redaction is reduced detail. Over-redaction can erase the tenant, feature flag, or correlation value that explains the incident. Prefer a derived summary produced by test code, as in the example, because its safe fields are obvious in review.
Know when more tracing is the wrong fix
Do not increase trace retention when the existing trace already proves the request returned 200 and the UI assertion failed. That case belongs in client-state, rendering, or application-log analysis. More copies of the same successful exchange add storage, not signal.
Avoid tracing every pass to compensate for an uncorrelated test. Give each attempt a test identity that also appears in server logs, then compare evidence from the same attempt. Timestamps alone are weak when parallel workers issue identical requests.
Do not block service workers merely to make a service-worker feature pass. You would be removing the component under test. Likewise, do not replace an integrated backend request with a route mock while investigating backend availability. Either change can make the symptom vanish without fixing the product.
Finally, a force-killed worker or terminated CI job may not flush its trace archive. When that is the suspected boundary, preserve runner output and infrastructure termination events, and reproduce with a controlled timeout. The right evidence may live outside Playwright because the process responsible for writing trace.zip never got the chance to finish.
// FIELD DISPATCH
Get the QA Field Notes
Weekly QA battles, AI testing guides, and interview drills. Free on Substack.
// LIVE COURSE / THE TESTING ACADEMY
Playwright Automation Mastery
Go beyond Selenium. Master Playwright with JS/TS in 90 days.
From the instructor behind this guide.
Playwright jobs are growing 8x faster than Selenium. 90 days / 75+ live hrs / Tue-Thu-Sat 7 AM IST.
PRIMARY REFERENCES
Verify the details at the source
QABattle guides are practical explanations. Product behavior, standards, and APIs can change, so use these primary references for the canonical details.
- 01Official playwright.dev reference
playwright.dev
Primary documentation selected and verified for the claims in this guide.
- 02Official playwright.dev reference
playwright.dev
Primary documentation selected and verified for the claims in this guide.
- 03Official playwright.dev reference
playwright.dev
Primary documentation selected and verified for the claims in this guide.
- 04Official playwright.dev reference
playwright.dev
Primary documentation selected and verified for the claims in this guide.
FAQ / QUICK ANSWERS
Questions testers ask
Why is there no trace.zip after my Playwright test fails?
The usual cause is the trace mode. `on-first-retry` records the first retry, not the initial run, so it produces nothing when retries are disabled. Use `retain-on-failure` when the original failed attempt is the evidence you need.
Does requestfailed fire for a 500 response in Playwright?
No. An HTTP 500 is still a completed HTTP response, so inspect the response status instead. The `requestfailed` event is for transport failures such as a refused connection or an aborted request.
Can I rely on the Network tab instead of asserting the response?
Treat the Network tab as diagnostic evidence, not as the test oracle. Wait for the relevant response and assert its status or the resulting UI state in the test, then use the trace to explain a failure.
Why does Playwright miss a request handled by a service worker?
A service worker can sit between the page and the network, which changes which page-level routing events are visible. Browser-context events can expose service-worker traffic in Chromium, or you can block service workers when the test is meant to observe direct page traffic.
Should CI keep a Playwright trace for every passing test?
Keep every trace only for a short diagnostic run. Continuous recording adds time, storage, and sensitive-data exposure, so a failure-retention mode is a better default for most pipelines.
RELATED GUIDES
Continue the learning route
GUIDE 01
Debug Agent-Generated Playwright Tests with Trace Evidence
Master Playwright agent trace debugging with practical examples, architecture decisions, failure analysis, CI guidance, metrics, and scenario-led interview answers.
GUIDE 02
Playwright Evidence Pipeline for Traces, Video, and Screenshots
Playwright evidence pipeline architecture: practical design, implementation, debugging, CI, metrics, and interview guidance for QA, SDET, and automation engineers.
GUIDE 03
Redact Secrets from Playwright HAR and Trace Evidence
Learn Playwright HAR trace secret redaction with working code, failure cases, debugging steps, and CI evidence for reliable QA automation in practice.
GUIDE 04
Analyze Playwright Traces from the Command Line
A practical guide to Playwright CLI trace analysis for agents, with implementation examples, debugging workflows, CI evidence, security controls, and release gates.
GUIDE 05
Playwright Agentic Browser Automation and Evidence Guide
A practical guide to Playwright agentic browser automation evidence, with implementation examples, debugging workflows, CI evidence, security controls, and release gates.