October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run ScanOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
Firefox Developer Tools

How to Take a Screenshot of a Single-Page App (SPA)

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To screenshot a single-page app (SPA), first navigate to the exact client-side route and reproduce the UI state you need. For a one-off image, Firefox Developer Tools can capture the whole scrollable page or one DOM element. For repeatable captures, use Playwright (or an existing Puppeteer setup), wait for the app’s data and images to settle, then choose a viewport, full-page, or element screenshot.

Choose the capture scope before you start

An SPA can change its content without a full navigation. The URL, authentication state, filters, expanded panels, modal dialogs and scroll position all affect the pixels you get. Decide which of these scopes matches your goal:

  • Viewport: only the currently visible browser area. Use this for a realistic user view or a fixed-size visual regression image.
  • Full page: the complete scrollable document, including content below the fold. It records the rendered state of the page, not every possible state of the application.
  • Element: one component such as a chart, card, table or navigation panel, selected with a stable CSS selector or element handle.

Before capturing, check that the intended route is in the address bar (including hash or history-based routing), data has loaded, lazy images are visible, and no consent banner, chat bubble or temporary loading overlay is covering the result.

One-off screenshots in Firefox Developer Tools

Firefox includes built-in capture commands, so no script is needed for a single image.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Open the SPA and navigate to the required client-side route.
  2. Set the exact state to show: sign in only when appropriate, choose filters, open or close panels, select a tab, and position the page as required.
  3. Wait until text, charts, images and asynchronous data have settled.
  4. Open Developer Tools, select the settings menu, and under Available Toolbox Buttons enable Take a screenshot of the entire page.
  5. Use the screenshot icon for a full-page image. Firefox saves it to your Downloads folder.
  6. For a component, open the Inspector, right-click the desired node and choose Screenshot Node.

Inspect the saved file. Sticky headers may appear repeatedly or overlap content, virtualized lists may contain only the rows the app rendered, and a canvas, map or chart must be checked visually rather than inferred from its DOM text.

Automate reliable captures with Playwright

Playwright is a practical default when screenshots must be generated repeatedly. It can launch Chromium, Firefox or WebKit and supports viewport, full-page and element captures, with PNG, JPEG or WebP output and CSS-pixel or device-pixel scaling.

Install and run a basic script

npm install playwright

Save this as capture-spa.js and replace the route and selector with values from your app:

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch();
  const page = await browser.newPage({
    viewport: { width: 1440, height: 900 },
    deviceScaleFactor: 1
  });

  await page.goto('https://example.com/app#/dashboard', {
    waitUntil: 'networkidle'
  });

  // Reproduce the state required by the screenshot.
  // await page.getByRole('button', { name: 'Open filters' }).click();
  // await page.getByLabel('Status').selectOption('active');

  await page.screenshot({ path: 'spa-viewport.png' });
  await page.screenshot({ path: 'spa-full-page.png', fullPage: true });
  await page.locator('[data-testid="chart"]').screenshot({ path: 'chart.png' });

  await browser.close();
})();

waitUntil: 'networkidle' is useful, but it is not a guarantee that your framework has finished rendering. For a known component, add an application-specific wait:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
await page.locator('[data-testid="dashboard-ready"]').waitFor();
await page.locator('[data-testid="chart"]').waitFor({ state: 'visible' });

Use stable targets

Prefer a dedicated data-testid, an accessible role and name, or another selector that is not generated from CSS module hashes. A full-page capture cannot be combined with an element target: choose either fullPage: true or a locator screenshot. Element screenshots crop to the element’s rendered bounds, so include padding in the component if the exported image needs it.

Control output and resolution

Playwright accepts path, type (png, jpeg or webp), and quality for lossy formats. A larger deviceScaleFactor produces more device pixels while keeping the same CSS viewport; use a fixed viewport and scale when comparing images over time. JPEG is smaller but loses sharp text and transparency; PNG preserves both, while WebP is often a compact choice when your pipeline accepts it.

Playwright CLI for quick repeatable jobs

If you prefer commands to a JavaScript file, the Playwright CLI can capture a viewport, a selected element, or the full page. Set a filename and choose PNG, JPEG or WebP; use its high-resolution device-pixel option when you need a denser image. The exact command syntax depends on the Playwright version installed, so run npx playwright screenshot --help on the same machine to see the available flags, then supply the route, output path and (for an element) a selector.

Rank #2
Sale
HTML and CSS: Design and Build Websites
  • HTML CSS Design and Build Web Sites
  • Comes with secure packaging
  • It can be a gift option

When Puppeteer is the better fit

Puppeteer automates Chrome and Firefox and supports full-page and element screenshots. Choose it when your tests, fixtures, authentication helpers or deployment already use Puppeteer; migrating solely for a screenshot is unnecessary. If you are starting a new cross-browser capture utility, Playwright’s single API for Chromium, Firefox and WebKit is a straightforward choice. This is a workflow preference, not a performance benchmark.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Authentication, data and SPA state

Capture the right session

Replicate the intended authenticated or anonymous state deliberately. In automation, use a test account or a stored browser context rather than embedding a real user’s password in source control. Verify that the route did not redirect to a login page and that API calls returned the expected tenant, locale and permissions.

