playwright-recorder-server
v0.3.0
Published
Standalone Playwright recorder server — launches a browser, streams a CDP screencast and recorded events over WebSocket, and generates Playwright scripts.
Maintainers
Readme
playwright-recorder-server
Recorder server for generating Playwright scripts from manual browser sessions. It launches a real Playwright Chromium browser that you interact with, records your clicks/fills/selections, streams a live screencast + events to a web page, and saves the generated script.
Run this command first, then record from your browser:
npm i -g playwright-recorder-server
playwright-recorderThe Playwright Chromium browser is installed automatically during npm i -g.
Then open http://localhost:3000/launch and start recording.
Usage
playwright-recorder [--port <port>] [--dir <recordings dir>] [--use-system-browser]
[--host <ip>] [--verify-key <pem>] [--token-secret <secret>]
[--allowed-origins <origins>]| Option | Default | Description |
|-----------|----------------------------------------|--------------------------------------|
| --port | 3000 | HTTP port the server listens on |
| --dir | ~/.playwright-recorder/recordings | Where .spec.ts / .events.json are saved |
| --host | 127.0.0.1 | Address the server binds to (localhost only by default) |
| --verify-key | (env RECORDER_JWT_PUBLIC_KEY) | PEM file with the public key used to verify RS256 recorder tickets. Enables secure mode. |
| --token-secret | (env RECORDER_JWT_SECRET) | Shared HS256 secret for verifying recorder tickets. Enables secure mode. |
| --allowed-origins | (env RECORDER_ALLOWED_ORIGINS) | Comma-separated exact origins allowed to connect in secure mode. localhost is always allowed. |
Secure mode (authentication)
By default the recorder runs in open mode — useful for the standalone
/launch demo. When you need to protect the recorder (e.g. a production
portal connecting to ws://localhost:<port>/ws on the user's machine), start
it with a verification key:
playwright-recorder --port 3002 --verify-key /path/to/cogniqa-public.pem
# or
set RECORDER_JWT_PUBLIC_KEY=<public key pem>
playwright-recorder --port 3002In secure mode every WebSocket connection and every write API
(/api/recordings, /api/ingest, /api/sessions/:id/drive) requires a valid
recorder ticket, and connections from disallowed origins are rejected.
Ticket contract
A ticket is a short-lived JWT signed by your portal:
{
"sub": "<userId>",
"fid": "<flowId>",
"aud": "playwright-recorder",
"jti": "<unique id>",
"iat": 0,
"exp": 0 // short expiry, e.g. 120s
}- RS256: sign with your private key; the recorder verifies with the public
key (
--verify-key/RECORDER_JWT_PUBLIC_KEY). - HS256: sign with a shared secret (
--token-secret/RECORDER_JWT_SECRET). - The ticket must carry
aud: "playwright-recorder", otherwise it is rejected. - The browser opens the socket with the ticket as a query parameter:
const ws = new WebSocket(`ws://localhost:3002/ws?ticket=${encodeURIComponent(ticket)}`);Security notes
- The server binds to
127.0.0.1by default (not all interfaces). - In secure mode a connection without a ticket, with an invalid signature, with a wrong audience, or from an origin not in the allowlist is rejected before the WebSocket handshake completes.
- Tickets are short-lived; a leaked ticket becomes useless in minutes and is scoped to the recorder (it is invalid against your API, which uses a different audience/key).
GET /api/healthis public so the portal can detect the recorder without a ticket.
How it works
- Open
http://localhost:3000/launch, enter a Target URL and press Record. The page opens a WebSocket tows://localhost:3000/wsand sends{ type: 'start', url, sessionId }. - The server launches a Playwright Chromium window, navigates to the URL, injects a recorder, and starts a CDP screencast (JPEG frames streamed to the page over the same WebSocket).
- Recorded clicks/fills/selects are captured, stored on the server, and broadcast live to the page's Recorded events panel.
- Generate Script sends
{ type: 'generate' }and the server returns the Playwright script built from all events so far (recording continues). - Stop sends
{ type: 'stop' }, the server closes the browser, and the page POSTs the events to/api/recordings. The server saves:recordings/<sessionId>-<timestamp>.spec.ts+.events.json.
localhost:3000/launch ──WS──► server ──launches──► Playwright browser
▲ screencast frames + events (you interact here)
│ script + saved filesNo Chrome extension is required — everything happens in the web page.
Development
npm install
npm run verify # unit test for the script generator
npm run smoke # end-to-end: WS start -> drive -> generate -> stop -> save (open mode)
npm run smoke:auth # secure-mode tests: ticket rejection + acceptancePublish
npm run prepublishOnly # runs verify + smoke
npm publish --access public