Migrate Playwright browser journeys to Monito

Move brittle Playwright browser journeys to Monito with spec conversions, login setup and a CI cutover. Keep unit, component and API tests in code.

Playwright is a code-first browser automation framework with a test runner, recorder and agent tooling. Source · checked 2026-10-23.

Use this playbook when you want to stop maintaining the full-browser specs for selected user journeys. Move signup, login, checkout, onboarding or settings persistence when their expected behavior is clear. Keep unit, component, API and fast isolated tests in Playwright or Vitest. A migration of browser journeys does not replace that coverage.

Read each spec before rewriting it. Separate account setup and fixture preparation from actions a user takes, then copy every required outcome into the scenario. Our team uses illustrative specs below, not files recovered from a customer. Replace their routes, labels and test data with your own. The linked benchmark runs show comparable behavior, not execution of these specs.

What the source documentation says

Write test code or record browser actions to generate it. Playwright Test supplies assertions, auto-waiting and tracing. Source · checked 2026-10-23.

Test code and agent-generated plans live in your repository. Source · checked 2026-10-23.

Your team owns the test files. The healer agent proposes patches and reruns tests; it may skip a test when it believes the functionality is broken. Source · checked 2026-10-23.

What translates and what changes

Playwright concepts mapped to Monito
 PlaywrightMonito
Test file or specTest code and agent-generated plans live in your repository. Source · checked 2026-10-23.Turn each selected user journey into a named scenario. Keep its starting path, actions and expected outcome together. There is no Playwright spec importer or code export.
LocatorsIn the examples, getByRole and getByLabel identify the controls to operate. Source · checked 2026-10-23.Describe the visible control and the action in plain English. Keep details that distinguish similar controls, such as the item name or the settings section.
AssertionsThe expect calls below state the visible result and the value that must persist. Source · checked 2026-10-23.Put each required outcome in What to test. Preserve arithmetic and reload checks. Reaching a page or seeing a toast does not prove the saved state.
Fixtures and storageStateInventory your fixtures and storageState files, including the account and state each journey assumes.Store email, password and any TOTP setup key in an environment login. Protected-preview request headers are also stored on the environment. There is no import of fixture files or storageState.

Select the login role in the scenario. Recreate non-login data setup separately; a saved login does not execute your fixture code or import a storageState file.

Base URLRecord the baseURL used by the spec's relative paths.Create the environment with your app's base URL and set the scenario's starting path. Use --base-url on project run for a deployed preview. A preview URL does not authorize sending saved logins to a new origin; use an approved origin for an authenticated journey.
Retries and flake handlingInventory the retries setting and the tests your reports mark flaky.The agent chooses browser actions during each run. It can retry an inconclusive action within bounded limits and recover from transient model-provider errors while time remains. A measured mismatch of required behavior is a failure to report, not a reason to retry until green. Missing access or evidence remains an error. Read the report before rerunning; do not weaken the expected outcome to hide a failure.

Record the reason for each retry in the old workflow. An infrastructure interruption and a product mismatch need different responses.

CI jobRun in your CI provider. The setup can add a GitHub Actions workflow for pushes and pull requests. Source · checked 2026-10-23.A deploy webhook queues runs after deployment. For a blocking GitHub check, use the documented CLI project run workflow. Both integrations require Pro or Team.
Traces, videos and screenshotsKeep the trace, video or screenshot artifacts your existing CI job retains for these specs. Source · checked 2026-10-23.Read the run report's measured checks, screenshots, network and console evidence. Recording is off for signed-in runs; masked screenshots are captured instead. Keep old traces, videos and screenshots separately; a new scenario starts its own run history.
Parallel shardingRecord the workers and shards used by the selected specs in your CI configuration. Source · checked 2026-10-23.Suite members launch side by side, with up to 5 launches in progress at once. This limits launch work, not the number of already running browsers. You do not configure CI shards. Give each journey independent test data so concurrent runs cannot overwrite the same cart or profile.

Set up the scenario and its login

