ScreenshotNeo

BlogEngineering

Puppeteer CSS Coverage Constructor Explained

The CSS coverage constructor is an internal Puppeteer detail. Use the supported page-level API to collect stylesheet coverage and understand its limits.

By the ScreenshotNeo team4 October 20266 min read

Short answer: ordinary application code should not call Puppeteer’s CSS coverage constructor. Use page.coverage.startCSSCoverage(), perform the navigation or interactions you want to measure, then call page.coverage.stopCSSCoverage() to get stylesheet coverage entries. Puppeteer explicitly says third-party code should not call the Coverage constructor or subclass that class. See the Coverage class documentation.

This guide targets the Puppeteer API documented in the current references linked below. Coverage APIs and defaults can change between releases, so check the reference for the version installed in your project.

1. What the CSS coverage constructor represents

Coverage is a page-level facility for collecting information about which portions of a page’s JavaScript and CSS were used during a measurement window. The CSSCoverage implementation has a constructor that accepts a CDPSession and an optional logger, but that signature is an implementation reference, not the recommended integration point for application code. The documented public route is through page.coverage.

Constructing the internal class yourself means taking responsibility for lower-level browser protocol setup and implementation details that Puppeteer’s page-level API handles. Unless you are working on Puppeteer itself or have a specialized integration requiring internal APIs, use the page methods.

2. Collect CSS coverage with Puppeteer

Install Puppeteer in a Node.js project:

npm install puppeteer

Save this as css-coverage.mjs and run it with node css-coverage.mjs. The script starts coverage before navigation, visits a page, stops coverage, prints each stylesheet’s used ranges and source text, and closes the browser even if an operation fails.

import puppeteer from 'puppeteer';

const browser = await puppeteer.launch();
try {
  const page = await browser.newPage();

  await page.coverage.startCSSCoverage();
  await page.goto('https://example.com', { waitUntil: 'networkidle2' });

  // Exercise page states whose CSS you want to include in the measurement.
  const cssEntries = await page.coverage.stopCSSCoverage();

  for (const entry of cssEntries) {
    console.log({
      url: entry.url,
      ranges: entry.ranges,
      textLength: entry.text.length,
    });
  }
} finally {
  await browser.close();
}

The supported methods are documented in the startCSSCoverage reference and the stopCSSCoverage reference. Stopping returns an array of stylesheet coverage reports. Each report includes source text and ranges describing used portions.

Measure more than the initial render

Coverage only describes activity observed while collection is running. To include styles used by menus, dialogs, tabs, or other interactive states, trigger those states before stopping coverage:

await page.coverage.startCSSCoverage();
await page.goto('https://example.com', { waitUntil: 'networkidle2' });
await page.click('[aria-label="Open menu"]');
await page.click('[data-tab="details"]');
const cssEntries = await page.coverage.stopCSSCoverage();

Replace the selectors with controls that exist on the target page. If an interaction depends on an element becoming visible, wait for it explicitly before clicking.

3. Options, navigation, and measurement boundaries

startCSSCoverage(options?) accepts optional CSS coverage options. The current API reference documents resetOnNavigation as defaulting to true. Choose options according to the measurement window you need, and consult the versioned API reference for the precise behavior of other options rather than relying on internal class signatures.

Situation What to consider
One page load Start coverage before navigation and stop after the page reaches the state you intend to measure.
Several navigations Account for the documented resetOnNavigation: true default. Set options deliberately and verify the resulting measurement window against the API version in use.
Interactive UI Run the relevant clicks and state changes before stopping coverage.
Injected styles Know the documented exclusion described below; coverage is not a complete inventory of every style a page may create.

Puppeteer documents this limitation: “CSS Coverage doesn’t include dynamically injected style tags without sourceURLs.” A style tag injected at runtime without a source URL may therefore be absent from the returned data. See the CSSCoverage API reference.

4. Reading the returned entries

The result is an array of stylesheet entries. The entry’s url identifies its stylesheet, text contains the stylesheet text, and ranges describes the portions recorded as used. Do not interpret a single run as a universal score for stylesheet quality: it reflects only the routes, page states, navigation behavior, and runtime styles observed in that run.

Puppeteer’s Coverage documentation demonstrates calculating a used-CSS percentage from the range lengths and entry text lengths. Such a percentage is useful as a measurement for a defined test journey, but it is not a standardized quality score, and it inherits coverage’s collection limits.

For output consumable by Istanbul, Puppeteer points to puppeteer-to-istanbul.

5. Common problems and fixes

Symptom Likely cause Fix
The constructor is unavailable or its signature does not match examples. The internal implementation API is being treated as a public integration point, or the installed Puppeteer version differs. Use page.coverage.startCSSCoverage() and page.coverage.stopCSSCoverage(). Check the documentation matching the installed release.
The returned array is empty or has fewer entries than expected. Coverage was started after the relevant work, stopped too early, or the page did not load the expected stylesheets. Start before navigation, wait for the page and required states, then stop. Inspect the returned URLs and page network behavior.
Styles used after a click are missing. The interaction happened outside the coverage window. Perform the click or state transition between start and stop.
A dynamically added style tag is missing. Puppeteer documents that dynamic style tags without sourceURLs are excluded. Where you control the injected style, provide a source URL if appropriate, or account for this limitation in your analysis.
Coverage appears to lose data across navigation. The documented default is resetOnNavigation: true. Review the option for your installed version and make the measurement window explicit.
The process hangs or leaks browser processes after an error. The browser close operation was skipped when navigation or collection failed. Put browser.close() in a finally block as in the runnable example.

6. Runtime, reliability, and cost considerations

Coverage requires launching or connecting to a browser and keeping it available for the measurement. The collection window should be long enough to include the routes and interactions of interest, while avoiding unrelated journeys that make results harder to interpret. For repeatable comparisons, keep the tested route, interaction sequence, viewport, and navigation setup consistent.

The cited Puppeteer references do not provide a universal runtime overhead, accuracy guarantee, or cost figure for CSS coverage. Browser hosting and execution cost depend on where and how your automation runs. Treat coverage as instrumentation for a defined scenario, and repeat runs when page behavior or network-dependent content can vary.

7. Or skip the browser setup

If your goal is to capture a clean page image or PDF rather than inspect CSS usage, ScreenshotNeo provides a website screenshot API and MCP server. One GET request can return PNG, JPEG, WebP, or PDF. Its capture flow accepts cookie or consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before the shot; each step can be turned off. Bot checks, blank pages, and failed loads are never billed, and response headers identify the page verdict and billing status. Its MCP server lets AI agents use screenshot, page-info, and PDF tools. One thousand screenshots a month are free with no card; paid plans start at $5 for 3,000. See the ScreenshotNeo API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp

Sign up for 1,000 free screenshots a month with no card.

8. Frequently asked questions

Should I call the Puppeteer CSSCoverage constructor directly?

No for ordinary third-party application code. Puppeteer marks the Coverage constructor as internal and directs callers to the page-level coverage API.

Does stopping CSS coverage return a percentage?

No. It returns stylesheet coverage entries. You can calculate a percentage from used ranges and text lengths for a defined run, but that number inherits the run’s measurement boundaries.

Can CSS coverage include every runtime-injected style?

No. Puppeteer documents that dynamically injected style tags without sourceURLs are not included.

Can I export the result for Istanbul?

Puppeteer points to puppeteer-to-istanbul as a route to Istanbul-consumable output.