How to run Playwright screenshot tests on an Indian VPS
Set up version-matched Playwright screenshot tests on an Indian Linux VPS, keep visual baselines stable, and troubleshoot common CI failures.
To run Playwright screenshot tests on an Indian VPS, install your project from its lockfile, install the browser binaries and Linux dependencies for that exact Playwright version, then run the tests headlessly. Keep the browser, operating system, fonts, viewport, and device scale consistent between baseline generation and checks. Start with one worker and increase concurrency only after measuring your suite on the VPS.
A headless Linux VPS does not need a desktop session for normal Playwright runs. Select an India region if it helps the runner reach your application or services; there is no universal CPU or RAM minimum for screenshot tests, so size the host using your actual workload.
1. Prepare the VPS and repository
Use a supported Linux image with a supported Node.js runtime for your project. The examples below assume the repository already contains a Playwright Test project and a committed npm lockfile. Install Node.js using your organization’s normal method, then connect to the VPS and clone the repository.
ssh your-user@your-vps
# On the VPS:
git clone YOUR_REPOSITORY_URL
cd YOUR_REPOSITORY_DIRECTORY
Replace the placeholders with your repository URL and directory. Keep credentials out of shell history and source control. If tests need application credentials, pass them through the runner’s secret or environment-variable mechanism.
2. Install matching Playwright browsers and dependencies
For an existing npm project, the basic setup is:
npm ci
npx playwright install --with-deps
npx playwright test
npm ci installs the versions recorded in the lockfile. The Playwright package version determines the expected browser builds, so install browsers after the project dependencies and repeat the browser installation when upgrading Playwright. Playwright’s [CI guide](https://playwright.dev/docs/ci) documents this workflow, and its [browser installation guide](https://playwright.dev/docs/browsers) explains browser and system dependency installation.
Use --with-deps where the account and Linux distribution allow installation of operating-system packages. This often requires root or sudo privileges. If you cannot install system packages as the test user, ask the VPS administrator to provision the dependencies or use a suitable Playwright container image.
Install Chromium only when that is all you test
If your project only needs Chromium, you can limit the browser installation:
npx playwright install --with-deps chromium
For a headless-shell-only setup, Playwright documents the --only-shell option. Check the current [browser CLI documentation](https://playwright.dev/docs/browsers) before using it, and confirm that your project’s launch mode is compatible. A Chromium-only install does not cover Firefox or WebKit projects.
Expose a stable test command
A package script makes local and VPS runs easier to compare. Add or adapt this entry in package.json:
{
"scripts": {
"test:e2e": "playwright test"
}
}
Then use the same command in your shell or CI runner:
npm run test:e2e
Retain Playwright reports, traces, and screenshot output as artifacts if your runner supports artifact retention. This makes a failed run easier to inspect after the test process exits.
3. Capture screenshots and compare them to baselines
Use page.screenshot() when a test should write an image directly. Use Playwright Test’s toHaveScreenshot() matcher when you want a stored reference image and automatic visual comparison.
import { test, expect } from '@playwright/test';
test('product page matches its visual baseline', async ({ page }) => {
await page.goto('https://your-app.example/products');
await expect(page).toHaveScreenshot('products.png');
});
Run the test with npx playwright test. On the first run, Playwright may report a missing expected snapshot. Generate reference screenshots deliberately in the same environment you intend to use for comparisons:
npx playwright test --update-snapshots
Review the generated changes before committing them. Updating snapshots should represent an intentional UI change, not a way to silence unexplained rendering drift. See the [visual comparisons guide](https://playwright.dev/docs/test-snapshots) for the snapshot workflow and environment considerations.
Choose the screenshot region and scale
A screenshot of the viewport is the default. Set fullPage: true when the whole scrollable page is under test:
await page.screenshot({ path: 'page.png', fullPage: true });
Playwright screenshot APIs also support animation handling, masking changing regions, output paths, and CSS-pixel or device-pixel scale choices. Keep the options and viewport consistent when generating baselines and checking them. A mask excludes those pixels from visual review; make it narrow and use it only for content that is expected to change and is outside the behavior being tested.
await page.screenshot({
path: 'page.png',
fullPage: true,
animations: 'disabled',
mask: [page.locator('[data-testid="live-clock"]')]
});
For assertion-based screenshots, configure the equivalent screenshot options on toHaveScreenshot() or in the test configuration. Consult the [Page screenshot API](https://playwright.dev/docs/api/class-page#page-screenshot) and [snapshot assertion API](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot) for the current option names and behavior.
4. Keep screenshot baselines reproducible
Visual snapshots are environment-specific. Browser rendering and available fonts can differ between browsers and operating systems. Playwright includes browser and platform details in snapshot naming, but a matching name does not make two different environments pixel-identical. Generate and compare baselines with the same browser build and, where practical, the same operating-system image and fonts.
- Pin the project dependency with the lockfile and install its matching browser build.
- Use the same Linux distribution or the same pinned container image for baseline creation and checks.
- Keep viewport dimensions, device scale factor, color scheme, locale, timezone, and relevant test settings fixed.
- Wait for the page state your test cares about before capturing; avoid arbitrary delays where a meaningful readiness signal is available.
- Disable animations or mask known dynamic regions only when that is appropriate for the behavior under test.
- Review snapshot diffs and update baselines only for intended changes.
If the test verifies animation, timestamps, rotating content, or live data, disabling or masking it may hide a real regression. Decide which behavior matters before adding screenshot normalization.
5. Choose host installation or Docker
| Approach | Useful when | Things to keep aligned |
|---|---|---|
| Install on the VPS host | You want a direct Linux setup and already manage the host’s packages. | Linux distribution, system libraries, fonts, Node.js, Playwright package, and browser builds. |
| Official Playwright Docker image | You want a more repeatable browser and system-dependency environment. | Pin the image to a Playwright version aligned with the project dependency. |
The [official Docker documentation](https://playwright.dev/docs/docker) lists supported image variants and warns that the image version must align with the Playwright package version; a mismatch can leave browser executables unavailable. The documented image variants include Ubuntu 22.04 and 24.04. Playwright does not support its Firefox and WebKit browser builds on Alpine’s musl-based distribution.
A typical container invocation for Chromium is:
docker run --rm --init --ipc=host \
-v "$PWD:/work" -w /work \
mcr.microsoft.com/playwright:vX.Y.Z-noble \
sh -lc 'npm ci && npx playwright test'
Replace vX.Y.Z-noble with a current official image tag that matches the Playwright version in your lockfile. Verify current tags in the [Docker guide](https://playwright.dev/docs/docker). The --init option helps reap child processes; --ipc=host is recommended for Chromium because constrained shared memory can cause crashes. Do not add elevated container capabilities by default. The Docker guide mentions SYS_ADMIN only as a troubleshooting attempt for unusual launch failures in local development.
6. Run headless, or use Xvfb for headed debugging
Playwright launches browsers headlessly by default, so ordinary screenshot tests on a Linux VPS do not require a desktop or X server. Run the suite directly:
npx playwright test
If you need to reproduce a problem with a visible browser on a Linux host, install Xvfb and run the command inside a virtual display:
xvfb-run -a npx playwright test
Use headed execution as a debugging aid. It adds display setup and resource use; it is not required for routine headless test runs. The [Playwright CI guide](https://playwright.dev/docs/ci) covers headless execution and Xvfb.
7. Start with one worker, then measure concurrency
Begin with one worker on a new VPS. Playwright recommends one worker in CI for stability and reproducibility, while allowing parallel work on sufficiently powerful self-hosted systems. Screenshot suites can use substantial memory and CPU because each worker may launch browser processes and load pages independently.
npx playwright test --workers=1
After a representative run, inspect CPU, memory, disk use, and total duration. Increase workers gradually only if the host has capacity and the suite remains stable. There is no authoritative universal VPS size for Playwright screenshot tests: page complexity, browser count, test concurrency, and the application all affect resource needs. The [CI documentation](https://playwright.dev/docs/ci) discusses worker guidance.
8. Select an Indian VPS for the workload
Choose the region based on which application, APIs, and test data the runner must reach. Confirm that the provider offers the Linux image you need, root or sudo access for dependency installation, Docker if applicable, outbound connectivity, and resource limits suitable for your test. India-region providers advertise Linux VPS options in locations such as Mumbai, but provider listings establish availability claims, not independently measured Playwright performance.
Do not choose an instance based on a generic minimum specification. Run the actual suite with one worker and observe CPU, memory, disk space, and run time. If the suite is slow or unstable, determine whether the limiting factor is host capacity, the application response, browser startup, or external network access before resizing or increasing parallelism.
9. Troubleshoot common failures
| Symptom | Likely cause | What to do |
|---|---|---|
| Browser executable not found | Browser install was skipped, or the Playwright package was upgraded without reinstalling its browser build. | Run npx playwright install for the installed package version. For Docker, align the image tag and project Playwright version. |
| Browser fails to launch on Linux | Missing system dependencies, incompatible libraries, or a startup problem. | Install dependencies with npx playwright install --with-deps where permitted. Enable browser logs with DEBUG=pw:browser. |
| Installation fails behind a proxy | The browser download or Linux package manager cannot reach its destination, or proxy variables are not available to the install process. | Check proxy reachability and follow the browser guide’s guidance for running installs as root and passing package-manager proxy environment variables. |
| Chromium crashes in Docker | Shared memory constraints or unreaped child processes can contribute to instability. | Use the documented --ipc=host and --init settings, then inspect browser logs and container resource limits. |
| Snapshots differ between VPS and local machine | Different browser, OS, fonts, viewport, device scale, color settings, or animation state. | Compare those inputs and generate/check snapshots in the same environment where practical. Update baselines only for reviewed, intentional changes. |
| Tests fail only when running in parallel | Resource contention, shared test state, or test interference. | Reproduce with one worker, inspect resource use and shared fixtures, then raise worker count gradually. |
| Test waits time out or captures a blank page | The app may not be ready, the VPS cannot reach a dependency, or navigation failed. | Check network access, navigation errors, and the page readiness condition. Wait for a meaningful selector or application state before capture. |
| Headed mode reports no display | No X server is available on the headless host. | Use headless mode for routine runs, or install Xvfb and invoke the tests with xvfb-run -a. |
For browser startup diagnostics, run:
DEBUG=pw:browser npx playwright test
Or skip the browser setup
If you need a clean screenshot of a URL rather than a self-managed browser test environment, [ScreenshotNeo](https://screenshotneo.com) provides a website screenshot API and MCP server. Its one-call request can return an image; see the [API documentation](https://screenshotneo.com/docs/) for parameters and response details.
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}`);
- Cookie banners, newsletter popups, and chat widgets are removed before the shot; each cleanup step can be turned off.
- Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed. Response headers report the page verdict and billing status.
- An MCP server provides
take_screenshot,get_page_info, andcapture_pdftools 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 screenshots. Every feature is on every plan.
Create a free ScreenshotNeo account for 1,000 screenshots a month with no card.
Performance, reliability, and cost notes
- Performance: Browser startup, page complexity, network access, and worker count all affect runtime. Measure a representative run before tuning concurrency.
- Reliability: Lock the project dependency, install matching browsers, and keep the baseline and check environments aligned. Retain failure artifacts when possible.
- VPS cost: The research does not establish a standard instance size or price for this workload. Compare providers’ current Linux images, resource allocations, regional availability, and access limits, then size from observed use.
- Alternative for URL screenshots: ScreenshotNeo pricing is Free for 1,000 shots/month, 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. Its usage API can help track use.
Frequently asked questions
Can Playwright run headless on a VPS?
Yes. Headless is the default, and standard runs do not need a desktop session.
Do I need Xvfb?
Only when you need a headed browser on a Linux VPS without a display. Use xvfb-run for that case.
Should I install all three browser engines?
Install the engines your project tests. Chromium-only installation is suitable when the suite only targets Chromium.
Can I use the same screenshots on Linux and macOS?
Do not assume pixel-identical output across operating systems. Rendering and fonts can differ; generate and compare baselines in a consistent environment.
What VPS size do I need?
There is no universal answer supported by the available evidence. Start with one worker, run your suite, and size from observed resource use and runtime.
Can ScreenshotNeo replace Playwright visual regression tests?
It can return website screenshots from an API or MCP tool, but this guide’s Playwright matcher workflow is for comparing screenshots against project baselines. Choose the workflow that matches whether you need a managed URL capture or an in-suite visual assertion.


