Playwright Tags: How to Organize and Run Tagged Tests
Tag Playwright tests with clear labels, then use grep filters and projects to run the right subset locally or in CI.
Playwright tags are labels attached to tests or test groups. Add them with a test details object or an @ token in the title, then select tests with --grep or exclude them with --grep-invert. Use tags for categories that cut across your suite, such as smoke tests or checkout tests; use projects for configured execution groups such as browsers or environments.
Tags must start with @. Playwright displays them in reports, and its grep filter searches a combined identity string that includes the project name, file name, describe title, test title, and tags. That means grep can match ordinary text too, not just explicit tags. See the official tag guide, Test API, and command-line reference.
1. Add tags to tests
The details-object form keeps classification out of the human-readable test title. This is a complete example test file:
import { test, expect } from '@playwright/test';
test('checkout accepts a valid card', {
tag: ['@smoke', '@critical'],
}, async ({ page }) => {
await page.goto('https://example.com/checkout');
await expect(page.getByRole('heading', { name: /checkout/i })).toBeVisible();
});
Replace the example URL and assertion with your application’s checkout page and expected behavior. You can also put the tag token in the title:
test('checkout accepts a valid card @smoke', async ({ page }) => {
await page.goto('https://example.com/checkout');
await expect(page.getByRole('heading', { name: /checkout/i })).toBeVisible();
});
A tag on a describe group applies to tests in that group. Individual tests can add more tags:
test.describe('checkout', { tag: '@checkout' }, () => {
test('accepts a valid card', { tag: ['@smoke', '@critical'] }, async ({ page }) => {
await page.goto('https://example.com/checkout');
await expect(page.getByRole('heading', { name: /checkout/i })).toBeVisible();
});
test('shows a declined-card message', { tag: '@regression' }, async ({ page }) => {
await page.goto('https://example.com/checkout');
// Add the declined-card setup and assertion for your application.
});
});
Pick a tag scheme that reflects decisions your team makes. For example, @smoke and @regression can describe execution purpose, @slow can identify tests that take longer, and @checkout can describe a product area. These are practical naming suggestions, not a prescribed Playwright taxonomy. Agree on spelling and meaning, then apply a shared label at the describe boundary when every test in that group belongs to it.
2. Run tests by tag from the command line
Run commands from the project root where the Playwright test configuration and package are available:
# Include tests matching one tag
npx playwright test --grep @smoke
# Exclude tests matching a tag
npx playwright test --grep-invert @slow
# Include tests matching either tag (regular-expression OR)
npx playwright test --grep "@smoke|@critical"
# Include tests containing both tags (regular-expression lookaheads)
npx playwright test --grep "(?=.*@smoke)(?=.*@critical)"
--grep and --grep-invert take regular-expression patterns. The OR pipe and AND lookaheads above are regex syntax; they are not separate Playwright operators. Quote patterns with shell-significant characters, especially the pipe and parentheses. PowerShell has its own argument parsing rules; follow Playwright’s shell-specific examples in the tag documentation if a pattern is changed or interpreted unexpectedly.
Other useful command combinations include restricting a tag selection to a project, or to a file:
# Smoke tests in one configured project
npx playwright test --project=chromium --grep @smoke
# Regression-tagged tests from one file
npx playwright test tests/checkout.spec.ts --grep @regression
Use npx playwright test --list --grep @smoke to inspect the selected tests without running them. Use npx playwright test --help to see the CLI options available in the Playwright version installed in your project.
3. Set a filter in Playwright configuration
For a deliberate default selection, set grep or grepInvert in playwright.config.ts. The following keeps the smoke filter scoped to one project:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
grep: /@smoke/,
// To exclude a tag in this project instead, use:
// grepInvert: /@slow/,
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
],
});
Configuration grep accepts a regular expression or an array of regular expressions. An array acts as alternative patterns: a test matching any pattern can be selected. The config also supports grepInvert for exclusion. A project can have its own filter, which is useful when selection policy differs by project. Check the official TestConfig reference and projects guide for the exact options.
A config-level filter changes what an ordinary test run selects. If most runs should include the full suite, keep selection on the command line instead, or make the filtered config choice explicit to the team and CI jobs.
4. Choose between tags and projects
| Use | Answers | Selection example |
|---|---|---|
| Tag | Which cross-cutting category does this test belong to? | --grep @smoke |
| Project | Under which shared configuration should this test run? | --project=chromium |
| Both | Which category, within which configured execution group? | --project=chromium --grep @smoke |
Projects commonly define browser, device, or environment configurations. Tags classify tests across those configurations. A test tagged @smoke can be selected in more than one project; a project represents how a group runs rather than a test category. See Playwright projects.
5. Add a run-level tag when useful
The configuration tag option labels every test in that configured run, which can help identify run context in reports. It does not select tests. Each configured tag must start with @.
import { defineConfig } from '@playwright/test';
export default defineConfig({
tag: '@staging',
});
Keep this separate from test-level tags: use grep and grepInvert to choose a test subset. The run-level option is documented in the TestConfig API.
6. Organize tags so filters stay understandable
- Use stable, specific names. A team-wide
@smokedefinition should mean the same thing in every folder and project. - Keep one label per useful dimension. A test may have several tags, such as
@checkoutand@smoke, when each helps answer a different selection question. - Tag groups only when the whole group qualifies. Place the tag on individual tests if only some members qualify.
- Review filters with
--list. This catches unexpected selection before a long run or CI change. - Use distinctive patterns. Since grep searches titles, paths, project names, and tags together, a generic pattern may match text that was not intended as a tag.
Playwright does not prescribe a universal naming scheme or a maximum number of tags. Keep the scheme small enough that a teammate can predict what a filter selects.
Or skip the browser setup
If you need screenshots of pages while documenting or debugging tagged browser runs, ScreenshotNeo is a website screenshot API and MCP server from ScreenshotNeo. One GET request captures a URL without setting up a browser locally. See the ScreenshotNeo API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://playwright.dev -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://playwright.dev"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
access_key: 'YOUR_API_KEY',
url: 'https://playwright.dev',
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await require('node:fs/promises').writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));
ScreenshotNeo removes cookie banners, popups, and chat widgets before capture. Bot checks, blank pages, failed loads, and cache hits are never billed. Its MCP server lets AI agents use screenshot tools, and 1,000 screenshots per month are free with no card; paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month, with no card.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| The tag filter selects no tests | The tag is missing, misspelled, or lacks the required @ prefix; a config filter may also narrow selection. |
Check test and group declarations, then inspect the selection with npx playwright test --list --grep @smoke. Review config and project grep settings. |
| The filter selects tests with no matching tag | Grep checks the combined project, file, group, title, and tag identity string. | Use a more distinctive pattern and search filenames, describe titles, test titles, and project names for the matching text. |
| A test title contains the tag but report grouping looks awkward | The tag was included as title text. | Use the test details object’s tag field to keep classification separate from the display title. |
| Tests appear in an unexpected browser or environment | A tag filter selects tests; it does not define their execution configuration. | Use --project or adjust project configuration, then combine with grep if needed. |
| OR or AND selection behaves unexpectedly | The expression is a regular expression, or the shell altered special characters. | Quote the pattern, inspect it with --list, and consult the shell-specific command in the Playwright tag guide. |
| Normal runs unexpectedly execute only a subset | A grep or grepInvert default is set in configuration. |
Remove the config filter or make it intentional per project; pass a CLI filter only for selected runs. |
Performance, reliability, and cost
Tags do not make selected tests faster individually; they let you run fewer tests when a subset is appropriate. Run smoke coverage for quick feedback and broader coverage on the cadence your team needs. Confirm that the filter selects the intended set, since an overly broad grep can erase the time savings and an overly narrow one can omit coverage. The actual runtime depends on the selected tests, project configurations, and your execution environment.
For reliable CI behavior, keep tag meanings consistent, keep selection commands visible in scripts, and review selection changes with --list. Tags and grep are Playwright Test features; no separate service or per-tag charge is involved.
FAQ
Can one Playwright test have multiple tags?
Yes. Provide an array in the details object, and combine filters with an OR pattern or lookaheads when you need either or both labels.
Can I filter tags from the HTML report?
Tags are shown in reports, but test selection for execution is done through grep options or configuration filters. Use --grep to choose the run.
Does a describe-level tag replace tags on its tests?
No. A describe group can apply a shared tag while an individual test adds its own tags.
Should I use tags for Chromium and Firefox?
Use projects for browser configurations and tags for cross-cutting test categories. Combine project selection and a tag filter when both constraints matter.
Official references: Annotations and tags, Test API, TestConfig, Command line, and Projects.


