How to Capture a Full-Page Screenshot of a Page with a CSS Animation
Use Playwright to capture an entire page and choose whether CSS animations should stop or continue. Includes runnable JavaScript, Python, cURL, and Node.js options.
Use Playwright’s fullPage: true to capture the whole scrollable page, then choose animations: 'disabled' for a more stable still or animations: 'allow' to leave animation running. Disabling animation does not always show its initial frame: finite animations are fast-forwarded to completion, while infinite animations are canceled to their initial state during the screenshot. With animations allowed, the result depends on capture timing; the API does not promise a particular frame.
1. Choose what the still should show
Full-page capture and animation handling are separate decisions. fullPage controls how much of the document is captured; animations controls how Playwright treats animation effects during capture. See the official Playwright screenshot API and screenshot guide.
| Goal | Setting | What to expect |
|---|---|---|
| Repeatable still with animation effects suppressed | animations: 'disabled' |
Finite animations are fast-forwarded to completion; infinite animations are canceled to their initial state for capture. |
| Show the page with animation left active | animations: 'allow' |
The capture reflects whatever was rendered at that moment. Exact frame timing is not guaranteed. |
Choose disabled when you want a reference image without ongoing motion, keeping in mind that a finite animation may appear at its end state. Choose allow when motion is part of the design you want to represent and an incidental frame is acceptable. If you need a particular moment in an animation, the documented screenshot option does not provide a frame-selection setting; arrange the page state yourself before capture and verify the result for your use case.
2. Capture the full page with Playwright JavaScript
The following is a complete Node.js example using Playwright’s library API. It launches Chromium, opens a page, waits for it to load, and writes a full-page PNG with animations disabled.
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
try {
const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
await page.goto('https://example.com', { waitUntil: 'networkidle', timeout: 30000 });
await page.screenshot({
path: 'page.png',
fullPage: true,
animations: 'disabled',
});
} finally {
await browser.close();
}
})();
Install the package and browser once with:
npm install playwright
npx playwright install chromium
To leave animation active, change the screenshot option to animations: 'allow'. You can also omit the animations option to use the API default, but setting it explicitly makes the intended behavior easier to review.
Wait for the page state you need
Navigation completion is not the same as every visual element being ready. If the target content appears after a client-side render, wait for a meaningful selector before taking the screenshot:
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.locator('main article').waitFor({ state: 'visible', timeout: 15000 });
await page.screenshot({
path: 'page.png',
fullPage: true,
animations: 'disabled',
});
Use a selector that indicates the content you care about. A fixed delay can be useful for a known short animation or delayed render, but it is less reliable than waiting for a specific element.
3. Python option
Playwright’s Python API exposes the same full-page and animation controls. Install it and its browser, then run this asynchronous script:
pip install playwright
playwright install chromium
import asyncio
from playwright.async_api import async_playwright
async def main():
async with async_playwright() as p:
browser = await p.chromium.launch()
try:
page = await browser.new_page(viewport={"width": 1440, "height": 900})
await page.goto("https://example.com", wait_until="networkidle", timeout=30000)
await page.screenshot(
path="page.png",
full_page=True,
animations="disabled",
)
finally:
await browser.close()
asyncio.run(main())
For an active animation, use animations="allow". As in JavaScript, disabling means finite effects are fast-forwarded and infinite effects are canceled to their initial state for the screenshot.
4. cURL and other direct HTTP options
cURL does not render a web page or execute its CSS. It can only request an image from a screenshot service or an endpoint you operate. For example, ScreenshotNeo accepts a URL and returns an image or PDF; the service handles browser capture. A direct screenshot API call is shown below. Consult the ScreenshotNeo API documentation for authentication and supported parameters.
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com \
-o shot.webp
The equivalent request from Python is:
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://example.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
And from Node.js:
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://example.com',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await require('node:fs/promises').writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
These API examples request a screenshot of the URL. They do not expose a documented per-request animation-frame selection setting in this article’s source material. If the exact animation state matters, use a browser workflow where you can control page state, or check the service documentation for current options.
5. Full-page capture details and edge cases
- Full page versus viewport:
fullPage: truecaptures the full scrollable document as though the page were displayed on a very tall screen. Without it, the screenshot is limited to the viewport. - Finite versus infinite effects: disabling animation has different documented effects for each. Finite animations complete; infinite animations return to their initial state for the capture.
- Transitions: transitions are also disabled during capture when animations are disabled. Finite effects can emit
transitionend, so page scripts listening for it may run. - Lazy-loaded content: full-page capture does not by itself guarantee every lazy-loaded image or below-the-fold widget has loaded. Scroll through the page or wait on the specific content before capture when completeness matters.
- Very long pages: a full-page image can become very tall and consume substantial memory. If the consumer can accept multiple images, capture sections or use a PDF workflow instead.
- Fixed and sticky elements: full-page output can include fixed-position elements in ways that differ from a user scrolling through the page. Inspect the output for repeated headers, overlays, or sticky navigation.
- Specific animation frame:
animations: 'allow'does not select a timestamp. If you need a defined state, make the page reach that state before capture and use a stable capture procedure.
6. Manual capture in Firefox
For a one-off capture without writing automation, Firefox Developer Tools provides a full-page screenshot action through its screenshot icon. This is a manual full-page path; the Firefox documentation cited here does not describe how that workflow freezes CSS animations or selects a frame. See Mozilla’s Taking screenshots documentation.
7. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Only the visible area is in the image | The full-page option was omitted or not passed to the screenshot call. | Set fullPage: true in JavaScript or full_page=True in Python. |
| The animation appears at its end | It is a finite animation and animations were disabled; Playwright fast-forwards finite effects to completion. | Use allow if an active frame is acceptable, or set up the desired page state before capture. |
| An infinite animation appears at its starting state | That is the documented disabled-animation behavior for infinite effects. | Use allow if you want a frame from the running effect. The exact frame is timing-dependent. |
| The screenshot varies between runs | The animation or page content is still changing when capture occurs. | Disable animation for a stable still, and wait for a content selector before capturing. |
| Images or sections are missing | Content may load lazily or after navigation has already completed. | Wait for the relevant selector or scroll through the page to trigger lazy loading, then capture. |
| Navigation times out | The page may keep connections open, or the selected load condition may never be met. | Use a more appropriate navigation condition such as domcontentloaded and wait separately for the content needed. Set a timeout appropriate to the site. |
| Browser launch fails | The Playwright browser binary may not be installed for the package version. | Run npx playwright install chromium or playwright install chromium in the relevant environment. |
| Output is unexpectedly huge or capture fails on a long page | A tall full-page image can exceed practical memory or downstream image limits. | Capture sections or use a document format suited to long pages; reduce unnecessary page content before capture. |
8. Performance, reliability, and cost
Browser automation has setup and runtime costs: the browser must be installed and launched, navigation and page scripts consume time, and full-page images grow with document height and viewport width. Reuse a browser process when taking many screenshots, close pages when finished, set navigation and selector timeouts, and capture only the dimensions you need. Network-idle waits can be slow or unsuitable on pages with persistent requests; waiting for a specific element can be more targeted.
For repeatable results, make viewport, browser version, page readiness condition, and animation policy explicit. A capture with allow may differ across runs because it records a moment in time. A capture with disabled removes motion during the operation, but finite and infinite effects resolve differently as described above. Compare outputs when updating the browser or page implementation.
With a screenshot API, local browser installation is not needed for the request, but pricing and behavior depend on the service. ScreenshotNeo’s stated plans are Free: 1,000 shots per month with no card; Starter: $5 for 3,000; Growth: $15 for 15,000; Pro: $39 for 60,000; Scale: $99 for 250,000; and Business: $249 for 1,000,000. Yearly billing gives two months free, and every feature is on every plan. ScreenshotNeo says only clean shots are billed: bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing; responses identify the page verdict and billing status in headers. See ScreenshotNeo for the service overview.
9. Or skip the browser setup
ScreenshotNeo takes a screenshot with one GET request. The example returns a WebP image; see the ScreenshotNeo docs for API details.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com -o shot.webp
It accepts cookie and consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.
Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month without a card.
10. FAQ
Does a full-page screenshot include content below the fold?
Yes, with Playwright’s fullPage: true, the capture covers the full scrollable page. Lazy-loaded content may still need to be triggered or awaited.
Does disabling animations always show the first frame?
No. Finite animations are fast-forwarded to completion, while infinite animations are canceled to their initial state for the screenshot.
Can I tell Playwright to capture at a specific animation timestamp?
The cited screenshot API documentation does not establish a frame or timestamp selection option. Prepare the page state before capture if a particular moment is required.
Can I take the screenshot without code?
Firefox Developer Tools documents a manual full-page screenshot action. Its cited instructions do not specify how CSS animation is handled.


