Select Page
Automation Testing

Playwright HAR Replay: A Practical Guide for Network-Driven Tests

Learn Playwright HAR replay for scoped network mocking, strict request matching, fixture maintenance, and CI safety across browser tests.

Purusoth Kumar

Senior Automation Test Engineer

Posted on

15/10/2026

Playwright HAR replay lets a browser test fulfill matching HTTP requests from a saved HTTP Archive instead of requiring the same live API to respond on every run. The practical pattern is to record traffic from a controlled test environment, scope the HAR to the endpoints the UI scenario needs, and install routeFromHAR() before the application sends those requests. For requests that enter the HAR route but do not match an entry, Playwright can abort or fall back according to the configured notFound policy (Playwright HAR mocking guide). This guide is based on @playwright/test 1.63.0, the npm latest stable release verified on October 7, 2026.

Critical scope rule: A url filter and notFound solve different problems. The url option decides which requests enter the HAR route. notFound decides what happens when an in-scope request has no matching HAR entry. Requests outside the HAR url filter are not made hermetic by notFound: 'abort'.

Playwright HAR replay is most useful when the purpose of the test is to validate browser behavior under a known HTTP response state. It does not rerun server business logic, database work, queues, downstream services, or recorded network timing. Keep direct API, contract, integration, and selected live end-to-end coverage for those risks. Codoid’s QA automation services combine all these layers in a single strategy.

Table of Contents

Key Takeaways

  • HAR replay is match-driven. Playwright matches recorded exchanges by URL and HTTP method, and POST requests also require matching POST data.
  • A scoped routeFromHAR() does not control traffic outside its URL pattern. Model full network isolation separately when you need it.
  • Use notFound: 'abort' to expose missing in-scope HAR entries. Use fallback only when another route or the network is intentionally allowed.
  • Use focused HAR fixtures for coordinated UI states, hand-written routes for volatile or synthetic edge cases, and real API and end-to-end coverage for integration confidence.
  • HAR replay does not reproduce recorded latency and does not put the browser offline. Those are separate test dimensions.

What Playwright HAR Replay Testing Actually Does

A HAR file captures a collection of HTTP request and response exchanges from a browser journey. It can include request and response headers, cookies, content, timings, and other metadata. Playwright can route browser requests against that collection and fulfill a request when the current request matches a recorded entry. This is request matching, not a general guarantee that responses are consumed in the temporal order in which they were originally recorded (Playwright Mock APIs).

That distinction matters when the same endpoint is called repeatedly. If multiple recordings match, Playwright selects the entry with the greatest number of matching headers. Do not depend on recorded order to distinguish otherwise indistinguishable requests. Instead, make the request state distinguishable, split scenarios into separate fixtures, or use a focused hand-written mock.

What HAR Replay Can and Cannot Reproduce

S. No Test concern HAR replay fit Use instead or alongside when needed
1 Recorded HTTP status, headers, and response body Strong fit when the request matches a HAR entry route.fulfill() for a smaller synthetic response
2 Coordinated multi-request UI data state Strong fit Direct API setup if the test must create real backend state
3 Redirects Supported for matching recorded redirects Live coverage if redirect behavior depends on current server policy
4 Different POST inputs Only when POST data matches a recording Separate fixtures or route.fulfill() for broad input variation
5 Offline behavior HAR replay does not put the browser context offline use.offline or browserContext.setOffline(true)
6 Slow or variable latency Recorded HAR timing is not replayed as network delay Dedicated network conditioning or application-specific delay injection
7 Server logic, databases, queues, downstream services Not reproduced API, contract, integration, and live end-to-end tests

When Playwright records a minimal HAR for routing, it intentionally omits timing, page, cookie, security, size, and other HAR fields that are not used for replay. That is why a response that was slow during capture does not automatically replay slowly (BrowserContext.routeFromHAR()).

How Playwright Matches Requests to HAR Entries

Playwright matches the request URL and HTTP method strictly. For POST requests, it also matches the POST payload strictly. If several entries qualify, the recording with the most matching headers is chosen. Matching redirects are followed automatically.

S. No Request change Likely outcome Testing implication
1 GET /api/orders?page=1 becomes page=2 The URL differs, so the original entry may not match Record the intended variant or mock that volatile request separately
2 POST quantity changes from 1 to 2 POST data no longer matches strictly Use separate scenario data or a focused route
3 Generated timestamp or UUID changes Payload or query may miss the fixture Stabilize test data or isolate the volatile endpoint
4 Several entries have the same URL, method, and body Headers may disambiguate. Recorded order is not the documented selector Do not rely on temporal sequence playback
5 A new endpoint is introduced If inside HAR scope, notFound applies. If outside scope, HAR does not control it Decide deliberately whether that dependency belongs in the fixture

