Fix Playwright Screenshots with Text Cut Off at the Right Edge
Diagnose right-edge text clipping in Playwright by checking layout, capture bounds, scale, and scroll containers, then apply the fix that matches the cause.
To fix text cut off at the right edge in a Playwright screenshot, first find out whether the browser laid out or clipped the text that way, or whether the screenshot capture bounds excluded it. Check the viewport and any clip rectangle, inspect the rendered element and page dimensions, and compare the result with a full-page or element screenshot when appropriate. Treat deviceScaleFactor and screenshot scale as separate settings; changing either is not a universal fix.
This guide uses Playwright’s JavaScript API. The same diagnosis applies to its other language bindings: screenshot capture preserves the browser’s rendered layout, so CSS overflow and capture geometry must be investigated separately. See the official Screenshots guide and Page screenshot API for the option semantics.
1. Identify what is being cut off
There are two common categories of right-edge clipping:
- Layout or CSS clipping: the page itself places content outside a container, applies
overflow: hidden, wraps text unexpectedly, or renders at a viewport width that triggers a different responsive layout. A screenshot will capture that rendered result. - Capture geometry: the text is visible in the rendered page, but the viewport-sized screenshot or an explicit
cliprectangle ends before it.
First record the Playwright version, browser engine, operating system, viewport dimensions, deviceScaleFactor, screenshot scale, and whether the page or a nested element owns scrolling. Keeping these details fixed makes comparisons useful and prevents a workaround for one environment from being mistaken for a general fix.
2. Run a minimal diagnostic capture
The following runnable Node.js example prints the viewport, document dimensions, horizontal overflow, and target element bounds, then saves a regular viewport screenshot and a full-page screenshot. It uses the installed Playwright package and its bundled Chromium.
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage({
viewport: { width: 1280, height: 800 },
deviceScaleFactor: 1,
});
await page.goto('https://example.com', { waitUntil: 'networkidle' });
const diagnostics = await page.evaluate(() => {
const target = document.querySelector('main') || document.body;
const rect = target.getBoundingClientRect();
return {
innerWidth: window.innerWidth,
innerHeight: window.innerHeight,
documentWidth: document.documentElement.scrollWidth,
documentHeight: document.documentElement.scrollHeight,
bodyWidth: document.body.scrollWidth,
horizontalOverflow: document.documentElement.scrollWidth > window.innerWidth,
target: {
left: rect.left,
right: rect.right,
width: rect.width,
scrollWidth: target.scrollWidth,
clientWidth: target.clientWidth,
overflowX: getComputedStyle(target).overflowX,
},
};
});
console.log(diagnostics);
await page.screenshot({ path: 'viewport.png' });
await page.screenshot({ path: 'full-page.png', fullPage: true });
await browser.close();
})();
Replace the example URL and target selector with the affected page and element. If navigation never reaches network idle because the site continuously polls or streams, use waitUntil: 'domcontentloaded' and wait explicitly for the content you need before capturing.
3. Check viewport and clip boundaries
The viewport determines the browser’s CSS-pixel layout width. If the page uses a narrow viewport, responsive CSS may wrap or hide text, or a fixed-width element may extend beyond the viewport. Set the viewport to the intended dimensions before navigation when possible, then inspect the page again.
If the screenshot call includes clip, verify all four values. The rectangle is expressed as x, y, width, and height; its right boundary is x + width. A width that ends before the text will crop it even when the page rendered correctly.
await page.screenshot({
path: 'region.png',
clip: { x: 0, y: 0, width: 1280, height: 800 },
});
For an element whose measured right edge is right, ensure the capture region includes that edge and any desired padding. Be mindful that a clip rectangle can also include area outside the viewport depending on the requested geometry and browser behavior; compare against an unclipped capture when debugging.
4. Choose the capture target that matches the problem
| Capture method | Use it when | What it does not fix |
|---|---|---|
| Viewport screenshot | You need exactly the visible browser viewport. | It does not include offscreen page content or correct CSS overflow. |
| Full-page screenshot | Content below the fold is missing and you need the full scrollable page. | It does not repair horizontal overflow or text clipped by page CSS. |
| Element screenshot | You need one component or text region without unrelated page area. | It does not undo clipping imposed by the element or its ancestors. |
Playwright describes a full-page screenshot as capturing the full scrollable page as if it fit on a very tall screen. This is about page height and is not a general remedy for content cut off horizontally. For a specific component, capture its locator:
const card = page.locator('[data-testid="report-card"]');
await card.screenshot({ path: 'report-card.png' });
Element screenshots avoid guessing a large page-wide clip. If the element itself has a constrained width or hidden overflow, inspect its computed styles and ancestors instead of expecting the screenshot method to change them.
5. Inspect layout and horizontal overflow
Use the diagnostic values to distinguish a narrow capture from a wide layout. If documentWidth or the target’s scrollWidth exceeds its visible width, inspect the page for fixed-width content, unbroken strings, wide tables, positioned elements, and containers with overflow-x: hidden or clip.
When the page is supposed to fit a particular viewport, fix the page’s responsive CSS or the test’s viewport setup. When the content is intentionally wider than the viewport, decide whether the required artifact should show the wider element, the horizontally scrolled region, or the viewport as users see it. A screenshot cannot make hidden or offscreen content visible without changing the page state or capture target.
For a nested scrolling layout, identify the element that owns the horizontal or vertical scrollbar. Full-page capture is based on the page’s scrollable area; a custom application pane may have its own scroll dimensions and position. Scroll that container to the desired position before capturing, or screenshot the container element. Do not keep increasing screenshot dimensions if the relevant content belongs to a separate scroll container.
6. Keep device pixel ratio and screenshot scale separate
deviceScaleFactor configures the emulated device pixel ratio in the browser context. The screenshot option scale controls whether output dimensions use CSS pixels or device pixels. Playwright documents deviceScaleFactor as defaulting to 1; screenshot scale is a separate control. Neither setting changes the CSS viewport width in the same way as changing viewport.width.
const context = await browser.newContext({
viewport: { width: 1280, height: 800 },
deviceScaleFactor: 1,
});
const page = await context.newPage();
await page.screenshot({
path: 'css-pixels.png',
scale: 'css',
});
When high-DPI emulation appears related, make a controlled comparison with deviceScaleFactor: 1, keeping viewport, browser version, page state, and screenshot options fixed. An older Chromium issue reported that setting the factor to 1 worked around that issue’s reproduction. That report is environment-specific and does not establish a universal fix. If the screenshot is cropped at the CSS layout level, lowering pixel density will not correct the layout.
7. Compare browser and operating system behavior
If the same page and geometry behave differently across engines or operating systems, reproduce the case with the same Playwright release and viewport in each environment, then record the differences. Historical issue reports describe particular full-page capture failures involving Chromium with a device scale factor above one and WebKit on Linux, including a report tied to a Cairo limitation. These are diagnostic examples tied to specific setups, not proof of a current general defect.
When sharing a reproducible case, include a minimal page or URL, Playwright version, browser name and version, OS, viewport, device scale factor, screenshot options (including clip and scale), page dimensions, and whether scrolling is on the body or a nested element.
8. Troubleshooting
| Symptom | Likely cause | What to check or change |
|---|---|---|
| The rightmost text is absent in both the screenshot and the live page. | Layout overflow, clipping, or responsive CSS. | Inspect target and ancestor widths, computed overflow, long unbroken text, and the viewport. Fix the layout or set the intended viewport. |
| The text is visible in the browser but absent from a clipped screenshot. | The clip rectangle ends too early. | Check x + width against the rendered right edge; temporarily remove clip to compare. |
| The screenshot ends at the viewport edge, while the page extends farther right. | A viewport screenshot is capturing only the visible viewport. | Decide whether the target is the viewport or the wider element. Capture the element or adjust page state and geometry as appropriate. |
| Content below the fold is missing. | A viewport screenshot was used, or the content is in a nested scroll container. | Try fullPage: true for page content; inspect and scroll the owning container for nested content. |
| Only high-DPI runs show a different result. | Device scale factor or an environment-specific browser issue. | Compare with factor 1 while holding other inputs constant; record the exact environment. Do not assume this is a general remedy. |
| A full-page result differs by browser or OS. | Engine/platform-specific behavior or page structure. | Reproduce on another engine and platform, check current Playwright documentation and issue context, and report a minimal case. |
| The page looks incomplete when the screenshot runs. | Capture occurred before the target content rendered. | Wait for a stable target selector or an application-specific ready condition. Avoid relying on a fixed delay when a deterministic condition is available. |
9. Performance, reliability, and cost
A viewport screenshot generally avoids capturing the entire document, while full-page output can be much taller and produce a larger image. Capture only the target you need: a locator screenshot can reduce irrelevant pixels, and avoiding oversized images can reduce storage and transfer work in your pipeline. For repeatable results, pin the Playwright version and browser installation, use a fixed viewport and device scale factor, wait for a known page-ready condition, and preserve the capture options with the artifact.
ScreenshotNeo is a hosted alternative when you do not want to operate browser capture infrastructure. It provides a website screenshot API and MCP server; its capture options include full-page and CSS-selector element capture, viewport and device presets, custom CSS and JavaScript, waits, and output formats. The API bills only clean shots: bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, with verdict and billing information in response headers. See ScreenshotNeo and its API documentation.
Or skip the browser setup
Use one GET request to capture a page. Replace the placeholder API key with a key from your account, and change the target URL as needed. See the ScreenshotNeo API docs for the available capture parameters.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const fs = await import('node:fs/promises');
await fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
- Cookie and consent banners, newsletter popups, and chat widgets are removed before the shot; each cleanup step can be turned off.
- Bot checks, blank pages, timeouts, failed loads, and cache hits are never billed.
- An MCP server lets AI agents, including Claude and Cursor, take screenshots with tools such as
take_screenshot,get_page_info, andcapture_pdf. - 1,000 screenshots a month are free with no card; paid plans start at $5 for 3,000 screenshots. All features are available on every plan.
Sign up free for 1,000 screenshots a month, with no card required.
FAQ
Does fullPage: true fix text cut off on the right?
No. It captures the full scrollable page vertically. It does not fix a narrow viewport, a too-small clip rectangle, or CSS that clips horizontal content.
Should I always set deviceScaleFactor to 1?
No. Use it as a controlled diagnostic if high-DPI emulation correlates with the problem. Preserve the intended device configuration once you know the cause.
Why is the page wide even though my screenshot dimensions look correct?
Screenshot dimensions describe the output region; the rendered document can still contain content wider than the viewport. Compare document and element scroll widths with the viewport and inspect the layout.
What information is useful in a Playwright bug report?
Include a minimal reproduction, Playwright and browser versions, OS, viewport, device scale factor, screenshot options, page dimensions, and scroll-container structure.


