Set snapshotPathTemplate in playwright.config.ts to define where Playwright stores snapshots, then use assertion-specific pathTemplate settings when screenshots and other snapshots need different layouts. Include {testFilePath} and {arg}{ext} for predictable, test-grouped paths; add {/projectName} when multiple projects share the output tree.
Configure the global and assertion-specific templates
Playwright’s snapshotPathTemplate controls snapshot locations for toHaveScreenshot(), toMatchAriaSnapshot(), and toMatchSnapshot(). The option was added in Playwright v1.28. Put the global template at the top level of your Playwright configuration. Set expect.toHaveScreenshot.pathTemplate or expect.toMatchAriaSnapshot.pathTemplate inside expect to override the global layout for those assertion types. See the Playwright TestConfig API documentation.
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}',
},
},
});
This example puts ordinary snapshots under tests/__screenshots__. Screenshot assertions use a project-aware folder, while ARIA snapshots use a separate __snapshots__ folder. The assertion-specific template replaces the global template for that assertion rather than merely adding a suffix to it.
When to use an override
Keep only the global setting if all snapshot types should follow one organization. Add an override when a type has a distinct purpose or extension, or when screenshot baselines need project separation but other snapshot files do not. The global template remains the fallback for assertion types without their own configured template.
Recommended Free Tools
#1 Best Overall
Choose tokens that make paths stable and readable
Templates are built from literal path text and documented tokens. Playwright substitutes token values using the test, project, and assertion context.
| Token | Meaning | Useful when |
|---|---|---|
{arg} |
Relative snapshot path without its extension, based on the assertion argument or an auto-generated name. | You want distinct assertion names in the path. |
{ext} |
Snapshot extension, including the leading dot. | You want the template to retain the proper file extension. |
{testFilePath} |
Path from testDir to the test file. |
You want snapshots grouped by test file and its subdirectories. |
{testFileDir} |
Directories between testDir and the test file. |
You want the test’s directory structure without its filename. |
{testFileName} |
Test filename, including its extension. | You want the full test filename as a path component. |
{testFileBaseName} |
Test filename without its last extension. | You want a filename-derived folder without the extension. |
{testName} |
Filesystem-sanitized test title, including parent describe titles but not the file name. |
You want test-title context in the snapshot path. |
{projectName} |
Filesystem-sanitized project name; empty for an unnamed project. | You need snapshots for named browser or configuration projects kept apart. |
{snapshotDir} |
The project’s snapshot directory. | You want to base the path on the project’s snapshot directory. |
{testDir} |
The project’s test directory. | You want the path rooted in the project’s test directory. |
{platform} |
The value of process.platform. |
You intentionally need platform-specific snapshots. |
Why templates usually end with {arg}{ext}
{arg} does not include the extension; {ext} does, including its leading dot. Using both at the end—{arg}{ext}—preserves the assertion’s name and file type. Omitting {ext} can leave a generated path without the expected extension, while treating {arg} as if it already includes the extension can produce a malformed naming scheme.
For example, {testDir}/__screenshots__/{testFilePath}/{arg}{ext} groups output under the test directory, mirrors the test file path, then uses the assertion name and extension. Including {testFilePath} avoids scattering all baselines into one flat directory; including {arg} helps distinguish multiple assertions from the same test file.
Rank #2
Handle named and unnamed projects
When several projects write into one snapshot tree, include the project name to prevent otherwise similar snapshots from different projects sharing a location. A plain {projectName} token becomes an empty value for an unnamed project. If placed between separators, that can leave an unwanted empty path segment.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Use the conditional-separator form {/projectName} to emit the slash only when the project name is non-empty. With a template such as __screenshots__{/projectName}/{testFilePath}/{arg}{ext}, a named chromium project has a chromium folder, while an unnamed Firefox project has no empty project folder: its test file follows __screenshots__ directly. A token may be preceded by one character that is emitted only if the token has a non-empty value.
This is especially useful when a configuration mixes named and unnamed projects. If every project is named and you want an explicit project folder, use {projectName} with a separator. If output should intentionally be shared regardless of project, omit the token, understanding that matching paths can then converge on the same location.
Rank #3
Set a path for one assertion
Assertion arguments influence {arg}, so a named snapshot gives a predictable, reviewable path. For a screenshot:
import { test, expect } from '@playwright/test';
test('checkout page', async ({ page }) => {
await page.goto('https://example.com/checkout');
await expect(page).toHaveScreenshot('checkout-home.png');
});
The argument identifies the snapshot; the configured template determines how its path is assembled. For screenshot snapshots, PNG is the default. Giving the screenshot an explicit .webp name selects WebP, which the Playwright guide describes as lossless. Consult the Playwright snapshot guide for screenshot assertion behavior.
Provide nested path segments directly
toHaveScreenshot() also accepts an array of path segments, which is useful when a single assertion needs a nested location:
await expect(page).toHaveScreenshot(['checkout', 'desktop', 'home.png']);
Playwright requires the resolved path to remain inside that test file’s snapshots directory. If the array or other path construction escapes that boundary, Playwright throws rather than allowing the assertion to write outside it. Use ordinary nested segments for organization; do not use traversal components such as .. to target another test’s directory.
Keep paths portable across operating systems
A relative snapshotPathTemplate is resolved relative to the configuration directory, not arbitrarily to the shell’s current working directory. Forward slashes are accepted as separators on any platform, so templates using / remain readable and portable in configuration files. Use absolute paths only when the output location truly needs to sit outside the configuration-relative layout and the supported configuration permits it.
Think about portability before adding {platform}. It deliberately makes the path depend on process.platform; that may be appropriate if rendered output is expected to differ by operating system, but it can also split baselines and complicate review when the same tests run on multiple platforms. Likewise, project names should be stable if snapshot paths are part of code review or CI artifacts.
Understand the older snapshotDir setting
snapshotDir remains the base-directory option for toMatchSnapshot(), but Playwright marks it as the older approach and directs users to snapshotPathTemplate for customized layouts. Prefer a template when you need placement based on the test file, assertion name, project, or other documented tokens. Avoid configuring both settings as competing descriptions of the same desired layout; check the API documentation for the Playwright version used by your project if migrating existing configuration.
Troubleshoot path template problems
- Snapshots appear in an unexpected root: Check whether the template is relative and remember that it resolves from the configuration directory. Verify which project supplies
testDirand whether an assertion-specific override is active. - Unnamed projects create awkward paths: Replace a separator directly before
{projectName}with the conditional form, such as{/projectName}, so the separator disappears when the name is empty. - Files lose or duplicate extensions: Treat
{arg}as extensionless and keep{ext}at the end of the template. For a screenshot-specific format, provide an explicit screenshot filename extension. - Two projects appear to use the same snapshot path: Add a project component to the relevant template. Use the conditional separator if some projects are unnamed.
- An assertion-specific setting seems ignored: Confirm that the setting is nested under the correct
expectassertion key and that the assertion type matches it. For example,toHaveScreenshot.pathTemplatedoes not configure ARIA snapshots. - Playwright rejects an array path: Ensure the resolved screenshot path stays inside the test file’s snapshots directory; an assertion cannot write outside that boundary.
- Snapshots differ across machines: Inspect whether
{platform}or differing project/test configuration is intentionally part of the path. A path template controls where a baseline is stored, not whether the rendered page itself is identical.
Or skip the browser setup
If your goal is to capture a live website rather than manage Playwright test baselines, ScreenshotNeo provides a one-request screenshot API and an MCP server. Its API can accept consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each of those steps can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers indicate the page verdict and billing status. AI agents can use its MCP tools, including take_screenshot, get_page_info, and capture_pdf.
For a direct request, use the ScreenshotNeo API documentation for the access key and options:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
ScreenshotNeo’s free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. That is a different workflow from Playwright snapshot testing: it captures a URL through an API rather than adding a baseline assertion to your test suite. Sign up for ScreenshotNeo’s free plan to try 1,000 screenshots a month without a card.
Free tools Windows power users keep installed
One-click scans. No signup required.
Frequently Asked Questions
Can one snapshot template be used for screenshot and ARIA assertions?
Yes. Set a global template for shared path rules, then override an assertion type only when it needs a different layout.
Does snapshotPathTemplate change how Playwright compares snapshots?
No. It controls snapshot location; it does not change the assertion’s comparison behavior.
Quick Recap
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.

