Playwright Network Idle Timeout Issue: Causes, Fixes, and Troubleshooting Guide

Introduction: What Does the Playwright Network Idle Timeout Issue Mean?

The playwright network idle timeout issue happens when a Playwright test waits for the page’s network activity to become idle, but the required idle state is never reached before the timeout.

A common example is:

await page.goto(‘https://example.com’, {

  waitUntil: ‘networkidle’

});

The test may eventually fail with a navigation timeout even though the application itself is working correctly.

This is especially common with modern applications that continuously make requests for analytics, advertisements, polling, WebSockets, notifications, live data, or background APIs.

For beginners, the important lesson is simple:

Do not assume that “no network requests” means “the page is ready.”

Playwright already provides auto-waiting for many UI actions and assertions. In most cases, waiting for a specific application condition is more deterministic than waiting for the entire network to become idle.


What Is networkidle in Playwright?

networkidle is a navigation waiting condition that waits until there are no network connections for at least 500 milliseconds.

For example:

import { test, expect } from ‘@playwright/test’;

test(‘wait for network idle’, async ({ page }) => {

  await page.goto(‘https://example.com’, {

    waitUntil: ‘networkidle’

  });

  await expect(page.getByRole(‘heading’)).toBeVisible();

});

Although networkidle can be useful in specific situations, Playwright’s documentation discourages using it as a general readiness signal for testing. The application may be usable even while background requests continue.

That distinction explains many Playwright network idle timeout issue failures.


Why Does Playwright networkidle Timeout?

The most common causes are:

  1. Analytics requests continuously run.
  2. WebSocket connections remain open.
  3. Polling APIs repeatedly request data.
  4. A backend API responds slowly.
  5. Third-party resources never settle.
  6. SPA applications make background requests.
  7. CI machines are slower than local machines.
  8. The configured timeout is too small.
  9. The application redirects or performs additional navigation.
  10. The test is waiting for network idle when it should wait for a UI condition.

The important question is not only “Why is Playwright waiting?”, but “What exactly should the test wait for?”


Difference Between networkidle, load, and domcontentloaded

These three options have different meanings.

OptionMeaningTypical Use
domcontentloadedHTML document has been parsedFast initial page checks
loadPage load event has firedTraditional page loading
networkidleNetwork has been idle for a periodSpecific cases where network settling matters

Example:

await page.goto(‘https://example.com’, {

  waitUntil: ‘domcontentloaded’

});

Or:

await page.goto(‘https://example.com’, {

  waitUntil: ‘load’

});

Or:

await page.goto(‘https://example.com’, {

  waitUntil: ‘networkidle’

});

For most UI tests, domcontentloaded or the default navigation behavior combined with a meaningful locator assertion is often more reliable than forcing networkidle.


Common Causes of Playwright Network Idle Timeout

1. Analytics Requests Never Stop

Problem: networkidle never completes.

Cause: Google Analytics, telemetry, tracking pixels, or monitoring scripts continue sending requests.

Incorrect approach:

await page.goto(‘https://myapp.com’, {

  waitUntil: ‘networkidle’

});

Correct solution:

