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

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Set snapshotPathTemplate in playwright.config.ts to define where Playwright stores snapshots, then use expect.toHaveScreenshot.pathTemplate or expect.toMatchAriaSnapshot.pathTemplate when one assertion needs a different layout. The configuration below keeps files grouped by test and assertion, separates named projects safely, and works for screenshots, ARIA snapshots, and value snapshots.

Start with a working configuration

Playwright added snapshotPathTemplate in version 1.28. It controls snapshots produced by expect(page).toHaveScreenshot(), expect(locator).toMatchAriaSnapshot(), and expect(value).toMatchSnapshot(). Put it in the configuration file used by your test run.

import { defineConfig } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  snapshotPathTemplate: '{testDir}/__screenshots__/{testFilePath}/{arg}{ext}',
  expect: {
    toHaveScreenshot: {
      pathTemplate: '{testDir}/__screenshots__{/projectName}/{testFilePath}/{arg}{ext}',
    },
    toMatchAriaSnapshot: {
      pathTemplate: '{testDir}/__snapshots__/{testFilePath}/{arg}{ext}',
    },
  },
});

The top-level template is the default. The nested templates override it for their respective assertion types. In this example, screenshot assertions include a project directory when one exists, while ARIA snapshots use a separate tree.

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

How template resolution works

A relative template is resolved from the directory containing your Playwright configuration. Forward slashes are accepted on every operating system. Playwright substitutes tokens when the snapshot path is created.

Token Value Typical use
{arg} The assertion’s relative snapshot path without its extension, or an automatically generated name. Keep each assertion’s name in the filename.
{ext} The snapshot extension, including the leading dot. End a template with {arg}{ext}.
{platform} The current process.platform. Separate baselines created on different operating systems.
{projectName} The filesystem-sanitized project name, or an empty value for an unnamed project. Keep Chromium, Firefox, and WebKit baselines apart.
{snapshotDir} The project’s snapshot directory. Build paths relative to Playwright’s configured snapshot location.
{testDir} The project’s test directory. Keep snapshots near the test tree.
{testFileDir} Directories between testDir and the test file. Mirror nested test folders.
{testFileBaseName} The test filename without its final extension. Use a short file-based directory or prefix.
{testFileName} The test filename including its extension. Retain the exact source filename.
{testFilePath} The path from testDir to the test file. Group snapshots by test file while preserving folders.
{testName} The filesystem-sanitized test title, including parent describe titles but not the filename. Use the test title as a directory or filename component.

{arg} is extensionless. The extension comes from {ext}, so omitting {ext} can create files without the expected suffix. For predictable organization, include both tokens at the end of the template.

Choose a layout that stays maintainable

One tree for all projects

Use a project-neutral template when every project intentionally shares the same baseline files:

snapshotPathTemplate: '{testDir}/__screenshots__/{testFilePath}/{arg}{ext}'

This is compact, but it is appropriate only when projects are equivalent for snapshot purposes. Different browsers, viewport settings, themes, or operating systems can produce incompatible images in the same location.

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

A separate directory for named projects

For a multi-project configuration, add an optional separator before {projectName}:

snapshotPathTemplate: '{testDir}/__screenshots__{/projectName}/{testFilePath}/{arg}{ext}'

The slash in {/projectName} is conditional. If the project is named chromium, the path contains a chromium directory. If the project has no name, the slash and empty token are omitted, so Playwright does not create an empty directory level.

With a test at tests/ui/example.spec.ts, an unnamed project can write to tests/__screenshots__/ui/example.spec.ts/hero.png; a named Chromium project can write to tests/__screenshots__/chromium/ui/example.spec.ts/hero.png.

Separate assertion families

Screenshot files and ARIA snapshots answer different review questions. Giving them different roots makes code review and cleanup safer:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
expect: {
  toHaveScreenshot: {
    pathTemplate: '{testDir}/__screenshots__{/projectName}/{testFilePath}/{arg}{ext}',
  },
  toMatchAriaSnapshot: {
    pathTemplate: '{testDir}/__snapshots__/{testFilePath}/{arg}{ext}',
  },
}

Keep {testFilePath} in both templates unless you have a strong reason to flatten files. Two test files can use the same assertion name, and flattening would make collisions more likely.

Override the path for an individual assertion

Use the assertion’s path argument when one snapshot needs a custom relative name. A screenshot can receive an array of path segments:

import { test, expect } from '@playwright/test';

test('checkout summary', async ({ page }) => {
  await page.goto('/checkout');
  await expect(page).toHaveScreenshot(['checkout', 'summary.png']);
});

The resulting path is still constrained to that test file’s snapshots directory. If the supplied segments would escape that directory, Playwright throws instead of writing outside the allowed location. Do not use .. segments or absolute paths to bypass this containment rule.

For value snapshots, pass a name such as cart.json to toMatchSnapshot(). For ARIA snapshots, use the API’s supported snapshot name or path form and let the configured toMatchAriaSnapshot.pathTemplate determine the surrounding directories.

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

Snapshot file types and naming

Screenshot assertions use PNG by default. Supplying an explicit .webp filename selects WebP; the Playwright guide describes that output as lossless. A template should normally finish with {arg}{ext} so an assertion’s chosen extension is preserved.

Prefer explicit names for durable tests:

