cdpfleet Docs GitHub Dashboard

Cases / #33 · 2026-10-10 · Easy

When is a page ready? commit, domcontentloaded, load, networkidle or a selector

Five ways to wait for a page, timed on a static catalogue, a big article and a page that renders its data late — and how many data items were actually there when each wait returned.

Chromium

Run on production on 2026-10-10: ✓ Node.js ✓ Python ✓ Java ✓ C# ✓ Go

The problem

page.goto() waits for load by default, scripts often add networkidle "to be safe", and both feel like "the page is ready". Through a proxy every extra wait costs seconds — and on pages that fetch or render data after load, none of them means the data is there. Which wait gets you the data soonest, and which ones lie?

What we used, and why

WhatWhy
waitUntil: "commit"Returns as soon as the response starts — nothing rendered yet.
waitUntil: "domcontentloaded"The HTML is parsed; images, scripts started later and data loads may still be running.
waitUntil: "load"Every subresource has loaded (the default). One slow image or ad sets the pace.
waitUntil: "networkidle"No requests for 500 ms. Discouraged by Playwright itself — and not a data signal.
locator(data).first().waitFor() after commitWait for the thing you came for.
A fresh context per measurementNo cache between runs, so every strategy waits for the same work.

How it works

  1. Launch one Chromium session.
  2. For each page and each strategy: open a new context, navigate with that wait, time it, and count the data items present right after.
  3. Print every timing with its item count.

The code

The same program in five languages (also on GitHub, with the raw output). Set these environment variables first:

// npm install [email protected]
// env: CDPFLEET_API_KEY, PROXY_URL
import { chromium } from 'playwright';

const KEY = process.env.CDPFLEET_API_KEY;
// A static catalogue, a big article and a page that renders its data with a delayed script.
const PAGES = [
  { url: 'https://books.toscrape.com/', data: 'article.product_pod' },
  { url: 'https://en.wikipedia.org/wiki/Web_scraping', data: '#mw-content-text p' },
  { url: 'https://quotes.toscrape.com/js-delayed/', data: '.quote' },
];
const STRATEGIES = ['commit', 'domcontentloaded', 'load', 'networkidle', 'selector'];

const res = await fetch('https://starter.cdpfleet.com/chromium/session', {
  method: 'POST',
  headers: { 'x-api-key': KEY, 'content-type': 'application/json' },
  body: JSON.stringify({ proxy: process.env.PROXY_URL, headless: 'new' }),
});
if (!res.ok) throw new Error(`launch ${res.status} ${await res.text()}`);
const { wsUrl } = await res.json();
const browser = await chromium.connect(wsUrl, { headers: { 'x-api-key': KEY } });

try {
  const rows = [];
  for (const { url, data } of PAGES) {
    for (const strategy of STRATEGIES) {
      // A fresh context each time: no cache, so every strategy waits for the same work.
      const context = await browser.newContext();
      const page = await context.newPage();
      const t = Date.now();
      if (strategy === 'selector') {
        await page.goto(url, { waitUntil: 'commit', timeout: 60000 });
        await page.locator(data).first().waitFor({ timeout: 60000 });
      } else {
        await page.goto(url, { waitUntil: strategy, timeout: 60000 });
      }
      const ms = Date.now() - t;
      rows.push({ url, strategy, ms, items_ready: await page.locator(data).count() });
      await context.close();
    }
  }
  console.log(JSON.stringify({ rows }, null, 2));
} finally {
  await browser.close();
}

What we got

PageWaitmsData items present
https://books.toscrape.com/commit64754
https://books.toscrape.com/domcontentloaded349120
https://books.toscrape.com/load351320
https://books.toscrape.com/networkidle256320
https://books.toscrape.com/selector314517
https://en.wikipedia.org/wiki/Web_scrapingcommit263435
https://en.wikipedia.org/wiki/Web_scrapingdomcontentloaded873035
https://en.wikipedia.org/wiki/Web_scrapingload620335
https://en.wikipedia.org/wiki/Web_scrapingnetworkidle557335
https://en.wikipedia.org/wiki/Web_scrapingselector511035
https://quotes.toscrape.com/js-delayed/commit11630
https://quotes.toscrape.com/js-delayed/domcontentloaded26910
https://quotes.toscrape.com/js-delayed/load68020
https://quotes.toscrape.com/js-delayed/networkidle118190
https://quotes.toscrape.com/js-delayed/selector1373110

From the Node.js run on 2026-10-10. IP addresses are replaced with placeholders (203.0.113.x); equal addresses stay equal. The other languages produced the same findings.

Raw output (Node.js)
{
  "rows": [
    {
      "url": "https://books.toscrape.com/",
      "strategy": "commit",
      "ms": 6475,
      "items_ready": 4
    },
    {
      "url": "https://books.toscrape.com/",
      "strategy": "domcontentloaded",
      "ms": 3491,
      "items_ready": 20
    },
    {
      "url": "https://books.toscrape.com/",
      "strategy": "load",
      "ms": 3513,
      "items_ready": 20
    },
    {
      "url": "https://books.toscrape.com/",
      "strategy": "networkidle",
      "ms": 2563,
      "items_ready": 20
    },
    {
      "url": "https://books.toscrape.com/",
      "strategy": "selector",
      "ms": 3145,
      "items_ready": 17
    },
    {
      "url": "https://en.wikipedia.org/wiki/Web_scraping",
      "strategy": "commit",
      "ms": 2634,
      "items_ready": 35
    },
    {
      "url": "https://en.wikipedia.org/wiki/Web_scraping",
      "strategy": "domcontentloaded",
      "ms": 8730,
      "items_ready": 35
    },
    {
      "url": "https://en.wikipedia.org/wiki/Web_scraping",
      "strategy": "load",
      "ms": 6203,
      "items_ready": 35
    },
    {
      "url": "https://en.wikipedia.org/wiki/Web_scraping",
      "strategy": "networkidle",
      "ms": 5573,
      "items_ready": 35
    },
    {
      "url": "https://en.wikipedia.org/wiki/Web_scraping",
      "strategy": "selector",
      "ms": 5110,
      "items_ready": 35
    },
    {
      "url": "https://quotes.toscrape.com/js-delayed/",
      "strategy": "commit",
      "ms": 1163,
      "items_ready": 0
    },
    {
      "url": "https://quotes.toscrape.com/js-delayed/",
      "strategy": "domcontentloaded",
      "ms": 2691,
      "items_ready": 0
    },
    {
      "url": "https://quotes.toscrape.com/js-delayed/",
      "strategy": "load",
      "ms": 6802,
      "items_ready": 0
    },
    {
      "url": "https://quotes.toscrape.com/js-delayed/",
      "strategy": "networkidle",
      "ms": 11819,
      "items_ready": 0
    },
    {
      "url": "https://quotes.toscrape.com/js-delayed/",
      "strategy": "selector",
      "ms": 13731,
      "items_ready": 10
    }
  ]
}

Takeaways