← Back to docs

Playwright Guide

Language: EN | EN | SV

Playwright Guide

This page is the focused guide for how to actually use Playwright in Tools.

If you want the broader feature overview, keep using the main page here:

When to use what

There are three main Playwright workflows in this project:

1. Stored admin scripts

Use this when you want to:

  • save one reusable browser script in Tools
  • keep the same sign-in/session through a persistent profile
  • run the same flow manually or on a schedule later

This is the right path for things like:

  • Facebook workflows
  • repeated verification/check flows
  • browser automation that should run from Tools admin or the scheduler

2. Recording / manual browser opening

Use this when you want to:

  • sign in manually first
  • record/codegen the steps before the final script is ready
  • prepare one persistent profile that a stored script will reuse later

This is normally done through browserbot.sh, except for the dedicated Socdemo playback path which now uses play/socdemo-play.sh as its direct runner.

3. Project E2E specs

Use this when you want to:

  • run the test suite under tests/e2e
  • verify that the Tools UI still works
  • save reports, video, screenshots, and traces for test runs

This belongs to the dedicated Playwright E2E admin page and the normal Playwright test structure in the project root.

Quick start: most common path

If you just want to get started quickly:

  1. open /admin/browser-automation/create
  2. create a script with a simple key such as example-home
  3. choose chrome or chromium
  4. set a start_url
  5. paste a simple script
  6. click Run now
  7. inspect the output and screenshot

Example script:

await page.goto(input.url || 'https://example.com', { waitUntil: 'domcontentloaded' });
helpers.log('Loaded page', await page.title());
await helpers.screenshot('example-home.png');
return {
  title: await page.title(),
  url: page.url(),
};

How to use Playwright from the admin UI

Admin pages:

  • /admin/browser-automation
  • /admin/browser-automation/playwright

Create one stored script

On the create/edit page, fill in:

  • Key – stable script identifier such as facebook-post
  • Name – readable admin label
  • Browserchrome, chromium, or edge
  • Start URL – the first page to open
  • Profile directory – persistent profile name if you want to reuse sign-in/session state
  • Timeout – max runtime
  • Input JSON – optional values your script reads through input
  • Script source – the actual Playwright code

When to use profile_directory

Set a persistent profile when you want to:

  • keep sign-in between runs
  • reuse cookies/session state
  • prepare login manually once and then run the script again and again

If you leave the field blank, Tools normally uses the script key itself as the default saved profile name.

When to use headed mode

Use headed mode when you:

  • sign in for the first time
  • expect a challenge/captcha/2FA step
  • want to see exactly what the browser is doing

Headless mode is better for stable already-prepared runs.

How to use browserbot.sh

The repo-root wrapper is the fastest way to use the same Playwright setup from shell.

List stored scripts

bash browserbot.sh --list

Run one stored script

bash browserbot.sh --key facebook-post
bash browserbot.sh --name "Facebook post"

Run with one explicit profile

bash browserbot.sh --key facebook-post --profile facebook-admin

Run in headed mode

bash browserbot.sh --key facebook-post --headed

Force one clean temporary profile

bash browserbot.sh --key facebook-post --fresh-profile

That is the right choice when you do not want to reuse saved session state.

How to record steps first

If you want to build the flow before saving the final script in the database, record/codegen first.

Record mode

bash browserbot.sh --record --key facebook-post --start-url https://www.facebook.com/

This is useful when you want to:

  • sign in manually
  • click through the workflow once
  • use the recording as the base for the final script

Open mode

bash browserbot.sh --open --browser chrome --profile facebook-admin --start-url https://www.facebook.com/

This opens the browser without playback and without forcing the codegen flow.

It is the right mode when you just want to:

  • sign in
  • verify that a persistent profile really works
  • install or verify something manually in the browser

How to reuse an already signed-in profile

If you already have one good base profile, you can clone it into a new profile instead of repeating the whole login flow.

bash browserbot.sh --clone-profile --copy-profile-from default --profile facebook-page-bot
bash browserbot.sh --open --profile facebook-page-bot --start-url https://www.facebook.com/