Create a project and an environment with your app's base URL. Give the scenario a Name and a Where value, either a starting path or a full URL. In What to test, put the instructions and expected outcome together. The examples separate those two parts for review; they are not an import file or separate required form fields. Select the environment you intend to run against. Replace the illustrative paths, account names and fixture data with values your application actually has.

Add the email and password as an environment login, then select its role in the scenario. For authenticator login, open Advanced and save the setup key; Monito generates the TOTP code during sign-in. Login secrets stay encrypted in server storage. Protected-preview request headers also belong on the environment, with encrypted values tied to its origin. These settings do not implement general prompt-variable substitution. A disposable email login needs your own Resend receiving domain, API key, expected sender and subject prefix. It reads a code or magic link for a new disposable address, not an existing fixed-email account.

Writing a scenario

Three converted browser journeys

These examples show how to rewrite intent. Each report link is a run of a comparable journey from our benchmark. It is not a run of your check or a validation of these illustrative configurations.

Sign in and reach the account dashboard

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

test.use({ storageState: { cookies: [], origins: [] } });

test('account dashboard access', async ({ page }) => {
  const email = process.env.QA_EMAIL ?? '';
  const password = process.env.QA_PASSWORD ?? '';
  expect(email).not.toBe('');
  expect(password).not.toBe('');

  await page.goto('/login');
  await page.getByLabel('Email', { exact: true }).fill(email);
  await page.getByLabel('Password', { exact: true }).fill(password);
  await page.getByRole('button', { name: 'Sign in', exact: true }).click();

  await expect(page).toHaveURL(/\/dashboard$/);
  await expect(page.getByRole('button', { name: 'Account menu' })).toBeVisible();
  await expect(page.getByRole('heading', { name: 'Recent activity' })).toBeVisible();
  await expect(page.getByTestId('login-error')).toBeHidden();
});

Illustrative Playwright TypeScript spec using @playwright/test. Configure baseURL and supply QA_EMAIL and QA_PASSWORD through your test environment. The example account uses password login without an authenticator challenge. Source · checked 2026-10-23.

After · Monito scenario
Name: Account dashboard access
Starting path: /login
Environment: Staging

Instructions: Sign in with the saved QA login and open the account dashboard.

Expected: The account menu and recent activity are visible. A sign-in error or unresolved login challenge does not pass.

Save the account as an environment login instead of pasting credentials into What to test. When the sign-in challenge itself is under test, select Start logged out under Options, or leave Reuse login sessions off on the login. Session reuse is off by default. If your actual flow uses an authenticator, save its setup key and include that challenge in the scenario. The benchmark below did not complete sign-in.

The run ended with an Error status, which our benchmark scores as cannot verify: the security check failed and no credentials were supplied. It illustrates an unresolved login prerequisite, not a successful sign-in or proof that your authentication will work.

Check that the checkout total includes shipping

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

test.use({ storageState: '.auth/checkout.json' });

test('checkout review includes delivery', async ({ page }) => {
  await page.goto('/catalog');
  await expect(page.getByTestId('cart-empty')).toBeVisible();
  const mug = page.getByRole('article', { name: 'Test mug' });
  await mug.getByRole('button', { name: 'Add to cart' }).click();
  await page.getByRole('link', { name: 'Checkout', exact: true }).click();
  await page.getByLabel('Shipping address').selectOption('staging');
  await page.getByRole('button', { name: 'Review order' }).click();

  const subtotal = page.getByTestId('subtotal');
  const shipping = page.getByTestId('shipping');
  const total = page.getByTestId('total');
  await expect(page.getByTestId('order-items')).toContainText('Test mug');
  await expect(subtotal).toBeVisible();
  await expect(shipping).toBeVisible();
  await expect(total).toBeVisible();
  await expect(subtotal).toHaveAttribute('data-cents', /^\d+$/);
  await expect(shipping).toHaveAttribute('data-cents', /^\d+$/);
  const itemCents = Number(await subtotal.getAttribute('data-cents'));
  const shippingCents = Number(await shipping.getAttribute('data-cents'));
  await expect(total).toHaveAttribute('data-cents', String(itemCents + shippingCents));
  // Stop at review. Do not submit the order.
});

