How to Convert a Vue Page to a PNG Screenshot with Playwright
Capture a Vue route as a PNG with Playwright. Set a stable viewport, wait for the rendered content, and choose viewport, full-page, or element capture.
To save a Vue page as a PNG with Playwright, open the route in a browser, set its viewport, wait for a reliable signal that the Vue content is rendered, and call page.screenshot(). For example:
import { chromium } from 'playwright';
const browser = await chromium.launch();
try {
const page = await browser.newPage({
viewport: { width: 1280, height: 800 },
});
await page.goto('http://localhost:5173/example-route');
await page.getByRole('heading', { name: 'Example page' }).waitFor();
await page.screenshot({ path: 'vue-page.png', type: 'png' });
} finally {
await browser.close();
}
Replace the local URL and heading with your app’s route and a stable readiness condition. Navigation reaching a browser load milestone does not necessarily mean a client-rendered Vue view or its data is ready. The example shows the workflow; it does not claim that a particular application was run. See the Playwright Page API and its screenshot guide.
1. Install Playwright and prepare the Vue app
Start the Vue development server or serve a production build, then keep it available while the capture script runs. The example uses Vite’s common local address; substitute the actual host, port, and route for your project.
npm install --save-dev playwright
npx playwright install chromium
npm run dev
Save the capture code in an ES module file such as capture.mjs, then run it from another terminal:
node capture.mjs
If your project already uses Playwright Test, Playwright may already be installed. Use the browser installation command appropriate to the browser you intend to launch. This guide uses Chromium; the Playwright API also supports other browser engines.
2. Wait for the Vue view, not just navigation
page.goto() navigates the browser, but a single-page app can still be fetching data, hydrating components, or displaying a loading state. Wait for something that means the intended view is ready: a heading, a data row, a loaded indicator, or an application-owned ready signal.
await page.goto('http://localhost:5173/products/42');
await page.getByRole('heading', { name: 'Product details' }).waitFor();
await page.locator('[data-testid="product-price"]').waitFor();
await page.screenshot({ path: 'product.png', type: 'png' });
Choose a condition that corresponds to the content you need in the image. If the heading appears before asynchronous data, wait for the data-dependent element too. Playwright automatically waits for many actions and assertions; add an explicit wait when it represents a real application readiness requirement rather than waiting arbitrarily. See the Page API.
3. Choose the screenshot area and output
The screenshot method and options determine whether the file shows the visible viewport, the whole document, or one component. PNG is the default screenshot format, but specifying type: 'png' makes the intended format explicit.
| Goal | Code | Use it when |
|---|---|---|
| Visible viewport | await page.screenshot({ path: 'page.png' }) |
You want exactly what fits in the configured browser viewport. |
| Entire scrollable page | await page.screenshot({ path: 'page.png', fullPage: true }) |
You need content below the fold in one tall image. |
| One component | await page.locator('.card').screenshot({ path: 'card.png' }) |
You need a chart, card, or other specific element. |
| PNG bytes in memory | const png = await page.screenshot({ type: 'png' }) |
You will upload or process the image without first saving a file. |
For an element capture, use a selector that identifies a single intended element. For a full-page screenshot, remember that the resulting image can be much taller than the viewport. Playwright documents full-page capture as capturing the full scrollable page as if it were displayed on a very tall screen. More examples are in the Playwright screenshots guide.
4. Set viewport and pixel scale
Set the viewport when creating the page, before navigation, so responsive layout is determined at the intended size. Changing viewport size can change breakpoints and layout; Playwright recommends setting it before navigation when possible.
const page = await browser.newPage({
viewport: { width: 1440, height: 900 },
});
await page.goto('http://localhost:5173/example-route');
Playwright’s screenshot scale option accepts 'css' or 'device'. CSS scale produces one image pixel per CSS pixel; device scale produces device-pixel resolution and is the documented default. Use CSS scale when you want output dimensions to track CSS dimensions; use device scale when you want the browser device scale reflected in output. The Page API documents screenshot options.
To capture transparency where the chosen format supports it, pass omitBackground: true. This does not apply to JPEG, which has no transparency channel. PNG supports transparency.
await page.screenshot({
path: 'transparent.png',
type: 'png',
omitBackground: true,
});
5. Complete runnable script
This script launches Chromium, navigates to a Vue route, waits for a page-specific signal, and writes either a viewport or full-page PNG. Change the URL, readiness locator, and capture option for your application.
import { chromium } from 'playwright';
const url = 'http://localhost:5173/example-route';
const output = 'vue-page.png';
const browser = await chromium.launch();
try {
const page = await browser.newPage({
viewport: { width: 1280, height: 800 },
});
await page.goto(url);
await page.getByRole('heading', { name: 'Example page' }).waitFor();
// Viewport PNG. Add fullPage: true to capture the scrollable document.
await page.screenshot({
path: output,
type: 'png',
fullPage: true,
});
} finally {
await browser.close();
}
To capture one element instead, replace the final call with await page.locator('.report-card').screenshot({ path: output, type: 'png' }). To keep the bytes in memory, omit path and store the returned buffer.
6. Repeatable captures and visual comparisons
For one-off exports, page.screenshot() writes an image. For regression checks, Playwright Test provides expect(page).toHaveScreenshot(), which waits for two consecutive screenshots to match before comparing against a baseline. It is a test assertion, distinct from saving a screenshot with the Page API. See Playwright visual comparisons and PageAssertions.
Visual output can vary with operating system, browser version, settings, hardware, and headless mode. Keep those conditions stable when comparing screenshots, and ensure dynamic page content is controlled or settled before capture. Do not treat a screenshot mismatch as proof that the Vue code changed until you account for rendering environment and data differences.
7. cURL, Python, and Node.js alternatives
Playwright is a Node.js browser automation library, so its direct screenshot workflow is JavaScript. If you need a language-neutral HTTP call for a hosted screenshot service, these examples request a PNG from ScreenshotNeo. Review the ScreenshotNeo API documentation for request options.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://stripe.com \
-o shot.png
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.png", "wb").write(r.content)
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(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(fs => fs.writeFile('shot.png', Buffer.from(await res.arrayBuffer())));
Use your own page URL in place of the example target. Keep API keys out of browser code and public repositories. The JavaScript Playwright script above is the self-hosted browser workflow; these HTTP snippets call ScreenshotNeo’s screenshot API.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server. One GET request returns an image or PDF. For example, this requests a screenshot of a public Vue route:
curl -G "https://api.screenshotneo.com/v1/shot" \
-d access_key=YOUR_API_KEY \
--data-urlencode url=https://example.com/vue-route \
-o vue-page.webp
Before capture, ScreenshotNeo accepts cookie and consent banners like a visitor and removes more than 60 known 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 identify the page verdict and billing status. Its MCP server gives AI agents tools for screenshots, page information, and PDF capture. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. Every feature is on every plan. Read the API docs, then sign up for 1,000 free screenshots a month with no card.
Performance, reliability, and cost
- Browser work: the capture script must launch or reuse a browser, load the route, and wait for the required content. Keep the readiness signal specific so it does not wait longer than the page needs.
- Page size: full-page images can be tall, and device scale can produce more pixels than CSS scale. Choose the smallest capture area and scale that meet your output requirements.
- Reliability: close the browser in a
finallyblock, use a route that is reachable from the script’s environment, and wait for data-specific content. For visual comparisons, keep the rendering environment stable. - Cost: Playwright is an open-source browser automation library, but running captures still uses compute and browser resources in your environment. ScreenshotNeo charges by plan; its published tiers include 1,000 free shots monthly and paid plans from $5 for 3,000, with yearly billing giving two months free. Only clean shots are billed.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Screenshot shows a spinner or empty content | The Vue route navigated, but async data or the target component is still loading. | Wait for the specific heading, data element, or application-ready signal before capturing. |
| Navigation fails or times out | The dev server is stopped, the URL or port is wrong, or the browser process cannot reach that host. | Start the app, verify the route in a browser, and use a host reachable from the script’s environment. |
| PNG has unexpected dimensions or layout | The viewport was set too late or the app uses responsive breakpoints. | Set the viewport when creating the page, before navigation, and choose dimensions matching the desired layout. |
| Only the visible portion appears | The default capture is the current viewport. | Pass fullPage: true for the entire scrollable page, or capture a particular locator. |
| Transparent output is not transparent | The page background was not omitted or the output is JPEG. | Use PNG and omitBackground: true; transparency does not apply to JPEG. |
| Visual snapshots differ between runs | Dynamic content or rendering environment differs. | Wait for intended content, control changing data where possible, and compare in a stable browser and operating system environment. |
| ScreenshotNeo response is not an image | The target may have returned a bot check, blank page, timeout, or failed load, or the request may be invalid. | Inspect the response status and X-Page-Verdict and X-Billed headers, verify the URL and key, and consult the docs. |
FAQ
Does Playwright capture the Vue component itself?
Playwright captures the rendered browser page or a locator’s rendered element. It does not convert a Vue component file directly into an image; the app must be running in a browser.
Can I save the screenshot without writing a file first?
Yes. Call page.screenshot({ type: 'png' }) without a path and use the returned image buffer in your upload or processing code.
Should I use full-page capture for a social preview?
Usually choose a fixed viewport that matches the intended preview dimensions. Full-page capture is useful when the complete scrollable document is the deliverable.
Where can I find the screenshot API options?
The Page API documents screenshot options, and the screenshots guide shows common capture patterns.