This is useful when:

  • default already contains expensive setup such as login, cookies, or extension configuration
  • you want several variants for different accounts or pages
  • each variant still needs its own final account switch or page-specific session state

How stored scripts access Playwright objects

Your stored script runs inside an async function and receives:

  • page
  • context
  • browser
  • playwright
  • helpers
  • input

Common helpers

  • helpers.log(...parts)
  • await helpers.screenshot('shot.png')
  • await helpers.saveText('note.txt', '...')
  • await helpers.saveJson('state.json', value)
  • helpers.setOutput(value)
  • await helpers.delay(ms)
  • helpers.getEnv('NAME')

Minimal template

await page.goto(input.url || 'https://example.com', { waitUntil: 'domcontentloaded' });
helpers.log('Title', await page.title());
await helpers.screenshot('page.png');
helpers.setOutput({
  title: await page.title(),
  url: page.url(),
});
return { ok: true };

How to run the project's E2E specs

The project's Playwright tests use:

  • config: playwright.config.ts
  • specs: tests/e2e
  • profiles: storage/playwright/profiles/<name>
  • reports/artifacts: storage/playwright/

Important difference from stored admin scripts

  • stored admin scripts are browser automation for real work flows
  • E2E specs are test cases for the project UI and behavior

When to use the admin Playwright E2E page

Open:

  • /admin/browser-automation/playwright

From there you can:

  1. read one spec file
  2. run the whole test suite
  3. run one selected file
  4. set base URL
  5. choose whether the webserver should be skipped
  6. choose a persistent profile before the run
  7. inspect stored reports and artifacts

How to run persistent E2E/codegen locally

Project alias:

npm run test:e2e:codegen

Persistent helper:

bash bin/playwright-record-persistent.sh

Against an external environment:

PLAYWRIGHT_SKIP_WEBSERVER=true PLAYWRIGHT_BASE_URL=https://tools.tornevall.net bash bin/playwright-record-persistent.sh

First-time setup if Playwright is not installed yet

For the browser automation runner

cd automation/playwright
npm install

For the Laravel-root / E2E setup and the current Browserbot/Socdemo host stack

sudo bash bin/install-browserbot-stack.sh

That installer is now the canonical host-side setup entrypoint for this stack. In its current form it installs Node from NodeSource, filtered Linux browser dependencies, Xvfb, the Playwright package, and one project-local Playwright Chromium cache under storage/app/browser-automation/playwright-browsers.

Important details for the current runtime split:

  • browserbot.sh is still the general shell wrapper for stored scripts, --open, --record, profile cloning, and profile-seed export/import.
  • play/socdemo-play.sh is now the special direct runner for the SocialGPT Socdemo playback flow.
  • The Socdemo runner is intentionally Chromium-first, rejects snap-style /usr/bin/chromium-browser, and only uses Chrome when you explicitly request it.
  • SOCDEMO_DISPLAY_MODE=headless is intentionally blocked for that extension-backed Socdemo playback path; the supported server-side model is still a headed browser inside Xvfb.

If Node/npm/npx is broken or missing

sudo bash bin/install-browserbot-stack.sh

Practical recommendations

Good working pattern

  • start with a very small script
  • verify screenshot/output first
  • move to the real target site only after the base flow works
  • use a persistent profile for sign-in-heavy sites
  • use headed mode during the first login/session setup
  • keep input simple and readable

When something feels wrong

Start by checking:

  • does the script open the correct start_url
  • are you using the right browser
  • are you using the right profile_directory
  • are you accidentally running --fresh-profile when you really want saved session reuse
  • does the first run need headed mode
  • are the expected artifacts actually being written

Recommended first real workflow

If you want one slightly more realistic flow without starting too big:

  1. open a page with --open or --record
  2. sign in manually in a persistent profile
  3. keep that profile name
  4. run a stored script against the same profile
  5. let the script only verify title, URL, or one known element
  6. only after that, add clicks, form steps, or publishing actions

Related guides