How do I wait for a network response in Playwright?
Written by Jatin Thacker, Automation Architect · Updated
page.waitForResponse() before the action that sends the request, without await, then perform the action and await the promise. It resolves with the matching Response, so you can check its status and read its JSON.This answer is one piece of Chapter 13: Waiting and Synchronisation.
- Auto-Waiting Deep Dive
- Explicit Waiting Methods
- Handling Race Conditions
- Controlling the Clock
- Practice and interview questions: Waiting & Synchronization
Order matters. If you click first and start waiting afterwards, a fast response can arrive in between, and the wait sits there until it times out. So store the promise, click, then await it.
waitForResponse() accepts a URL string, a regular expression, or a predicate that receives each Response. A predicate lets you match on more than the URL, such as the status code.
In the example:
- The test opens the API Lab and waits for the first load's rows, so the wait cannot catch that earlier request by mistake.
- It starts waiting for a
/api/productsresponse with status 200. - It clicks Refresh products and awaits the promise.
- It reads the JSON and asserts the table shows one row per item in the response.
The URL pins ?mock=static on purpose. By default the practice app answers API calls from a service worker inside the browser. In ?mock=static mode the same calls travel over the network to snapshot files. waitForResponse sees the response in either mode, but page.route() and page.request only work in static mode, so pinning it keeps this example consistent with those.
import { test, expect } from '@playwright/test';
test('wait for the products response a button triggers', async ({ page }) => {
await page.goto('/api-lab.html?mock=static&seed=42');
const rows = page.getByTestId('live-product-row');
await expect(rows.first()).toBeVisible(); // the first load has finished
const responsePromise = page.waitForResponse(
(res) => res.url().includes('/api/products') && res.status() === 200
);
await page.getByRole('button', { name: 'Refresh products' }).click();
const response = await responsePromise;
const body = await response.json();
await expect(rows).toHaveCount(body.items.length);
});1 passed (1.5s)
Practised in the full course: the drill Interception: Service Workers.
See the chapterRelated questions
AI can write the test now. The job is knowing whether it checks anything. That's what the course teaches, one chapter at a time.
163 lessons · 226 drills · start free