Skip to content

Add Set Extra HTTP Headers keyword to change request headers mid-test #5115

Description

@Snooz82

Use case

Extra HTTP headers (auth tokens, correlation/tracing IDs, tenant selectors, feature-flag headers) can currently only be set once, at New Context time via extraHTTPHeaders. When a test obtains a fresh token mid-session — after login, after a token refresh, or when switching users — the only way to change headers today is to close the context and create a new one, which throws away all page state, cookies and open pages. Playwright allows updating the headers on a live context (or page) at any time; the library should too.

Proposed keyword / arguments

Set Extra HTTP Headers &{headers} *, scope=Context

  • headers — free named arguments (or a dict) of header name → value; applied to all subsequent requests. Header values must be strings.
  • scope — Context (default): headers apply to every page in the current context, including pages opened later; Page: only requests initiated by the current page (page-level headers are merged over context-level ones, per Playwright semantics).
New Context
New Page    ${URL}/login
# ... perform login, obtain a token ...
Set Extra HTTP Headers    Authorization=Bearer ${token}    X-Correlation-Id=${test_id}
Go To    ${URL}/dashboard

# Override for the current page only
Set Extra HTTP Headers    X-Experiment=variant-b    scope=Page

Playwright API

Implementation notes

  • New RPC in protobuf/playwright.proto carrying the header map plus a page/context flag.
  • node/playwright-wrapper: resolve current page or context from the catalog, call setExtraHTTPHeaders.
  • Python keyword (natural home: Browser/keywords/network.py or playwright_state.py), docs, atest asserting the header arrives server-side (test app echoes request headers) and that scope=Context covers a page opened after the call.

Backwards compatibility

Purely additive: a new keyword; the existing New Context extraHTTPHeaders= argument is untouched and simply provides the initial value the keyword can later replace.

Activity

  1. self-assigned this
    on Aug 6, 2026
  2. added theissue type on Aug 6, 2026
  3. added this to the Ecosystem project milestone on Sep 26, 2026
  4. aaltat commented on Nov 7, 2026

    @aaltat
    Member

    Update after the Playwright 1.63–1.65 review (main at 5e35099)

    • Still not implemented. Nothing in node/playwright-wrapper calls setExtraHTTPHeaders. Headers can only be set at creation time, through extraHTTPHeaders on New Context (Browser/keywords/playwright_state.py:811) and New Persistent Context (playwright_state.py:1021). No atest covers extraHTTPHeaders, so the work for this issue should first add a test that the existing New Context argument reaches the server.
    • No API change in 1.63–1.65. browserContext.setExtraHTTPHeaders and page.setExtraHTTPHeaders have the same signatures and docs in 1.62 and 1.65.
    • The call replaces the whole set; it does not merge. Playwright's server code assigns the new map in place of the old one, and there is no getter for the current headers. For example, after New Context extraHTTPHeaders={'X-Tenant': 'a'}, the call Set Extra HTTP Headers Authorization=... stops sending X-Tenant. The keyword docs must say this, or the keyword must merge the new headers with the ones it already knows. Merging is possible only if the library tracks the headers per context.
    • scope already means something else in this library. scope is the Scope enum (Global, Suite, Test) for the lifetime of a setting (Browser/utils/data_types.py:1590, used by Set Browser Timeout, Set Strict Mode and others). Using scope=Context|Page for a different idea would confuse users. Use a different name for the context/page choice, or support only the context level. Only the context level matches the existing context setters Set Offline and Set Geolocation (node/playwright-wrapper/browser-control.ts:131,145), which is also the natural home for the Node side.
    • Headers now reach WebSocket handshakes. Playwright 1.63 added tests showing that extra HTTP headers are sent on the WebSocket handshake with Chromium 151 and later and with WebKit (test(websocket): cover setExtraHTTPHeaders and locale on the handshake request microsoft/playwright#42037). Firefox still does not send them for a WebSocket opened inside a Worker. This helps the token use case and should go in the keyword docs.
    • Basic auth has a separate API since 1.63. browserContext.setHTTPCredentials is no longer deprecated. It accepts an array of {username, password, origin} entries, so credentials can be limited to one origin and changed mid-test. An Authorization header set with setExtraHTTPHeaders goes to every origin the page calls, third-party origins included. The keyword docs should warn about this. If the request is really about Basic auth, credentials are a better fit than headers. The 1.65 fix that stops proxy credentials from answering website auth challenges (fix: do not send proxy credentials to website auth challenges microsoft/playwright#43482) does not affect headers.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions