ScreenshotNeo

BlogHow-to

How to Set the Playwright Screenshot Directory

Configure Playwright screenshot folders correctly for test artifacts, explicit captures, and visual baselines with runnable examples and fixes.

By the ScreenshotNeo team29 September 20267 min read

How to Set the Playwright Screenshot Directory

Direct answer: Set Playwright Test’s top-level outputDir to choose where test-run artifacts are written. Configure automatic capture separately with use.screenshot.

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

export default defineConfig({
  outputDir: './screenshots',
  use: {
    screenshot: 'only-on-failure',
  },
});

With this configuration, Playwright writes test artifacts below ./screenshots. The documented default is test-results, resolved under the package configuration directory. Playwright cleans the configured output directory at the start of a run and creates a unique subdirectory for each test, which keeps parallel tests from writing to the same location.

That setting applies to artifacts generated by Playwright Test. It does not change the destination of every screenshot API. An explicit page.screenshot() call receives its own path, while visual assertion baselines created by expect(page).toHaveScreenshot() use snapshotPathTemplate.

Choose the screenshot destination by purpose

What you are saving Setting or API Typical location behavior
Automatic screenshots, traces, and videos from a test run outputDir plus use.screenshot Inside the configured output directory, separated by test
A screenshot explicitly requested in test code page.screenshot({ path }) The path you provide; a relative path uses the current working directory
Expected images for visual assertions snapshotPathTemplate A snapshot directory determined by the template and test metadata

Before changing a path, identify which of these three outputs you mean. Changing outputDir will not relocate visual baselines, and changing a page.screenshot() path will not change automatic failure artifacts.

Playwright uses different path settings for test artifacts, explicit screenshots, and visual baselines.
Playwright uses different path settings for test artifacts, explicit screenshots, and visual baselines.

Configure automatic Playwright Test screenshots

Set one directory for all projects

Put outputDir at the top level of playwright.config.ts when every project should use the same artifact root.

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

export default defineConfig({
  testDir: './tests',
  outputDir: './artifacts/playwright',
  use: {
    screenshot: 'on',
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
  ],
});

use.screenshot accepts 'off', 'on', or 'only-on-failure'. Use 'on' when every test needs an image, 'only-on-failure' when artifacts are mainly for diagnosis, and 'off' when screenshots are unnecessary. The capture policy controls whether Playwright takes screenshots; it does not name a destination directory.

Give one project a different output directory

A project-level outputDir overrides the top-level value for that project. This is useful when browser engines, locales, or deployment targets need separate artifact trees.

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

export default defineConfig({
  outputDir: './artifacts/all',
  projects: [
    {
      name: 'desktop',
      outputDir: './artifacts/desktop',
      use: { screenshot: 'only-on-failure' },
    },
    {
      name: 'mobile',
      outputDir: './artifacts/mobile',
      use: { screenshot: 'only-on-failure' },
    },
  ],
});

Keep project directories distinct if your CI collects files by project. Playwright still creates per-test subdirectories below each configured root.

Understand cleanup and CI retention

Playwright cleans the configured output directory at the start of a run. Do not use outputDir as a permanent archive for screenshots that must survive later runs. Copy artifacts to a retained CI artifact store after the test process finishes, or write long-lived exports to a separate directory from your test output directory.

The cleanup behavior also means a path outside the Playwright output tree is safer for manually curated reference material. Keep generated diagnostics and committed assets separate so a test run cannot remove them.

Save an explicit screenshot from test code

When a test decides exactly when to capture, call page.screenshot() with a path.

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

test('save a checkout screenshot', async ({ page }) => {
  await page.goto('https://example.com');
  await page.screenshot({ path: 'artifacts/manual/checkout.png', fullPage: true });
});

A relative path passed directly to the screenshot API is resolved from the current working directory, not automatically from the test file or outputDir. That can surprise developers who run tests from different directories in local shells and CI.

Use testInfo.outputPath() for test-scoped files

For a screenshot that belongs with one test’s other results, use the test’s testInfo object. The helper returns a path inside that test’s output directory and supports path segments.

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

test('capture the account page', async ({ page }, testInfo) => {
  await page.goto('https://example.com/account');
  const path = testInfo.outputPath('screenshots', 'account.png');
  await page.screenshot({ path, fullPage: true });
});

This helper keeps parallel tests from interfering with one another and constrains the resulting path to the test output directory. Use it when you want predictable, test-specific placement without manually inventing unique filenames.

Put visual comparison baselines in their own directory

expect(page).toHaveScreenshot() compares the current image with an expected baseline. Baselines are controlled by snapshotPathTemplate, not by outputDir.

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

export default defineConfig({
  snapshotPathTemplate: '{testDir}/__screenshots__/{testFilePath}/{arg}{ext}',
});