Make dynamic state deterministic

  • Set a fixed viewport, timezone and locale when layout or dates change with environment settings.
  • Wait for a readiness signal from the app instead of relying only on a timer.
  • Expand or collapse panels intentionally; full-page capture records only what is rendered.
  • For charts, canvases, maps and virtualized lists, inspect the pixels. DOM text alone cannot prove that the visual is complete.
  • Hide animations or wait for them to finish before taking comparison images.

Review privacy before sharing

Check the final PNG, JPEG or WebP for access tokens, personal information, internal URLs, customer records and confidential metrics. A screenshot can expose data even when the route itself looks harmless. Remove or mask sensitive values in the application state before capture rather than attempting to blur an accidentally published image.

Full-page versus element screenshots

Need Use Important limitation
What a user sees at one size Viewport screenshot Below-the-fold content is omitted.
Documentation or an entire dashboard Full-page screenshot Only the currently rendered state is included; virtualized content may be incomplete.
A chart, card or component Element screenshot Requires a reliable selector and captures the element’s current bounds.

Troubleshooting common failures

The image shows a blank shell

Cause: the SPA JavaScript or API data had not completed, or the script captured a redirect. Fix: confirm the final URL, wait for a ready selector, check browser-console and network errors, and ensure the capture environment can reach the API.

Lazy images or rows are missing

Cause: content loads only after scrolling or intersection events. Fix: scroll through the page before capture, wait for image elements to finish, or configure the app’s test mode to render all rows. A full-page flag does not automatically fix application-level virtualization.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The element selector fails

Cause: the selector is generated, duplicated, or queried before the component mounts. Fix: add a stable data-testid, wait for visibility, and scope the locator to the correct frame if the component is inside an iframe.

Fonts, charts or animations differ between runs

Cause: fonts are still loading, animations are mid-transition, or the browser engine and device scale differ. Fix: wait for fonts and a chart-ready signal, disable motion in a capture stylesheet, pin the browser engine, viewport and device scale, and compare like-for-like outputs.

Sticky headers or overlays obscure content

Cause: the page was captured with a fixed header, cookie notice, modal or chat widget still visible. Fix: set the desired UI state first, close or hide overlays deliberately, and inspect both the top and lower portions of the resulting image.

Performance, reliability and cost choices

A one-off Firefox capture has almost no setup cost. A scripted job adds browser startup time but pays off when you need many routes, consistent dimensions or scheduled visual regression images. Reuse a browser process for batches, create a fresh context per tenant or permission set, and write unique filenames so parallel jobs do not overwrite one another. Capture only the scope and format you need: full-page PNGs consume more storage than an element WebP, while JPEG can reduce size when transparency and lossless text are not required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For repeatability, record the route, viewport, browser engine, device scale, application build and authentication fixture alongside each image. Retry transient navigation failures, but do not hide persistent blank pages or authorization errors with retries; surface them as failed jobs.

Rank #4
Sale
Web Design with HTML, CSS, JavaScript and jQuery Set
  • Brand: Wiley
  • Set of 2 Volumes
  • A handy two-book set that uniquely combines related technologies Highly visual format and accessible language makes these books highly effective learning tools Perfect for beginning web designers and front-end developers
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

ScreenshotNeo provides a single-request screenshot API and an MCP server for AI agents. It accepts a URL and can return PNG, JPEG, WebP or PDF. Before capture it accepts cookie or consent banners like a visitor and removes more than 60 known consent platforms, newsletter popups and chat widgets; each step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and whether the request was billed.

For a route that does not require a private browser session, call the API as documented at ScreenshotNeo’s documentation:

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

The same request in Python:

import requests
r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

And Node.js:

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(`HTTP ${res.status}`);
const fs = require('node:fs');
fs.writeFileSync('shot.webp', Buffer.from(await res.arrayBuffer()));

ScreenshotNeo also supports full-page capture with lazy images loaded, CSS-selector element capture, dark mode, device presets or custom viewports, retina scale, custom CSS and JavaScript, clicks, waits, ad and tracker blocking, headers, cookies, user agents, authorization, timezone and geolocation, transparent backgrounds, resizing, chosen cache TTLs, signed links, asynchronous webhooks, batches of up to 100 URLs, usage reporting and an OpenAPI specification. Its MCP tools—take_screenshot, get_page_info and capture_pdf—let Claude, Cursor or another MCP client request captures without you wiring a browser.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The Free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots; yearly billing provides two months free, and every feature is included on every plan. Create a free ScreenshotNeo account to try it.

FAQ

Can I capture a hash route such as #/dashboard?

Yes. Navigate to the complete URL and wait for the route’s application state and data to render before taking the image.

Why does a full-page screenshot not include every row in my list?

Virtualized lists often render only nearby rows. Configure the app to render all rows or scroll and capture deliberately; the screenshot tool cannot infer rows that the SPA never placed in the document.

Should I use PNG or JPEG?

Use PNG for crisp text or transparency, JPEG for smaller photographic images, and WebP when your delivery pipeline supports it and you want a compact general-purpose file.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Can I capture a hash route such as #/dashboard?

Yes. Navigate to the complete URL and wait for the route’s application state and data to render before taking the image.

Why does a full-page screenshot not include every row in my list?

Virtualized lists often render only nearby rows. Configure the app to render all rows or scroll and capture deliberately; the screenshot tool cannot infer rows that the SPA never placed in the document.

Should I use PNG or JPEG?

Use PNG for crisp text or transparency, JPEG for smaller photographic images, and WebP when your delivery pipeline supports it and you want a compact general-purpose file.

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.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Read next

Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.