await page.goto(‘https://myapp.com’);

await expect(

  page.getByRole(‘heading’, { name: ‘Dashboard’ })

).toBeVisible();

Best practice: Wait for the application state your test actually needs.


2. WebSocket Connections Remain Open

Problem: A chat or trading application keeps a connection open.

Cause: WebSockets are designed to remain active.

Incorrect approach:

await page.waitForLoadState(‘networkidle’);

Correct solution:

await page.goto(‘https://myapp.com’);

await expect(

  page.getByTestId(‘dashboard’)

).toBeVisible();

The WebSocket can remain active while the UI is already ready.


3. Polling APIs Continuously Run

Some applications request data every few seconds:

GET /notifications

GET /notifications

GET /notifications

Waiting for complete network inactivity is therefore inappropriate.

Instead, wait for the specific UI state:

await expect(

  page.getByText(‘Notifications loaded’)

).toBeVisible();


4. Slow Backend Responses

Problem: The test passes locally but times out in CI.

Cause: The API takes longer to respond in the CI environment.

Incorrect approach: Increase the timeout repeatedly without understanding the slow request.

Correct solution:

Wait for the important API:

await page.waitForResponse(response =>

  response.url().includes(‘/api/dashboard’) &&

  response.status() === 200

);

Then validate the UI.


Using waitForResponse() for Specific API Calls

If your test depends on an API response, synchronize with that API instead of the entire network.

import { test, expect } from ‘@playwright/test’;

test(‘dashboard loads API data‘, async ({ page }) => {

  const responsePromise = page.waitForResponse(response =>

    response.url().includes(‘/api/dashboard’) &&

    response.request().method() === ‘GET’ &&

    response.status() === 200

  );

  await page.goto(‘https://example.com/dashboard’);

  await responsePromise;

  await expect(

    page.getByTestId(‘dashboard-data’)

  ).toBeVisible();

});

This approach is much more deterministic.

The test is saying:

I need the dashboard API to complete.”

It is not saying:

“Every network request on this website must stop.”


When to Avoid waitUntil: ‘networkidle’

Avoid networkidle when your application contains:

  • WebSockets
  • Server-sent events
  • Polling
  • Analytics
  • Advertisements
  • Live notifications
  • Continuous background requests
  • Third-party integrations

Instead, identify the actual condition required by the test.

For example:

await page.goto(‘https://example.com’);

await page.getByRole(‘button’, {

  name: ‘Create Account’

}).click();

Playwright automatically waits for many actionability conditions before interacting with an element.

You can also use assertions:

await expect(

  page.getByRole(‘heading’, { name: ‘Welcome’ })

).toBeVisible();

This is usually better than manually adding:

await page.waitForTimeout(5000);


Playwright Network Idle Timeout Issue: Slow Applications

Suppose a dashboard loads slowly.

Problem → Dashboard data appears after several seconds.

Cause → Backend response is slow.

Incorrect Approach →

await page.waitForTimeout(10000);

Correct Solution →

await expect(

  page.getByTestId(‘dashboard’)

).toBeVisible({

  timeout: 15000

});

Or synchronize with the API:

await page.waitForResponse(response =>

  response.url().includes(‘/api/dashboard’) &&

  response.ok()

);

Best Practice: Wait for a meaningful application condition rather than guessing a sleep duration.


Configuring Appropriate Playwright Timeouts

If a legitimate operation is slow, configure an appropriate timeout.

import { defineConfig } from ‘@playwright/test’;

export default defineConfig({

  timeout: 30_000,

  use: {

    navigationTimeout: 30_000

  }

});

You can also configure a navigation timeout for a particular test:

test(‘slow application’, async ({ page }) => {

  page.setDefaultNavigationTimeout(45_000);

  await page.goto(‘https://example.com’);

});

Increasing the timeout is useful when the application genuinely needs more time.

It is not a solution for an operation that never becomes idle.


Debugging Network Activity

When troubleshooting a playwright network idle timeout issue, monitor requests.

import { test } from ‘@playwright/test’;

test(‘monitor requests’, async ({ page }) => {

  page.on(‘request’, request => {

    console.log(‘REQUEST:’, request.method(), request.url());

  });

  page.on(‘response’, response => {

    console.log(

      ‘RESPONSE:’,

      response.status(),

      response.url()

    );

  });

  await page.goto(‘https://example.com’);

});

This can reveal:

  • Repeated API calls
  • Failed requests
  • Slow endpoints
  • Third-party requests
  • Unexpected redirects

You can also log failed requests:

page.on(‘requestfailed’, request => {

  console.log(

    ‘FAILED:’,

    request.url(),

    request.failure()?.errorText

  );

});


Network Interception for Troubleshooting

Playwright can intercept requests.

await page.route(‘**/analytics/**’, route => {

  route.abort();

});

await page.goto(‘https://example.com’);

This can be useful for controlled test environments, but do not blindly block production dependencies.

If analytics is irrelevant to the test, intercepting it can make the test more deterministic.


Debugging Navigation Timeouts

Run tests with debugging enabled:

npx playwright test –debug

You can also enable tracing:

npx playwright test –trace=on

Then inspect the trace:

npx playwright show-trace trace.zip

A trace can help identify:

  • Which navigation was waiting
  • What requests were active
  • Which action happened before the timeout
  • Whether the page redirected
  • Whether an element was available

For CI failures, traces are particularly valuable because the problem may not reproduce locally.


Fixing Playwright Network Idle Timeout in CI/CD

A common situation is:

Works on my laptop, fails in GitHub Actions or Docker.

Check:

  • CPU availability
  • Network latency
  • Browser version
  • Node.js version
  • Environment variables
  • API availability
  • Authentication state
  • DNS/network restrictions
  • Third-party services
  • Test parallelism

CI troubleshooting strategy

  1. Enable Playwright traces.
  2. Log requests and failed requests.
  3. Identify the request keeping the application active.
  4. Determine whether that request matters to the test.
  5. Replace global network-idle waiting with targeted synchronization.
  6. Increase timeout only if the operation genuinely needs more time.
  7. Reproduce using the same Docker/browser environment.

Real-World Playwright Network Idle Timeout Examples

Example 1: SPA Dashboard

Problem: Dashboard navigation times out.

Cause: React application continuously polls notifications.

Incorrect:

await page.goto(‘/dashboard’, {

  waitUntil: ‘networkidle’

});

Correct:

await page.goto(‘/dashboard’);

await expect(

  page.getByTestId(‘dashboard’)

).toBeVisible();


Example 2: Login API

If the test depends on login completion:

const loginResponse = page.waitForResponse(response =>

  response.url().includes(‘/api/login’) &&

  response.status() === 200

);

await page.getByLabel(‘Username’).fill(‘testuser’);

await page.getByLabel(‘Password’).fill(‘password’);

await page.getByRole(‘button’, {

  name: ‘Login’

}).click();

await loginResponse;

await expect(

  page.getByRole(‘heading’, { name: ‘Dashboard’ })

).toBeVisible();

This combines API synchronization with UI validation.


Common Mistakes and Solutions

MistakeSolution
Always using networkidleWait for specific UI/API conditions
Using waitForTimeout() everywhereUse assertions and events
Increasing timeout blindlyIdentify the slow request
Ignoring WebSocketsWait for the UI state
Ignoring pollingUse targeted API/UI synchronization
Blocking every third-party requestMock only irrelevant dependencies
Relying on local performanceTest under CI-like conditions
Waiting for all network trafficWait for application readiness

Playwright Network Waiting Best Practices

Use these rules in your automation framework:

1. Prefer UI assertions

await expect(page.getByTestId(‘results’)).toBeVisible();

2. Wait for important APIs

await page.waitForResponse(response =>

  response.url().includes(‘/api/results’) &&

  response.ok()

);

3. Avoid arbitrary sleeps

await page.waitForTimeout(5000);

should rarely be your primary synchronization strategy.

4. Use networkidle selectively

It can be appropriate when you specifically need the network to settle, but it should not automatically become your default wait.

5. Use Playwright auto-waiting

Locators and assertions already provide synchronization for many common UI conditions.

6. Keep CI environments consistent

Use the same browser versions, dependencies, and infrastructure where possible.


Playwright Interview Questions With Answers

What is Playwright network idle?

networkidle is a navigation/load-state condition that waits for network activity to become idle. It should be used selectively rather than as a universal indication that an application is ready.

Why does Playwright networkidle timeout?

Usually because the page continues making requests through analytics, polling, WebSockets, third-party resources, or slow APIs.

How do you fix Playwright network idle timeout?

Identify what keeps the network active and replace global network-idle synchronization with a specific API response, locator assertion, or application state.

Is networkidle recommended for every Playwright test?

No. A specific application condition is generally more deterministic.

What is the difference between waitForResponse() and networkidle?

waitForResponse() waits for a particular network response. networkidle waits for network activity to become idle.

How do you debug navigation timeout in Playwright?

Use request/response logging, Playwright Trace Viewer, debug mode, and CI artifacts to identify the operation causing the delay.


FAQs

What is the Playwright network idle timeout issue?

It occurs when Playwright waits for the network to become idle but the required idle state is not reached before the configured timeout.

Why is Playwright networkidle not working?

The page may have continuous requests from polling, WebSockets, analytics, third-party resources, or background APIs.

How do I fix Playwright navigation timeout?

First identify whether the navigation is genuinely slow or whether networkidle is waiting for requests that never stop. Then use the appropriate load state, API response, or UI assertion.

Should I use networkidle after every page.goto()?

No. It is usually better to wait for the specific UI or API condition required by the test.

Can Playwright handle slow APIs?

Yes. You can increase appropriate timeouts and, more importantly, synchronize with the API or resulting UI state your test depends on.


Leave a Comment

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