The template can use tokens including {testDir}, {testFilePath}, {projectName}, {arg}, and {ext}. Relative template paths resolve relative to the configuration directory.

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

test('homepage visual baseline', async ({ page }) => {
  await page.goto('https://example.com');
  await expect(page).toHaveScreenshot('homepage.png');
});

The path argument is constrained to the snapshot directory associated with the test file. Supplying a path that escapes that directory can throw an error. Treat baselines as versioned test inputs, while treating outputDir files as disposable run artifacts.

Path resolution, naming, and edge cases

  • Configuration-relative paths: A relative outputDir and a relative snapshotPathTemplate are interpreted from the Playwright configuration directory.
  • Current-working-directory paths: A relative path passed to page.screenshot() follows the process working directory.
  • Parallel workers: Prefer testInfo.outputPath() or unique names when writing explicit files. Avoid a fixed filename shared by tests.
  • Multiple projects: Use a project-level outputDir when artifacts must be separated by browser, device, or environment.
  • Full-page images: fullPage: true changes the captured image dimensions, not the directory.
  • Missing parent folders: Let Playwright create the destination when using its output helpers, or create custom parent directories before using a separately managed path.
  • Git repositories: Ignore generated output directories such as test-results or artifacts; commit visual baselines only when they are intentionally part of the test suite.

Common errors and fixes

Symptom Cause Fix
Changing outputDir does not move toHaveScreenshot() images Baselines use snapshot configuration Set snapshotPathTemplate and regenerate baselines deliberately
Explicit screenshots appear in an unexpected folder Relative screenshot paths use the current working directory Use an absolute path, a known project root, or testInfo.outputPath()
Files disappear before a run Playwright cleans outputDir at run start Archive artifacts elsewhere after the run; do not store permanent files there
Parallel tests overwrite one another Tests share a fixed explicit filename Use testInfo.outputPath() or include test metadata in the name
Only failed tests have images use.screenshot is set to 'only-on-failure' Change it to 'on' when every test needs a screenshot
A project still writes to the old directory A project-level value overrides the top-level value Inspect each project object and remove or update its override
A snapshot path is rejected The path escapes the permitted snapshot directory Use a name or path segment inside the configured snapshot tree

Performance, reliability, and cost considerations

Capturing every test screenshot increases browser work and artifact volume. For large suites, 'only-on-failure' limits routine output while preserving failure evidence. Explicit screenshots should be taken after the page reaches the state you intend to document; otherwise timing differences can create noisy artifacts or visual diffs.

Separate disposable artifacts from committed baselines. A stable snapshotPathTemplate, deterministic test data, and consistent browser project settings make visual comparisons easier to review. In CI, retain the output directory only for the duration needed to inspect failures, then upload it to the CI system’s artifact storage.

Playwright itself does not charge per screenshot. Your costs come from browser execution, CI minutes, storage, and any external screenshot service you add. A hosted API can remove browser installation and maintenance work, but it introduces request limits, authentication, and network-failure handling.

Or skip the browser setup

If you need website images rather than Playwright test artifacts, ScreenshotNeo provides a single GET request that returns PNG, JPEG, WebP, or PDF. Its API accepts full-page capture, element selectors, dark mode, device and viewport settings, custom CSS and JavaScript, waits, blocking rules, headers, cookies, user agents, authorization, timezone, geolocation, resizing, caching, signed links, asynchronous jobs, bulk capture, and more. See the ScreenshotNeo documentation for request 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,
)
r.raise_for_status()
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}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const data = Buffer.from(await res.arrayBuffer());
await Bun.write('shot.webp', data);

Cookie banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed; response headers identify the page verdict and whether the request was billed. An MCP server lets Claude, Cursor, and other MCP clients call take_screenshot, get_page_info, and capture_pdf. The free plan includes 1,000 screenshots per month with no card, and paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.

FAQ

What is Playwright’s default screenshot directory?

Playwright Test’s documented default output directory is test-results under the package configuration directory.

A hosted screenshot API can remove common overlays before capturing the page.
A hosted screenshot API can remove common overlays before capturing the page.

Can I set outputDir inside use?

No. Set outputDir at the top level or on an individual project. Put screenshot inside use.

Does outputDir affect screenshots made with page.screenshot()?

Only when you explicitly pass a path derived from the test output directory, such as testInfo.outputPath(). A direct relative path follows the current working directory.

Where should visual baselines go?

Use snapshotPathTemplate and keep the resulting snapshot directory under version control when the baselines are part of your test suite.

How do I keep artifacts from being deleted?

Copy or upload them after the Playwright run. The configured output directory is cleaned at the beginning of the next run.