- Use the Playwright CLI in the workflow; the old
playwright-github-actionis deprecated. - The core steps are checkout, setup-node,
npm ci,npx playwright install --with-depsandnpx playwright test. - Upload the HTML report as an artifact, even when tests fail.
- Split large suites with
--shardand merge the blob reports into one report.
Tests that only run on your laptop protect nobody. The moment a teammate opens a pull request, you want the same browser tests to run automatically and block the merge if they fail. A GitHub Actions Playwright workflow does exactly that, and the basic version is about 25 lines of YAML.
This guide builds that workflow in stages: first the minimum that works, then pull request triggers, report uploads, sharding and the fixes for failures that only appear in CI. Everything follows the official Playwright CI introduction.
If you are new to workflows, read our GitHub Actions CI/CD guide first. It explains triggers, jobs and secrets from scratch.
The basic GitHub Actions Playwright workflow
When you run npm init playwright@latest, the installer offers to add this file for you. Save it as .github/workflows/playwright.yml:
name: Playwright Tests
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
jobs:
test:
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: lts/*
- name: Install dependencies
run: npm ci
- name: Install Playwright browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npx playwright test
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: playwright-report/
retention-days: 30
The action versions above match what the Playwright docs showed when I checked. Action versions move, so confirm the latest in each action’s repository, for example actions/upload-artifact.
Why the extra timeout: the docs example sets no job-level timeout-minutes and suggests globalTimeout in playwright.config.ts so reporters still produce a report when the run is cut short. A job timeout is still a useful safety net; just keep it above your global one.
What each step in the GitHub Actions Playwright file does
| Step | Purpose |
|---|---|
actions/checkout |
Copies your repository onto the runner |
actions/setup-node |
Installs Node.js (lts/* picks the current long-term release) |
npm ci |
Clean, repeatable install from the lock file |
playwright install --with-deps |
Downloads browsers plus the Linux libraries they need |
playwright test |
Runs the suite; a non-zero exit code fails the job |
upload-artifact |
Saves the HTML report so you can download it |
Do not use the archived microsoft/playwright-github-action from older tutorials. The Playwright team recommends the CLI approach shown here.
Make GitHub Actions Playwright run on every pull request
A GitHub Actions Playwright job only protects the branch if it is required, so wire it into branch protection.
The pull_request trigger already starts the job for each PR into main. To make it a real gate, open the repository settings, add a branch protection rule (or ruleset) for main and mark the test job as a required status check. Now a red run blocks the merge button.
Two refinements help on busy repositories. First, cancel outdated runs when someone pushes again:
concurrency:
group: pw-${{ github.ref }}
cancel-in-progress: true
Second, skip browser tests when only docs changed:
on:
pull_request:
paths-ignore:
- '**.md'
- 'docs/**'
A common setup is a small smoke subset on each PR and the full suite nightly. Our smoke testing vs sanity testing guide shows how to tag the quick tests, and the regression testing checklist helps decide what belongs in the nightly run.
Keep the report and traces
Good reports turn a GitHub Actions Playwright failure into a five-minute fix instead of a guessing game.
A failure message in a log is rarely enough. Save the HTML report (already done above) and turn on traces for retried tests in playwright.config.ts:
import { defineConfig } from '@playwright/test';
export default defineConfig({
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 2 : undefined,
reporter: [['html'], ['list']],
use: { trace: 'on-first-retry' },
});
Download the playwright-report artifact from the run page, open index.html and click a failed test to see the trace with screenshots, network calls and a step timeline. Retries are for diagnosis, not for hiding flakiness: any test that passes only on retry is reported as flaky, so fix it.
Speed up a slow suite with sharding
Sharding is the usual next step for a GitHub Actions Playwright setup once the suite grows.
When the suite passes ten minutes, split it across machines. Playwright supports this with --shard, described in the sharding documentation. Use a matrix job plus the blob reporter, then merge:
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4]
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with: { node-version: lts/* }
- run: npm ci
- run: npx playwright install --with-deps
- run: npx playwright test --shard=${{ matrix.shard }}/4 --reporter=blob
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: blob-report-${{ matrix.shard }}
path: blob-report
retention-days: 1
merge-reports:
if: ${{ !cancelled() }}
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with: { node-version: lts/* }
- run: npm ci
- uses: actions/download-artifact@v4
with:
path: all-blob-reports
pattern: blob-report-*
merge-multiple: true
- run: npx playwright merge-reports --reporter html ./all-blob-reports
- uses: actions/upload-artifact@v4
with:
name: html-report
path: playwright-report
Four shards roughly quarter the wall-clock time, at the cost of four times the runner minutes. Check the free-minute allowance on your GitHub plan before you shard everything.
When tests pass locally but fail in GitHub Actions
Almost every GitHub Actions Playwright failure that is absent locally comes from one of these causes.
- Different screen size or fonts. Visual snapshots made on macOS will not match Linux. Generate snapshots in the same environment as CI.
- Slower machines. Replace fixed sleeps with web-first assertions that wait automatically. See end to end testing best practices.
- Too many workers. Shared runners have limited CPU. Lower
workersif you see random timeouts. - Missing browser libraries. Always use
--with-depson a fresh runner. - Test data collisions. Parallel tests that share one user or record will interfere with each other.
Secrets and the base URL
Credentials need extra care in a GitHub Actions Playwright pipeline.
Never write passwords in the YAML. Store them under Settings, Secrets and variables, then pass them as environment variables. Keep the target address in config as well, so the same tests run against local and preview environments.
- name: Run Playwright tests
run: npx playwright test
env:
BASE_URL: ${{ vars.STAGING_URL }}
TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}
In playwright.config.ts read process.env.BASE_URL for use.baseURL. Secrets are not passed to workflows triggered from forked repositories, so tests that need them will not run on fork PRs by default.
Common mistakes
- Copying an old tutorial that uses the deprecated Playwright action.
- Skipping
npm ciand usingnpm install, which can change the lock file mid-run. - Uploading the report only on success, so failures leave nothing to inspect.
- Making the full suite a required check when it takes 40 minutes.
- Pinning no versions anywhere, then wondering why Tuesday’s run behaves differently.
Final thoughts
A reliable GitHub Actions Playwright setup is small: the basic workflow, a required status check, a report you can open and sharding only when the run gets slow. Start with the 25-line file, make it required on pull requests and improve it one problem at a time.
Frequently asked questions
How do I run a GitHub Actions Playwright workflow?
Add a workflow file that checks out the repo, sets up Node, runs npm ci, installs browsers with npx playwright install –with-deps and then runs npx playwright test.
How do I run Playwright tests on every pull request?
Use the pull_request trigger in the workflow, then mark the job as a required status check in branch protection so failing tests block the merge.
Should I still use microsoft/playwright-github-action?
No. It is deprecated, and the Playwright team recommends installing and running tests through the CLI as shown above.
How do I see the Playwright report from GitHub Actions?
Upload the playwright-report folder with actions/upload-artifact, then download it from the workflow run page and open index.html.
How can I make Playwright CI runs faster?
Shard the suite across a matrix with –shard, limit workers on small runners and run only a smoke subset on each pull request.
Keep learning
Need help with testing, WordPress or SEO?
We help teams ship better software and grow their sites. Tell us what you are working on and we will suggest a clear next step.