How to Record a HAR File in Playwright

Prerequisite for Relative URLs: Configure baseURL

The examples below use relative navigation such as page.goto('/orders'). That requires Playwright Test to have use.baseURL configured. If your project does not configure baseURL, use an absolute URL in page.goto() (Playwright baseURL guidance).

    import { defineConfig } from '@playwright/test';

    export default defineConfig({
      use: {
        baseURL: 'https://test.example.com',
      },
    });
    

Record a Focused Fixture With routeFromHAR({ update: true })

For a test-specific fixture, use update: true while authoring or deliberately refreshing the HAR. In update mode, Playwright records actual network information instead of serving from the existing HAR and writes the file when the browser context closes. Limit the recording to the endpoints the scenario needs whenever possible.

    import { test, expect } from '@playwright/test';

    test('record orders API fixture', async ({ page }) => {
      await page.routeFromHAR('tests/hars/orders-success.har.zip', {
        url: '**api**',
        update: true,
        updateMode: 'minimal',
        updateContent: 'attach',
      });

      await page.goto('/orders');
      await expect(
        page.getByRole('heading', { name: 'Orders' })
      ).toBeVisible();
    });
    

Authoring safeguard: Do not leave update: true enabled in the normal replay path. With update enabled, the test is recording current network information rather than proving that the saved fixture can replay the scenario.

Record HAR Quickly From the Playwright CLI

The CLI is useful for exploratory capture. Open the browser, exercise the flow, and save only API requests. Playwright documents --save-har and --save-har-glob for this workflow.

    npx playwright open \
      --save-har=orders.har.zip \
      --save-har-glob="**api/**" \
      https://example.com
    

For repeatable suite maintenance, prefer a test-controlled recording path such as routeFromHAR({ update: true }) so the same setup, credentials, and navigation can be reviewed in code. Use CLI capture when you are discovering the required traffic or creating an initial fixture interactively.

Other Recording Options: recordHar and tracing.startHar()

browser.newContext({ recordHar: ... }) records network traffic for the entire context until it closes. Its mode defaults to full. Content defaults to attach for .zip output and embed for other file extensions. Await browserContext.close() so the HAR is saved.

    const context = await browser.newContext({
      recordHar: {
        path: 'tests/hars/orders.har.zip',
        urlFilter: '**/api/**',
        mode: 'minimal',
      },
    });

    const page = await context.newPage();
    await page.goto('https://test.example.com/orders');
    await context.close();
    

Playwright also provides tracing.startHar() and tracing.stopHar(), added in v1.60. This can be useful when HAR capture needs to be started and stopped explicitly within the lifecycle of an existing context.

Choosing Minimal vs Full and Embed vs Attach

S. No Option Best fit Important behavior
1 minimal Replay-oriented fixtures Keeps information required for HAR routing and omits replay-unused metadata
2 full Inspection or external HAR tooling needs fuller metadata Default for recordHar and tracing.startHar()
3 embed Keep response bodies inside HAR JSON Convenient single HAR, potentially bulky
4 attach Keep response bodies as attached resources or ZIP entries Convenient for .har.zip fixture packaging

How to Replay a HAR with routeFromHAR()

page.routeFromHAR() vs browserContext.routeFromHAR()

S. No Use case Prefer
1 One page owns the scenario and all relevant traffic page.routeFromHAR()
2 Popups, multiple pages, or shared browser-context traffic must use the same fixture browserContext.routeFromHAR()

Install the HAR route before the first request you expect it to handle.

Replay a Known API State

    import { test, expect } from '@playwright/test';

    test('shows the recorded orders state', async ({ page }) => {
      await page.routeFromHAR('tests/hars/orders-success.har.zip', {
        url: '**/api/**',
        notFound: 'abort',
      });

      await page.goto('/orders');
      await expect(page.getByText('ORD-1042')).toBeVisible();
      await expect(page.getByText('Ready to ship')).toBeVisible();
    });
    

The order ID and UI copy above are illustrative. Replace them with controlled test data from your application.

URL Scope vs notFound: The Critical Difference

Rule: url decides whether a request is handled by the HAR route. notFound decides what happens when an in-scope request has no matching HAR entry.