await expect(page).toHaveScreenshot('account-header.png');
await expect(page).toHaveScreenshot(['account', 'billing-panel.webp']);

Automatic names are useful while prototyping, but they are derived from test context and can change when titles or test structure change. Stable assertion names make review diffs easier to understand.

Global template versus assertion-specific template

Need Best setting Reason
One consistent layout for all snapshot types Top-level snapshotPathTemplate Every assertion inherits one rule.
Screenshots need browser/project folders expect.toHaveScreenshot.pathTemplate Only visual files gain the extra level.
ARIA snapshots need a dedicated root expect.toMatchAriaSnapshot.pathTemplate Accessibility baselines remain separate.
One test has a special filename or subfolder Assertion-level path argument The exception stays local instead of complicating global configuration.

Start with the smallest global rule that answers your repository’s needs. Add project separation when projects genuinely produce different baselines, and use assertion-level names for intentional exceptions.

Migration from snapshotDir

snapshotDir remains the older base-directory setting for toMatchSnapshot. It is useful when you only need to change that directory, but snapshotPathTemplate is the more flexible option for customized layouts and for coordinating different snapshot assertion types. During migration, avoid configuring two competing directory schemes without checking where each assertion actually writes.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Record the current paths generated by your existing tests.
  2. Add a template that reproduces the desired directory structure.
  3. Run the suite in update mode once to move or regenerate baselines deliberately.
  4. Review the resulting Git diff and remove obsolete snapshot directories only after all projects pass.

Common failures and fixes

Snapshots appear in an unexpected directory

Check which configuration file the command loaded and whether an assertion-specific template overrides the top-level value. Remember that relative templates resolve from the configuration directory, not necessarily the shell’s current directory.

An empty project directory appears

Use the conditional form {/projectName} rather than a literal slash followed by {projectName}. The conditional prefix is emitted only when the project name is non-empty.

Files have no extension

Add {ext} after {arg}. The argument token does not include an extension.

Two assertions overwrite one another

Include {testFilePath}, use explicit assertion names, or add {testName}. Flattened layouts are especially prone to collisions when different test files use names such as header.png.

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.

Playwright rejects an array path

The array form must remain inside the test file’s snapshots directory. Remove parent-directory segments, absolute components, and any attempt to traverse outside the permitted root.

Baselines differ between projects

Separate named projects with {/projectName}. If operating-system differences are expected, include {platform} as well, then regenerate each project’s baselines intentionally.

The template change creates a large diff

A path-template change changes filenames, so version control reports moves as deletions and additions when similarity is low. Make the change in its own commit, run one controlled update, and inspect that image content—not only paths—matches expectations.

Performance, reliability, and repository practices

  • Keep snapshot paths deterministic. Avoid tokens or generated names that change between runs unless that variability is intentional.
  • Use project-aware paths when browser engines, viewport sizes, themes, or operating systems are different.
  • Keep the test-file component in the path so parallel test execution cannot make unrelated assertions compete for one filename.
  • Store snapshots in version control with the tests that explain them. Review image and ARIA diffs together with the code change that caused them.
  • Use explicit extensions and names when a snapshot is part of a long-lived contract.
  • When reorganizing tests, treat the path change as a migration: update baselines, verify all projects, and remove only unused files.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your goal is a clean screenshot rather than a Playwright assertion baseline, ScreenshotNeo provides a single HTTP request. It accepts the cookie or consent banner like a visitor, removes more than 60 known consent platforms plus newsletter popups and chat widgets before capture, and bills only clean shots. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed; the response identifies the result with X-Page-Verdict and X-Billed headers. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.

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

See the ScreenshotNeo documentation for request options and authentication. The following calls are complete starting points.

cURL

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

Python

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)

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}`);

All 63 options are available on every plan, including full-page lazy-image loading, CSS-selector element capture, dark mode, 12 device presets plus custom viewports, retina scale, PDF paper and page controls, HTML/CSS rendering, custom JavaScript and CSS, clicks, waits, ad and tracker blocking, custom headers and cookies, user agent, authorization, timezone, geolocation, transparent backgrounds, resizing, configurable-TTL caching, signed image links, asynchronous jobs with signed webhooks, bulk capture for up to 100 URLs per call, usage data, and an OpenAPI specification. Parameter names used by other screenshot APIs also work.

The Free plan includes 1,000 shots per month with no card. Paid plans start at $5 for 3,000 shots; yearly billing provides two months free. Create a free ScreenshotNeo account to get started.

FAQ

Which Playwright versions support snapshotPathTemplate?

The option was added in Playwright 1.28. Projects on older versions should upgrade before adopting these templates.

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

Can one template serve screenshots and value snapshots?

Yes. The top-level setting is shared, while assertion-specific settings let you give screenshot or ARIA assertions a different layout.

Does {projectName} always create a folder?

No. It expands to an empty value for an unnamed project. Prefixing it with a conditional separator, as in {/projectName}, prevents an empty directory level.

Frequently Asked Questions

Which Playwright versions support snapshotPathTemplate?

The option was added in Playwright 1.28.

Can one template serve screenshots and value snapshots?

Yes. Use the top-level template for a shared layout and assertion-specific templates for exceptions.

Does {projectName} always create a folder?

No. It is empty for unnamed projects; use {/projectName} to make the separator conditional.

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

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.