Illustrative Playwright TypeScript spec. The app exposes monetary values as integer data-cents attributes. Supply baseURL and a prepared checkout account with an empty cart and a saved staging shipping address in .auth/checkout.json. Source · checked 2026-10-23.

After · Monito scenario
Name: Checkout review includes delivery
Starting path: /catalog
Environment: Staging

Instructions: Use the checkout account's saved login, start with an empty cart, add the test mug and choose its saved staging shipping address. Open checkout review without submitting the order.

Expected: The review contains the item and shipping charge, and the displayed total equals their sum.

Keep the empty-cart prerequisite and stop-at-review instruction. The spec reads app-specific amount attributes; the scenario asks Monito to verify the displayed amounts. Confirm that those displayed values represent the same business requirement before retiring the spec. Prepare or reset the cart outside the scenario when needed, and use a checkout account separate from other concurrent journeys.

The benchmark includes a working checkout and a cart whose total omits shipping. These reports exercise checkout behavior and arithmetic. They do not execute the illustrative example above.

Save a profile change and verify persistence

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

test.use({ storageState: '.auth/profile.json' });

test('display name survives reload', async ({ page }) => {
  await page.goto('/settings/profile');
  const name = page.getByLabel('Display name');
  await expect(name).not.toHaveValue('Migration sample');
  await name.fill('Migration sample');
  await page.getByRole('button', { name: 'Save', exact: true }).click();

  await expect(page.getByRole('status')).toHaveText('Profile saved');
  await expect(page.getByTestId('member-list')).toContainText('Migration sample');

  await page.reload();
  await expect(name).toHaveValue('Migration sample');
  await expect(page.getByTestId('member-list')).toContainText('Migration sample');
});

Illustrative Playwright TypeScript spec. Configure baseURL and prepare .auth/profile.json for a disposable profile account whose display name starts with a different value. Reset that fixture before each run. Source · checked 2026-10-23.

After · Monito scenario
Name: Display name survives reload
Starting path: /settings/profile
Environment: Staging

Instructions: Use the disposable profile account's saved login, starting with a different display name. Change it to Migration sample, save, inspect the member list and reload.

Expected: The success notice appears, the member list updates and Migration sample remains the display name after reload.

Keep the reload assertion even when the save notice looks convincing. A prepared storageState file provides access, not a fresh display name. Reset the account before subsequent runs so the action remains a real mutation. Recreate that fixture preparation in your own setup; it does not become part of the environment login merely because both refer to the same account.

The benchmark profile saves show both a persistent update and an update lost after reload. The latter still shows a success toast. Read the reload evidence before treating the visible confirmation as success.

Ask your coding agent to recreate the checks

You can ask your coding agent to recreate the checks through the hosted MCP server. Give it the public target URL, environment and non-secret intent. The check tool runs a URL and expectation. After reviewing the result, save_check saves that check under a name without starting another run. Use run_scenario for the saved scenario afterward. A check or run_scenario call spends credits. These tools do not import the source vendor's project.

Connect the hosted MCP server and provide the journey you reviewed above.

Agent prompt
Recreate this browser journey in Monito using the hosted MCP server. Use the intended project's environment and saved login. Call check with the public URL and the instructions plus expected outcome. Read the report and identify any missing prerequisites. If the scenario is correct, call save_check with its checkId and name. Use run_scenario with the saved scenarioId for subsequent runs. Keep credentials out of the expectation.

Cut over the trigger and schedule

  1. Inventory the journeys selected for migration, their assertions, fixtures and artifact retention. Keep unit, component, API and fast isolated tests in Playwright or Vitest. Keep any browser specs that still need explicit assertion code or multiple browser engines in their current CI jobs.
  2. In your Monito project, create a suite for the moved journeys. Set up the intended environment base URL and saved logins. Prepare independent accounts and data for each scenario. Put the required outcome in What to test, then run it manually and read the report against the old assertions.
  3. Run the old specs and new scenarios against the same deployed build during validation. Investigate disagreements, including cannot-verify results. Check that a known broken outcome is detected before removing its old spec from the CI selection.
  4. Replace the Playwright e2e job for the moved journeys with the blocking project run step below, after successful deployment. Use the generated GitHub Actions authentication setup under Automations. PROJECT_ID must identify the project containing those migrated scenarios. Set SUITE_NAME to the suite containing the migrated journeys. Keep the rest of the suite running in its existing jobs, including fixture setup still needed by either runner. Source · checked 2026-10-23.
  5. Remove only the migrated specs from the old job's selection after the new trigger has produced reports you reviewed. Preserve old reports and keep ownership of the retained jobs explicit. Add recurring coverage using the schedule presets below if those journeys also need checks between deployments.