S. No Request With url: **/api/** Effect of notFound: abort
1 /api/orders Inside HAR scope If no HAR entry matches, the request is aborted
2 /api/recommendations Inside HAR scope If unrecorded, the request is aborted
3 /analytics/events Outside HAR scope The HAR route does not serve or abort it. Another route or the network may handle it
4 /assets/app.css Outside HAR scope The HAR route does not control it

If you need a fully isolated browser-network test, design that isolation explicitly. For example, keep the HAR focused on application APIs and add separate allow-list or blocking routes for third-party analytics, telemetry, or other out-of-scope traffic. Do not assume a narrow HAR url filter plus notFound: 'abort' blocks every browser request.

Abort vs Fallback

Use abort when an unexpected missing HAR entry inside the route scope should fail the test. Use fallback when the missing in-scope request is intentionally allowed to continue. At browser-context level, fallback continues to the next route handler. If nothing else handles the request, it can ultimately reach the network. At page level, Playwright documents fallback as sending missing requests to the network.

S. No Policy Use it when Primary risk
1 abort You want in-scope fixture misses to fail visibly Legitimate API changes require deliberate fixture updates
2 fallback A hybrid scenario intentionally permits another route handler or live request Unreviewed live dependencies can reduce isolation

Request-to-HAR Decision Flow

    Does the request URL match routeFromHAR({ url: ... })?
        ↓
    Yes → Does a HAR entry match URL + method
          (plus POST data when applicable)?
              ↓
          Yes → Fulfill from the HAR
          No  → Apply notFound: abort or fallback

    No  → The HAR route does not handle it.
          Another route or the network may.
    

Service Workers, WebSockets, Offline Mode, and Other Boundaries

Service Workers

Playwright does not serve requests intercepted by a Service Worker from HAR and recommends blocking Service Workers for request-interception tests when necessary. However, blocking a worker can change application behavior, so keep worker-enabled coverage when caching, offline behavior, or worker routing is itself under test. Playwright documents Service Worker support as Chromium-based.

    import { defineConfig } from '@playwright/test';

    export default defineConfig({
      use: {
        serviceWorkers: 'block',
      },
    });
    

HAR Replay Does Not Mock WebSocket Messages

HAR replay is an HTTP and HTTPS request-response fixture mechanism. If the application uses WebSockets, use page.routeWebSocket() or browserContext.routeWebSocket() for WebSocket message mocking or interception, or keep live integration coverage for the socket behavior.

Offline and Latency Are Separate Test Dimensions

HAR replay does not make the browser offline. Use the offline context option or browserContext.setOffline(true) when the scenario requires no network. Likewise, do not treat recorded HAR timing as latency replay. Minimal HAR routing omits timing because it is not used to fulfill requests.

How to Maintain HAR Fixtures Safely in Git and CI

Playwright’s guide describes committing HAR fixtures alongside tests. That can make CI repeatable, but HAR data can contain headers, cookies, response bodies, and other captured information. Treat every HAR as reviewable test data rather than assuming it is safe to commit.

  • Record from a controlled test environment, not from a production session containing real customer data.
  • Use synthetic accounts and stable test data where possible.
  • Filter capture to the endpoints required by the scenario.
  • Inspect authorization headers, cookies, query parameters, request bodies, and responses before committing or refreshing a fixture.
  • Use scenario-specific names such as checkout-success.har.zip and checkout-auth-expired.har.zip.
  • Refresh a fixture because intended application or API behavior changed, not merely because the test failed.
  • Review HAR changes in code review and rotate any secret that was accidentally committed. Editing the current file does not remove it from repository history.

A Practical Test-Suite Strategy

The strongest automation strategy uses Playwright HAR replay alongside other layers, not as a replacement for them.

  • Use direct API or contract tests for current service behavior, authorization, business rules, and response contracts.
  • Use HAR-backed browser tests for coordinated, high-value UI scenarios where live dependencies add setup cost or instability without being the subject of the test.
  • Use hand-written routes for small synthetic states or highly volatile requests that are clearer in code than in a HAR fixture.
  • Keep a smaller set of live browser end-to-end checks for integrations that genuinely need end-to-end proof.
  • When a live Playwright test fails, diagnose the original failure before replacing its dependency with a HAR. Mocking should isolate an intentional test boundary, not hide a product or environment defect.

HAR Replay vs route.fulfill() vs Live Backend Testing

S. No Approach Best for Strength Main limitation
1 HAR replay Multi-request browser flows with recorded states Reuses coordinated HTTP exchanges Can become stale. Server logic is not executed
2 route.fulfill() Small mocks and rare or synthetic edge states Explicit and easy to review Noisy if you model many endpoints
3 Direct API and contract tests Service behavior, auth, business rules, contracts Tests the current backend without UI noise Does not validate browser rendering
4 Live browser end-to-end Critical integrated journeys Highest integration realism More environment, data, and network dependencies

A useful ownership rule: mock at the browser boundary when the test question is “How does the UI behave under this known HTTP state?” Use real API and integration coverage when the question is “Can the backend actually produce and process this state now?”

For related debugging guidance, see Codoid’s article on flaky Playwright tests, covering traces, screenshots, network logs, and retries. For direct API automation strategy, see API automation testing with Postman, REST Assured, and Playwright.

Playwright HAR Replay Checklist

S. No Check Detail
1 Define HAR route scope Specify exactly which requests belong inside the HAR route scope
2 Configure baseURL Set use.baseURL before copying examples that use relative page.goto() URLs, or use absolute navigation URLs
3 Record from a controlled environment Use synthetic data and a narrow URL filter
4 Choose HAR format deliberately Prefer minimal for replay-only fixtures. Choose .har or .har.zip with intent
5 Install route before requests Call routeFromHAR() before the first matching request fires
6 Use abort for fixture misses Fail visibly when unexpected in-scope entries are missing. Control out-of-scope traffic separately if full network isolation is required
7 Compare POST bodies and volatile fields Match POST bodies, timestamps, UUIDs, and query parameters when a recording stops matching
8 Handle Service Workers correctly Block Service Workers only when worker behavior is not itself part of the test objective
9 Use routeWebSocket for WebSockets Do not use HAR replay for WebSocket message behavior
10 Review HAR fixtures before commit Inspect for credentials, cookies, and sensitive payloads
11 Refresh fixtures only on intended change Keep real API and integration coverage as an independent source of truth

Conclusion

Playwright HAR replay is most reliable when teams treat it as deliberate fixture design. Scope the HAR carefully, understand strict request matching, distinguish route scope from notFound behavior, and use fixture misses as diagnostic signals instead of reflexively refreshing the archive. That gives browser tests stable, reviewable HTTP states without pretending the recorded responses prove that the current backend still works. The strongest automation strategy combines Playwright HAR replay for coordinated UI states, route.fulfill() for focused synthetic conditions, direct API and contract testing for service behavior, and selected live end-to-end journeys for integration confidence.

If network-driven Playwright flakiness or unclear test boundaries are making CI difficult to trust, Codoid’s QA automation services include Playwright-based web automation and broader API automation capabilities.

Need Help Stabilizing Your Playwright Network Tests?

Talk to a Playwright Automation Expert

Frequently Asked Questions

  • How do I record a HAR file in Playwright?

    Use routeFromHAR() with update: true for a test-controlled fixture, browser.newContext({ recordHar: ... }) for context-wide capture, tracing.startHar() when you need explicit start and stop control, or the CLI --save-har option for quick interactive recording.

  • What is the difference between page.routeFromHAR() and browserContext.routeFromHAR()?

    page.routeFromHAR() applies to requests made by that page. browserContext.routeFromHAR() applies across pages in the context, which is usually the better fit for popups or multi-page flows that share one fixture.

  • Why does my Playwright HAR POST request not match?

    Playwright matches POST data strictly in addition to URL and HTTP method. Dynamic timestamps, generated IDs, signatures, or changed JSON fields can make the request miss the recorded entry.

  • What is the difference between notFound: abort and fallback?

    abort fails an in-scope request when the HAR has no matching entry. At context scope, fallback continues to the next route handler and can eventually reach the network. At page scope, Playwright documents missing fallback requests as going to the network.

  • Does notFound: abort block requests outside the HAR URL filter?

    No. Requests outside the routeFromHAR url filter are not handled by that HAR route, so notFound does not apply to them. Add separate route controls if full network isolation is required.

  • Can Playwright HAR replay simulate offline mode or slow latency?

    No. HAR replay fulfills recorded HTTP exchanges. It does not put the context offline or replay recorded timing as latency. Use Playwright offline emulation for offline tests and a separate network-conditioning approach for latency and bandwidth scenarios.

  • Does HAR replay work with Service Workers?

    Requests intercepted by a Service Worker are not served from HAR. You can block Service Workers for interception-focused tests, but keep separate worker-enabled coverage when worker behavior matters.

  • Does HAR replay mock WebSocket messages?

    No. Use page.routeWebSocket() or browserContext.routeWebSocket() for WebSocket message mocking or interception.

  • Should Playwright HAR files be committed to Git?

    They can be, and Playwright documents committing HAR fixtures with tests. First inspect them for secrets, cookies, sensitive data, and unnecessary traffic. Prefer controlled synthetic test data.

  • When should a HAR fixture be refreshed?

    Refresh it when the intended API contract, request shape, or scenario data has changed. Do not automatically regenerate a failing fixture, because that can overwrite a useful regression signal.

  • Can HAR replay replace API or end-to-end testing?

    No. HAR replay isolates selected browser behavior from live dependencies. Keep real API, contract, and integration tests for backend confidence, and a smaller set of live end-to-end checks for critical integrated journeys.

Comments(0)

Submit a Comment

Your email address will not be published. Required fields are marked *

Talk to our Experts

Amazing clients who
trust us


poloatto
ABB
polaris
ooredo
stryker
mobility