When testing web applications, we often depend on external APIs or backend services. If these services are down, slow, or return data we can’t control, our tests fail.
Instead of relying on a real backend for every scenario, you can use Playwright to intercept network requests and modify the responses before they even reach your frontend.
What Is It?
Playwright allows you to “hook” into the browser’s network layer. Using the page.route method, you can catch a request, fetch the real data from the server, change it (patch it), and then give the modified version back to the application.
It’s like having a proxy sitting inside your test that can rewrite data in real-time.
Why QA Teams Should Use It
In enterprise projects, this is useful for:
- Testing Edge Cases: Force a specific field to be empty or an extremely long string to see if the UI breaks.
- Simulating Issues: Change a
200 OKresponse to a500 Internal Server Errorto test your app’s error handling. - Dynamic Tweaks: Modify specific values (like a user’s role or a feature flag) without needing to change the database.
- Debugging: If you suspect a UI bug is caused by certain data, you can “fake” that data quickly to confirm.
Installation & Setup
You don’t need any extra plugins. Everything is built into @playwright/test.
If you are starting fresh:
npm init playwright@latest
Practical Implementation Example
Let’s say you want to test how your page looks when a specific prefix is added to the page title, but you don’t want to change the actual HTML file on the server.
Here is how you intercept a request for title.html, fetch the real content, modify it, and fulfill the request.
import { test, expect } from '@playwright/test';
test('Modify API response on the fly', async ({ page }) => {
// 1. Set up the interceptor before navigating
await page.route('**/title.html', async (route) => {
// 2. Fetch the real response from the server
const response = await route.fetch();
// 3. Get the original body as text
let body = await response.text();
// 4. Modify the content (e.g., inject a prefix into the title tag)
body = body.replace('<title>', '<title>QA_DEBUG: ');
// 5. Fulfill the request with our modified body
await route.fulfill({
response,
body,
headers: {
...response.headers(),
'content-type': 'text/html'
}
});
});
// 6. Navigate to the page
await page.goto('https://your-site.com/title.html');
// 7. Verify the modification
await expect(page).toHaveTitle(/QA_DEBUG:/);
});
What happened here?
route.fetch()calls the actual server.body.replace()changes the data in memory.route.fulfill()sends the “fake” data to the browser. The browser thinks this came directly from the server.
Advantages
- Stability: Your tests will be fail-safe even if the backend data changed.
- Speed: Fetching and modifying a response is usually faster than setting up complex state in a database.
- No Code Changes: You don’t need to ask developers to add “test modes” to the application code.
- Use it when: You need to test UI reactions to specific, hard-to-trigger data scenarios.
Conclusion
Modifying responses on the fly is one of the most powerful features in Playwright. It moves you away from “flaky” tests and gives you full control over the environment. Instead of waiting for the backend team to build a specific scenario for you, you can just script it yourself in seconds.

