Why Is the Sidebar Missing from a Playwright Screenshot?
A missing sidebar is often caused by responsive CSS, print media emulation, or a clipped capture. Diagnose the page state before changing screenshot options.
A sidebar missing from a Playwright screenshot is often the result of the page’s responsive CSS at the screenshot viewport width. Print media emulation, a clipped capture region, or application state can also explain it. The exact cause depends on the page: check the viewport and media type, then inspect whether the sidebar exists in the DOM and what its computed styles and position are. Setting fullPage: true captures the full scrollable page; it does not make CSS-hidden content visible.
1. Check the viewport and media type
Start by reproducing the capture at the same viewport dimensions. Playwright’s documented test configuration default is 1280×720, but project configuration or context options may set a different size. A responsive layout can hide or move the sidebar at narrower widths.
Also check whether the page is using print media. If you want the ordinary screen layout, remove an unintended print override or explicitly emulate screen media.
import { chromium } from 'playwright';
const browser = await chromium.launch();
const context = await browser.newContext({ viewport: { width: 1280, height: 720 } });
const page = await context.newPage();
// Set viewport through the context before navigation.
await page.emulateMedia({ media: 'screen' });
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
console.log(await page.evaluate(() => ({
viewport: { width: innerWidth, height: innerHeight },
screenMedia: matchMedia('screen').matches,
printMedia: matchMedia('print').matches,
})));
await page.screenshot({ path: 'page.png' });
await browser.close();
Replace https://example.com with the page under investigation. You can instead set the viewport in Playwright test configuration, a browser context, or with page.setViewportSize(). For a reproducible diagnosis, choose the intended dimensions before navigation and keep them fixed across runs.
2. Find out whether the sidebar exists and can be seen
Use the application’s actual sidebar selector. The diagnostic below reports whether it exists, its bounding box, and computed visibility-related styles. A missing DOM node points toward app state, navigation, authentication, or rendering lifecycle. A present node with zero size, hidden styles, or an off-screen position points toward layout or CSS.
const sidebarSelector = 'aside'; // Replace with the page's real selector.
const sidebarState = await page.evaluate((selector) => {
const el = document.querySelector(selector);
if (!el) return { exists: false };
const style = getComputedStyle(el);
const rect = el.getBoundingClientRect();
return {
exists: true,
rect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },
display: style.display,
visibility: style.visibility,
opacity: style.opacity,
position: style.position,
inViewport: rect.bottom > 0 && rect.right > 0 && rect.top < innerHeight && rect.left < innerWidth,
};
}, sidebarSelector);
console.log(sidebarState);
visibility: visible alone does not guarantee the sidebar appears in the image: it may have zero dimensions, be outside the viewport, be covered by another element, or be cut off by a capture clip. Inspect the rectangle and, if needed, compare a screenshot of the same page without clip.
3. Separate page layout from screenshot scope
Playwright’s page.screenshot() defaults to the visible viewport (fullPage: false). Set fullPage: true only when you want the entire scrollable page. It does not override breakpoints, reveal hidden elements, or change screen media into print media. A clip rectangle deliberately limits the captured area and can exclude a sidebar.
| Option or condition | What it affects | What to check |
|---|---|---|
viewport |
Available layout width and height, which can activate responsive rules | Use the dimensions at which the sidebar should appear |
emulateMedia() |
CSS media features such as screen or print | Use screen for a normal screen capture unless the test specifically targets print |
fullPage: true |
Capture height: full scrollable page rather than visible viewport | It does not reveal CSS-hidden content |
clip |
The rectangle included in the capture | Remove it temporarily or expand it to include the sidebar |
4. Reproduce the capture in a controlled order
- Set the intended viewport before navigating, using the context or test configuration.
- Navigate to the page and establish the same app state as the failing run, including any required authentication or interactions.
- Set or clear media emulation; use screen media for the ordinary screen layout.
- Check the sidebar selector’s DOM presence, computed styles, and bounding rectangle.
- Take an unclipped viewport screenshot. Add
fullPage: trueonly if the required output includes the full scrollable height. - Compare runs while changing one axis at a time: viewport, browser project or engine, media type, page state, and capture scope.
Playwright projects can run different browser configurations. Keep the page state and capture options constant when comparing projects so a browser change is not confounded with a viewport or media change.
5. Common causes and fixes
| Symptom | Likely cause | Fix or next check |
|---|---|---|
| Sidebar is missing only at a narrow width | Responsive CSS hides it, collapses it, or replaces it with a menu | Capture at the intended desktop width, or test the mobile menu state if that is the expected behavior |
| Layout differs from the normal browser view | Print media is active, or another media override is in effect | Inspect matchMedia(); use page.emulateMedia({ media: 'screen' }) for screen output |
| Sidebar is in the DOM but absent from the image | It is hidden, zero-sized, off-screen, covered, or outside a clip | Inspect its computed styles and rectangle; remove clip for a diagnostic capture |
| Sidebar is absent from the DOM | Application state, navigation, authentication, or rendering lifecycle differs | Reproduce the required app state and wait for the relevant app condition before capture |
| Sidebar appears in a full-page image but not a viewport image | It may be below or outside the initial viewport, or the page layout may change with scroll position | Inspect its coordinates and the page’s scroll-dependent behavior; choose the intended capture scope |
| Two runs disagree | Viewport, browser project, media type, page state, or clip changed between runs | Record and compare those settings, changing one at a time |
6. Performance, reliability, and cost
For repeatable debugging, set viewport and media explicitly and avoid changing several capture variables at once. Use the narrowest wait that reflects the page condition you need; a screenshot taken before the application renders the sidebar can look like a CSS issue. When comparing runs, preserve the same navigation and application state.
The research sources establish Playwright API behavior and configuration defaults, but do not provide benchmark timings or the root cause for any particular site. The sidebar’s actual cause must be determined from its runtime DOM, styles, geometry, and the capture settings. Playwright’s screenshot options do not establish a per-capture price; any operational cost depends on where and how the browser runs.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. One GET request returns an image or PDF, and its capture flow accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each of those steps can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, with the page verdict and billing status reported in response headers. Its MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs.
For this one-call example, see the ScreenshotNeo API documentation:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Free includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Sign up free and get 1,000 screenshots a month with no card.
FAQ
Does fullPage: true make a hidden sidebar visible?
No. It changes the screenshot from the viewport to the full scrollable page. CSS and application state still determine whether the sidebar is rendered visibly.
Should I change the viewport before or after navigation?
For a reproducible layout, set it in the browser context or test configuration before navigation, then confirm the dimensions in the page.
What if the sidebar is present but outside the viewport?
Use its bounding rectangle to establish its position. Then determine whether the page is meant to show it at that viewport, whether scrolling or an interaction is required, and whether a clip excludes it.
Can this diagnosis identify the cause without the page or selector?
No. These checks narrow the possibilities, but the specific root cause requires the page’s actual runtime state and capture configuration.


