How to Generate Website Preview Images with Playwright for an Indian SaaS App
Build website preview images with Playwright using a fixed viewport, reliable page readiness, suitable output settings, and deployable browser dependencies.
To generate a website preview image with Playwright, open the page in a browser, set an explicit viewport and device scale, wait for the app’s content to be ready, then save a screenshot with page.screenshot(). For a compact link preview, capture the viewport; use fullPage: true only when the preview should include the entire scrollable page.
The same method applies to an Indian SaaS app. The title alone does not establish a required India-specific browser setting, hosting region, or compliance rule. Choose region and data handling based on your app’s actual requirements.
1. Choose the preview’s dimensions and capture area
Decide what the image is for before capturing it. A viewport screenshot produces a compact image of the visible page, useful for a thumbnail or preview card. A full-page screenshot captures the scrollable page and may produce a very tall file. You can also capture one element, such as a product card or dashboard panel.
| Setting | Use it when | Trade-off |
|---|---|---|
| Viewport screenshot | The preview needs fixed, compact dimensions. | Content outside the viewport is omitted. |
| Full page | The image should show the entire scrollable document. | The output can be tall and larger than a preview card needs. |
| Element screenshot | You need one component from a page. | The selector must resolve to the intended element. |
| CSS pixel scale | You want output dimensions close to the configured viewport. | May look less sharp on high-density displays. |
| Device pixel scale | You want more pixels for a sharper image. | Higher pixel count can increase file size and processing cost. |
For a link-card style preview, choose a viewport that matches the dimensions expected by the consuming interface. There is no universal dimension established for every preview consumer.
2. Install Playwright and its browser
Playwright’s browser binaries are tied to the installed Playwright version. Install the browser for the version your app uses, and repeat browser installation when upgrading Playwright as required by its documentation. On Linux or in a container, account for the browser’s system dependencies as part of deployment.
npm init -y
npm install playwright
npx playwright install chromium
The browser installation command above installs Chromium. If you select a different supported browser, install that browser instead. Check the official [Playwright browser installation documentation](https://playwright.dev/docs/browsers) for the version and operating system you deploy.
3. Capture a preview with Node.js
This runnable CommonJS script opens a page, uses an explicit viewport, and saves a PNG. Replace the example URL with a page your app is allowed to capture. It uses domcontentloaded for navigation and then waits for a page-specific selector; adapt that selector to your app’s actual ready state.
const { chromium } = require('playwright');
async function main() {
const browser = await chromium.launch();
try {
const page = await browser.newPage({
viewport: { width: 1200, height: 630 },
deviceScaleFactor: 1,
});
await page.goto('https://example.com', {
waitUntil: 'domcontentloaded',
timeout: 30_000,
});
// Replace this with an element that signals your app is ready.
await page.locator('body').waitFor({ state: 'visible', timeout: 10_000 });
await page.screenshot({ path: 'preview.png', type: 'png' });
} finally {
await browser.close();
}
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
Run it with node preview.js. For a dashboard that requires authentication, establish the intended session and app state before taking the screenshot. Avoid putting credentials directly in source code; load them using your app’s established secret-management approach.
4. Use the right readiness condition
Navigation completion and application readiness are different. A page can finish initial navigation before its data, images, or client-rendered components appear. Wait for the signal that means the preview is useful: a known heading or container, a completed loading state, or an app-specific readiness hook.
domcontentloadedwaits for the initial document to be parsed, but does not guarantee that client-side data or images are ready.loadwaits for load-event resources, but may not indicate that app rendering is complete.networkidlecan be useful for pages whose requests settle, but long-lived requests may prevent the page from becoming idle.- A selector wait is often more precise when the app has a stable element that appears only after rendering.
For dynamic pages, combine navigation with a specific selector or state check, then capture. If the page has lazy-loaded images, scroll the relevant region into view or use full-page capture where appropriate, and verify that the desired assets have loaded before generating the final image.
5. Capture full pages and individual elements
To capture the whole scrollable document, pass fullPage: true:
await page.screenshot({ path: 'full-page.png', fullPage: true });
For a specific component, locate it and take an element screenshot:
const card = page.locator('[data-preview-card]');
await card.waitFor({ state: 'visible' });
await card.screenshot({ path: 'card.png' });
Use a selector that identifies the intended element uniquely. If an element is below the fold, Playwright’s locator screenshot flow can bring it into view; confirm that sticky headers, overlays, or responsive layout do not obscure the desired result.
6. Select image format and scale
Playwright supports PNG, JPEG, and WebP screenshots. PNG is suitable when lossless output is important. JPEG and WebP support a quality option; PNG does not use that option. You can also return screenshot bytes as a buffer for post-processing instead of writing directly to a file.
// JPEG with a quality setting
await page.screenshot({ path: 'preview.jpg', type: 'jpeg', quality: 82 });
// WebP with a quality setting
await page.screenshot({ path: 'preview.webp', type: 'webp', quality: 82 });
// Capture bytes for further processing
const bytes = await page.screenshot({ type: 'png' });
Set deviceScaleFactor: 1 for CSS-pixel output, or use a higher value when the consumer benefits from device-pixel detail. A larger scale produces more pixels and can increase image size, memory use, and the time needed to encode or transfer the image. Choose the format and scale based on the receiving preview system’s supported formats and size constraints.
7. Run captures in Linux, CI, or Docker
In a deployment environment, browser binaries and system dependencies are runtime requirements. Keep the Playwright package and browser versions aligned, and use a version-pinned container image if that fits your deployment. Playwright’s Docker documentation says the package itself is installed separately from the image.
For Chromium in Docker, Playwright recommends --ipc=host to reduce out-of-memory crashes. Its Docker documentation also recommends using --init. Consult the [official Playwright Docker guide](https://playwright.dev/docs/docker) for the current image and runtime guidance.
docker run --init --ipc=host your-playwright-image
This command shows the relevant runtime flags, not a complete image build. Build and pin the image for the Playwright version your app installs, and provide the app’s code and configuration through your normal deployment process.
8. Make preview generation reliable
- Use an explicit viewport. This makes layout and output dimensions repeatable.
- Wait for an app-specific ready signal. A navigation event alone may be too early for a client-rendered app.
- Set timeouts deliberately. Bound navigation and selector waits so one slow page does not hold a worker indefinitely.
- Always close the browser. Put cleanup in a
finallyblock so failures do not leak browser processes. - Keep browser versions aligned. Reinstall browsers when updating the Playwright package as needed.
- Separate capture failures from image delivery. Record whether the page failed to load, the readiness condition timed out, or writing/processing the image failed.
- Limit concurrency to available resources. Browser processes consume memory and CPU; measure the workload in your own deployment before increasing parallel captures.
A service that accepts URLs submitted by users also needs app-specific security and scaling design. This research does not establish a safe URL policy, data retention scheme, or production capacity for a particular SaaS app, so define those separately for your deployment.
9. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Browser executable is missing | The browser for the installed Playwright version was not installed in this environment. | Run the Playwright browser installation command for the selected browser and deployment environment. |
| Browser fails to launch in Linux or Docker | Required system dependencies are unavailable, or the container runtime is constrained. | Install the documented dependencies or use the appropriate Playwright container setup; review the Docker guidance. |
| Chromium crashes with memory-related errors | The container may have limited shared memory or too many concurrent captures. | Follow the Docker guide’s Chromium recommendation for --ipc=host, and reduce concurrency if needed. |
| Screenshot is blank or missing app data | The capture happened before client rendering or data loading completed. | Wait for an app-specific selector or ready state before capturing. |
| Navigation times out on a page with ongoing requests | The selected readiness condition may wait for network activity that never settles. | Use a more suitable navigation event and wait for the specific content needed for the image. |
| Preview dimensions differ from expectations | Viewport dimensions or device scale were implicit or misunderstood. | Set viewport and deviceScaleFactor explicitly; account for the resulting output pixel dimensions. |
| Image is unexpectedly large | Full-page capture or a high device scale created many pixels. | Capture only the viewport or target element, reduce scale, or use JPEG/WebP quality where acceptable. |
| Fonts or images appear incomplete | Assets were still loading when the screenshot was taken. | Wait for the assets or app state required by the preview, and use a controlled environment with the needed fonts and resources. |
10. Performance, reliability, and cost
With Playwright, your SaaS app operates the browser and pays for the compute, memory, storage, and transfer used by its capture pipeline. Full-page screenshots, high device scale, image post-processing, and high concurrency can all increase resource use. Keep previews to the smallest useful capture area and scale, reuse browser processes where appropriate for your architecture, and measure actual workload behavior before setting capacity targets.
For reliability, pin the Playwright version and deployment image, install matching browser binaries, use explicit readiness conditions, and ensure cleanup occurs after both success and failure. The official docs are version-sensitive; recheck them against the version selected for your app.
Or skip the browser setup
ScreenshotNeo provides a website screenshot API and MCP server. One GET request can return a PNG, JPEG, WebP, or PDF; its other capture options include viewport and full-page capture, CSS selector capture, device presets, custom CSS and JavaScript, and waits for a selector, delay, or network idle. See the ScreenshotNeo API documentation for 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}`);
ScreenshotNeo removes cookie banners, popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.
Sign up for 1,000 free screenshots a month, with no card required.
FAQ
Does an Indian SaaS app need a special Playwright setting?
No India-specific setting is established by the Playwright guidance here. Set deployment region and data handling according to your app’s own requirements.
Should a preview use a full-page screenshot?
Only if the consumer needs the whole page. A viewport or element screenshot is usually a better fit for a compact preview asset.
Can I generate an image without saving it first?
Yes. Playwright can return screenshot bytes as a buffer so your app can post-process or store them through its own pipeline.


