This document explains Playwright's automated process for tracking and backporting client-side API changes from the Node.js implementation to its language ports (Python, Java, and .NET). The synchronization mechanism ensures that all language implementations maintain feature parity by automatically creating tracking issues when client-facing APIs are modified.
For information about the overall CI/CD pipeline and release processes, see CI/CD and Release Management. For details about the protocol communication that enables cross-language compatibility, see Protocol Communication Architecture.
Playwright is implemented in multiple programming languages, with the Node.js/TypeScript version serving as the canonical implementation. The following language ports mirror the Node.js API surface:
| Repository | Language | Maintained By |
|---|---|---|
microsoft/playwright | Node.js/TypeScript | Core team |
microsoft/playwright-python | Python | Microsoft team |
microsoft/playwright-java | Java | Microsoft team |
microsoft/playwright-dotnet | .NET/C# | Microsoft team |
All language ports share the same underlying browser automation protocol defined in protocol.yml. The client-side APIs—what end users interact with—must remain consistent across all implementations to provide a uniform developer experience.
Playwright uses a GitHub Actions workflow to automatically detect changes to client-side code and create tracking issues in the language port repositories.
The workflow triggers only on pushes to main (not pull requests) and only when any of the following path globs match a changed file .github/workflows/pr_check_client_side_changes.yml6-11:
| Path | What it covers |
|---|---|
docs/src/api/**/* | Public API documentation |
packages/playwright-core/src/client/**/* | Client-layer class implementations |
packages/playwright-core/src/utils/isomorphic/**/* | Shared cross-environment utilities |
packages/playwright/src/matchers/matchers.ts | expect assertion matchers |
packages/protocol/src/protocol.yml | Wire protocol definition |
These paths represent the public contract between Playwright and its users:
Browser, Page, Locator, BrowserContext that users directly interact withexpect assertion API for testsSources: .github/workflows/pr_check_client_side_changes.yml6-11
The diagram below maps the workflow steps to the actual GitHub API calls and script logic in .github/workflows/pr_check_client_side_changes.yml
Diagram: pr_check_client_side_changes.yml — Step-by-Step Execution
Sources: .github/workflows/pr_check_client_side_changes.yml1-75
The workflow uses actions/create-github-app-token@v2 to obtain a token scoped to all four repositories: playwright, playwright-python, playwright-java, and playwright-dotnet .github/workflows/pr_check_client_side_changes.yml19-28 This cross-repository scope is required because the workflow creates and updates issues outside of microsoft/playwright. The app credentials are stored as vars.PLAYWRIGHT_APP_ID and secrets.PLAYWRIGHT_PRIVATE_KEY on the repository.
Sources: .github/workflows/pr_check_client_side_changes.yml19-28
Issues are created with a version-specific title that allows for easy identification and prevents duplicates:
[Ports]: Backport client side changes for {major}.{minor}
For example: [Ports]: Backport client side changes for 1.40
The version is extracted from the root package.json .github/workflows/pr_check_client_side_changes.yml34 using a \d+\.\d+ regex, capturing only the major and minor components (e.g., 1.40 from 1.40.1). This groups all patch-level changes within a release cycle under a single issue per repository.
Sources: .github/workflows/pr_check_client_side_changes.yml34
The script calls github.rest.git.getCommit() to retrieve the full commit message, then uses regex /#(\d+)/ to detect whether the commit was merged via a pull request .github/workflows/pr_check_client_side_changes.yml35-44:
| Condition | Formatted reference |
|---|---|
Commit message contains #NNNN | https://github.com/microsoft/playwright/pull/{NNNN} |
| No PR number found | https://github.com/microsoft/playwright/commit/{SHA} ({commit message header}) |
This ensures maintainers can navigate directly to the pull request or commit that introduced the change.
Sources: .github/workflows/pr_check_client_side_changes.yml35-44
Issues maintain a checklist of commits that need backporting:
The script implements upsert logic per repository .github/workflows/pr_check_client_side_changes.yml47-73:
github.rest.search.issuesAndPullRequests() with a query of is:issue is:open repo:microsoft/{repo} in:title "{title}"total_count > 0, record the existing issue number and bodygithub.rest.issues.create() with body: 'Please backport client side changes: \n'- [ ] {formattedCommit} to the existing body and call github.rest.issues.update()Maintainers check off items as - [x] once the backport is complete. The issue is typically closed when all items are checked.
Sources: .github/workflows/pr_check_client_side_changes.yml47-73
Diagram: Monitored source files → pr_check_client_side_changes.yml → language port issues
Sources: .github/workflows/pr_check_client_side_changes.yml1-75
The entire synchronization mechanism lives in a single file: .github/workflows/pr_check_client_side_changes.yml
| YAML field | Value |
|---|---|
| Trigger event | on.push to main with paths filter |
| Job name | check |
| Runner | ubuntu-24.04 |
| Guard condition | github.repository == 'microsoft/playwright' (prevents forks from triggering) |
Steps in order .github/workflows/pr_check_client_side_changes.yml17-74:
actions/checkout@v6 — clone the repository so package.json is accessibleactions/create-github-app-token@v2 — acquire cross-repository tokenactions/github-script@v8 — inline Node.js script that performs all issue managementSources: .github/workflows/pr_check_client_side_changes.yml1-75
The core synchronization logic is the github-script step .github/workflows/pr_check_client_side_changes.yml33-74:
| GitHub API call | Purpose |
|---|---|
github.rest.git.getCommit() | Retrieve full commit message to extract PR number |
github.rest.search.issuesAndPullRequests() | Find open tracking issue by title in each port repo |
github.rest.issues.create() | Create new tracking issue when none exists |
github.rest.issues.update() | Append new commit entry to the issue checklist |
Sources: .github/workflows/pr_check_client_side_changes.yml33-74
While the workflow automates detection and tracking, the actual backporting is performed manually by language port maintainers:
This semi-automated approach balances automation (tracking what needs to be done) with human judgment (how to implement it in each language).
While pr_check_client_side_changes.yml handles ongoing synchronization, other workflows support the release process:
Sources: .github/workflows/roll_browser_into_playwright.yml .github/workflows/publish_release_docker.yml .github/workflows/tests_primary.yml .github/workflows/tests_secondary.yml
Playwright's cross-language synchronization system ensures API consistency across four language implementations through:
This lightweight automation reduces the risk of language ports diverging from the canonical Node.js implementation while allowing maintainers the flexibility to adapt implementations to each language's idioms.
Sources: .github/workflows/pr_check_client_side_changes.yml1-75
Refresh this wiki
This wiki was recently refreshed. Please wait 2 days to refresh again.