You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Browser-originated requests expose detailed network phase timings via Request.timing() (DNS, connect, TLS, TTFB, receive). Requests made through APIRequestContext (request.get/post/..., fetch) return an APIResponse that has no equivalent — the only way to get any timing today is to wall-clock the call in userland, which yields a single opaque total.
I'd like to propose exposing the per-phase ResourceTiming on APIResponse, read-only, mirroring Request.timing().
Why this is a thin change, not a new capability
Playwright already collects and maintains these exact timings for APIRequestContext — they were added in #32613 (merged) and recorded into the HAR/trace (the trace viewer already shows the duration), and proxy edge cases have since been fixed (#32855). So the data already exists in memory; this request is only to surface it through the public API instead of requiring users to parse trace/HAR artifacts.
A previous PR (#32647) implemented exactly this but was closed with the rationale that "Playwright isn't a network performance testing tool." Respectfully, I'd push back on two points:
This isn't about load/performance testing — it's diagnostic parity with browser requests, which already expose timing().
"Rough timings can be measured in userland" only holds for total time. The phase breakdown requires socket-level events (lookup / connect / secureConnect / response) on the connection Playwright owns inside fetch.ts, including redirect and proxy handling — userland has no access to it. feat(fetch): expose timings #32647 itself surfaced the SOCKS/HTTP-proxy connect timing bug fixed in fix(har timing): record connect timing for proxied connections #32855, which no userland wrapper could have measured correctly.
The shape would be identical to Request.timing(), so there are no new concepts to learn. It could also be gated behind the existing omitTiming option to stay opt-out.
Motivation / use cases
Debugging slow or flaky API tests in CI: knowing whether latency came from DNS, TLS handshake, or the server, instead of one aggregate number.
Synthetic monitoring built on Playwright (e.g. Elastic Synthetics, Checkly) that runs browser and API checks side by side and needs consistent network fields across both. Downstream context: feat: multi step api runner elastic/synthetics#997.
🚀 Feature Request
Browser-originated requests expose detailed network phase timings via
Request.timing()(DNS, connect, TLS, TTFB, receive). Requests made throughAPIRequestContext(request.get/post/...,fetch) return anAPIResponsethat has no equivalent — the only way to get any timing today is to wall-clock the call in userland, which yields a single opaque total.I'd like to propose exposing the per-phase
ResourceTimingonAPIResponse, read-only, mirroringRequest.timing().Why this is a thin change, not a new capability
Playwright already collects and maintains these exact timings for
APIRequestContext— they were added in #32613 (merged) and recorded into the HAR/trace (the trace viewer already shows the duration), and proxy edge cases have since been fixed (#32855). So the data already exists in memory; this request is only to surface it through the public API instead of requiring users to parse trace/HAR artifacts.A previous PR (#32647) implemented exactly this but was closed with the rationale that "Playwright isn't a network performance testing tool." Respectfully, I'd push back on two points:
timing().lookup/connect/secureConnect/response) on the connection Playwright owns insidefetch.ts, including redirect and proxy handling — userland has no access to it. feat(fetch): expose timings #32647 itself surfaced the SOCKS/HTTP-proxyconnecttiming bug fixed in fix(har timing): recordconnecttiming for proxied connections #32855, which no userland wrapper could have measured correctly.Example
The shape would be identical to
Request.timing(), so there are no new concepts to learn. It could also be gated behind the existingomitTimingoption to stay opt-out.Motivation / use cases
Prior art / recurring demand
APIResponse.timing(); closed unmergedHappy to help revive #32647 or open a fresh PR if the team is open to a read-only accessor over the already-recorded timings. Thanks for considering!