For asynchronous checks, the deploy webhook returns 202 when runs are queued. That response does not mean they passed. Results appear in the dashboard; this request does not block the pipeline for a verdict. Deploy webhooks require Pro or Team.

For a blocking pipeline, configure GitHub Actions under Automations and use its generated authentication setup before adding this run step. Set GITHUB_TOKEN and grant checks: write. PROJECT_ID identifies the Monito project; PREVIEW_URL is the deployed target. The CLI waits for results and exits with code 1 if a scenario fails or errors. --github-check publishes the Monito GitHub check; the check is neutral only when every non-passing result is an error Monito caused; other errors and failures mark it failed. The CLI exits 1 either way. The example pins the published CLI 4.8.1. A preview URL does not authorize sending saved logins to a new origin; use an approved origin for an authenticated journey.

Blocking GitHub check · shell
npx -y @monitodev/cli@4.8.1 project run "$PROJECT_ID" \
  --base-url "$PREVIEW_URL" --wait --github-check --suite "$SUITE_NAME"

Follow the GitHub Actions setup for authentication and permissions. The project run reference documents the command. GitHub Actions requires Pro or Team.

Without --suite, the command runs every scenario in the project, or the suite selected on the GitHub Actions automation. Pass --suite <name> or select a suite on the automation to limit it to the migrated journeys. Do not also fire a deploy webhook for the same deployment unless you intend duplicate runs. An asynchronous webhook is an alternative when the pipeline does not need to wait for a verdict.

Schedule allowance, regions and alerts

Schedule presets are hourly, every 6 hours, daily and weekly, in UTC. Runs execute in us-east; there is no region selector or multi-region execution. Failed automated runs can send email when run-alert emails are enabled. Email is available on Free, Pro and Team. Slack notifications require Team. Check the chosen environment, suite and notification preferences before relying on the schedule.

50 free test credits every month. Your balance refills to 50 on the 1st of each month (UTC), counting credits reserved by running tests. Unused credits are not added again; purchased credits are kept. Your signup credits count as the first month. Free includes one daily schedule. Verify your email to receive monthly refills. Any schedule other than that one daily schedule, a deploy webhook, GitHub Actions, and a public status page need Pro.

Check pricing before enabling the recurring workload. A slower schedule leaves a longer gap between checks; it changes the coverage you are buying.

When staying on Playwright fits better

Choose Playwright when you want test code under review in the repository, with agent-generated plans and repairs that your team can inspect. Source · checked 2026-10-23.

Choose Playwright when you need Chromium, Firefox and WebKit coverage or want to shard tests across multiple CI machines. Monito does not provide multiple browser engines. Source · checked 2026-10-23.

Choose Playwright when the test needs to exercise a component in isolation rather than a complete deployed browser journey. Source · checked 2026-10-23.

What to keep outside this migration

Keep unit, component, API and fast isolated tests in Playwright or Vitest. Move only the brittle full-browser user journeys whose actions and expected results you can review, such as signup, login, checkout, onboarding and settings persistence.

Monito runs desktop Chromium. It does not run component tests, provide multiple browser engines or export executable test code. Keep Playwright where those requirements determine the test's value.

Keep executable fixture preparation, request mocks and assertions about internal state in code when they are part of the requirement. A scenario checks the browser outcome; it does not translate every line of a spec or prove that the entire old suite has moved.

Validate your first scenario

Run the scenario against your own app and inspect the result before switching its trigger. Our team publishes the benchmark method and its limits on the reliability page. The reports above show comparable behavior; your application still needs its own validation.