In Playwright, wait for the page’s document.fonts.ready promise before taking the screenshot, then set fullPage: true. This lets fonts currently needed by the document finish loading and gives the browser’s related layout work time to settle; it does not guarantee that every font declared in CSS has loaded.
Wait for fonts, then capture the page
For a page whose relevant content is already rendered, the essential Playwright sequence is:
| # | Preview | Product | Price | |
|---|---|---|---|---|
| 1 |
|
The 138 Best Chrome Extensions | $2.99 | Buy on Amazon |
As an Amazon Associate I earn from qualifying purchases.
await page.evaluate(() => document.fonts.ready);
await page.screenshot({ path: 'page.png', fullPage: true });
document.fonts is the document’s FontFaceSet. Its ready promise fulfills after loading and layout operations for fonts used by the document are complete. MDN Web Docs describes it this way: “The promise will only resolve once the document has completed loading fonts, layout operations are completed, and no further font loads are needed.” MDN: FontFaceSet: ready property.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Playwright’s fullPage: true option captures the full scrollable page, rather than only the current viewport. Playwright: Screenshots.
#1 Best Overall
Use this sequence for dynamic pages
Font readiness only covers fonts relevant to the document at the time it is checked. If a single-page app has not inserted its content yet, or scrolling triggers lazy content that uses additional fonts, a font wait alone cannot make that content appear. Wait for the page-specific condition first; render or scroll through relevant lazy content if necessary; then wait for fonts again before capturing.
const url = 'https://example.com';
await page.goto(url);
// Replace this with a condition that proves your app's capture content is ready.
await page.locator('[data-capture-ready="true"]').waitFor();
// If needed, trigger scrolling or other page-specific rendering here.
// For example, scroll through the page before the final font wait.
await page.evaluate(() => document.fonts.ready);
await page.screenshot({ path: 'page.png', fullPage: true });
The selector is an example, not a universal readiness signal. Choose a condition tied to the actual content you need in the image. If scrolling or interaction causes more text or font faces to appear, perform those actions before the final document.fonts.ready wait.
What the font wait does—and does not—promise
The promise concerns fonts currently used by the document, together with the associated loading and layout work. A face declared in CSS may not be used, and optional faces that did not load in time may remain unloaded. Therefore, do not interpret a fulfilled promise as proof that every declared font downloaded or that a specific intended face was applied.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsIf text still looks wrong, inspect the loaded faces and font-loading errors using the CSS Font Loading API. It exposes font-face status and loading error events. Also verify that the page’s CSS actually selects the face you expect.
Direct Chrome DevTools Protocol
If your automation sends Chrome DevTools Protocol (CDP) commands directly, evaluate document.fonts.ready in the target page’s execution context, await its result, and only then send Page.captureScreenshot. CDP documents captureBeyondViewport for capturing beyond the viewport; its current protocol reference marks the option experimental and gives it a default of false. Check its availability and behavior against the Chromium version you run. Chrome DevTools Protocol: Page.captureScreenshot.
Playwright offers a higher-level screenshot option, fullPage: true. With CDP, you issue the protocol command yourself and must account for the beyond-viewport option. Whichever route you use, the order is the same: wait in the page context, then capture.
Stability, timeouts, and animations
- Prefer readiness over a guessed sleep.
document.fonts.readyfollows the document’s font and layout state; a fixed delay merely waits for a duration and can still be too short or needlessly long. - Set a timeout policy for production. A stalled page should not hold a job indefinitely, but there is no universal correct timeout established for screenshot capture. Choose one for your workload and treat timeout handling as your automation policy, not a browser guarantee.
- Handle animation separately. Waiting for fonts does not freeze transitions or animations. Playwright documents screenshot animation options; configure them separately when visual consistency requires it. Playwright: page.screenshot options.
- Recheck after page changes. If your own capture preparation causes new text or styles to render, wait for fonts after that work, immediately before capture.
Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| The screenshot uses a fallback font. | The intended face may not have loaded, may not be used by the rendered content, or may not be selected by the page’s CSS. | Inspect font-face statuses and loading errors; check the element’s computed styles and the page’s font rules. Do not assume ready means every declared face loaded. |
| Some text or sections are missing from the full-page image. | The application had not rendered them, or scrolling had not triggered lazy content, when the capture began. | Wait for an application-specific readiness condition and trigger relevant lazy rendering before the final font wait and screenshot. |
| The screenshot still changes between runs. | Animations or other changing page content may still be active even though fonts are ready. | Control animations with the screenshot library’s options and wait for any page-specific content that must be stable. |
| A CDP capture stops at the viewport. | captureBeyondViewport is false by default, or the Chromium version may not support the expected behavior. |
Check the protocol reference and your Chromium version; set the beyond-viewport option as appropriate and verify the result. |
| The font wait takes too long. | A page may be stalled or still initiating relevant font loads. | Apply a project-specific timeout and record or handle the failure. Do not treat an arbitrary timeout duration as a universal browser recommendation. |
Or skip the browser setup
ScreenshotNeo can return a screenshot from one GET request, without you setting up the browser automation yourself. Its clean-shot steps can accept cookie or consent banners and remove supported consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks and CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers report the page verdict and billing status. It also has an MCP server with screenshot tools for AI agents.
Free tools Windows power users keep installed
One-click scans. No signup required.
Here is a cURL example, with the target URL adapted to the page you want to capture:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
See the ScreenshotNeo API documentation for request options. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month—no card required.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




