How to Record a Website with a Headless Browser
Choose whether you need reusable test code, a browser video, or a debugging trace. Then capture it with Playwright and run the workflow headlessly.
To record a website with a headless browser, first choose what “record” means: reusable test code, a video of browser activity, or a trace for debugging. These are different outputs. Playwright Codegen interactively records actions in a visible browser and Inspector; it is not a headless recorder. You can run the generated or hand-written Playwright workflow headlessly afterward and configure it to save video or a trace.
This guide uses Playwright because its official documentation covers all three workflows. You will need Node.js and a project directory. Install Playwright Test with npm init playwright@latest, then follow the setup prompts. The examples assume the generated project includes Playwright Test.
1. Pick the recording you need
| Goal | Output | Best starting point |
|---|---|---|
| Turn interactions into reusable automation | Test code | Playwright Codegen, followed by review and editing |
| Show what a user saw | Video file | Playwright Test video recording or a manually configured browser context |
| Find why a run failed | Trace with page snapshots and execution evidence | Playwright tracing or Playwright Test trace settings |
A generated test, a video, and a trace answer different questions. Decide which artifact you need before configuring the browser.
2. Generate test code from an interactive recording
Run Codegen with the page you want to exercise:
npx playwright codegen https://demo.playwright.dev/todomvc
Codegen opens a browser window and Playwright Inspector. Interact with the site—click controls, fill fields, and navigate—then copy or save the generated code from the Inspector. The generator recommends locators based on roles, text, and test IDs, and can generate assertions for visibility, text, and values. Treat the result as a starting point: check that locators identify the intended elements, add assertions for the actual outcome, and remove incidental actions.
The workflow is interactive and headed. For a custom pause-and-inspect workflow, Playwright documents page.pause() and says to run headed. Once you have the test, run it headlessly with Playwright Test’s normal runner:
npx playwright test
Playwright Test runs headless by default unless configured otherwise. To see the browser while debugging, use npx playwright test --headed.
Configure Codegen input
Codegen supports options for setting a viewport, device emulation, color scheme, geolocation, language, timezone, and authenticated state. Use the installed CLI’s help to see the exact option spellings supported by your installed version:
npx playwright codegen --help
These settings matter when the site changes behavior based on viewport, locale, login state, or device characteristics. If the generated test depends on a signed-in session, use the documented authenticated-state workflow and keep saved state files out of source control when they contain credentials or session cookies.
3. Record a video of a headless run
For Playwright Test, set the video option in the project configuration. For example, update playwright.config.ts:
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
headless: true,
video: 'retain-on-failure',
},
});
Playwright Test supports off, on, retain-on-failure, and on-first-retry. Choose on to retain video for every test, retain-on-failure to keep videos for failed tests, or on-first-retry to record on the first retry. Videos are saved when the browser context closes, so allow the test runner to finish closing contexts before collecting artifacts.
Record a video with a manually created context
Use this complete Node.js example when you need direct control over context creation and output location. It records a headless browser session to WebM and waits for the context to close so the video is finalized:
import { chromium } from 'playwright';
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({
recordVideo: { dir: 'artifacts/videos' },
});
const page = await context.newPage();
try {
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
await page.getByRole('link', { name: 'More information' }).click();
await page.waitForLoadState('domcontentloaded');
} finally {
await context.close(); // Finalizes the video file.
await browser.close();
}
Create the output directory before running the script if your environment or framework does not create it. Keep the context open until all actions are complete. Closing only the browser page is not a substitute for closing the recording context.
Playwright also documents a CLI workflow for recording WebM sessions with start and stop commands, plus optional sizing and chapter markers. Consult the installed CLI’s help and current official documentation for the command syntax supported by your version. Puppeteer’s Page.record() page is in its next-version documentation and labels the API experimental; verify that it exists in your installed release before depending on it.
4. Capture a trace to debug a run
A video shows browser activity, but a trace is usually more useful when you need to investigate a failure. Playwright traces can include DOM snapshots, screenshots, network activity, and console logs at steps. Open the resulting trace with Trace Viewer to inspect what happened around an action.
For Playwright Test, enable tracing through the test configuration. A common choice is to collect a trace when a test is retried:
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
trace: 'on-first-retry',
},
});
Playwright Test trace modes include off, on, on-first-retry, retain-on-failure, and retain-on-failure-and-retries. Select the policy that fits your debugging and artifact-retention needs. You can open a trace with:
npx playwright show-trace path/to/trace.zip
For lower-level control outside Playwright Test, the tracing API can start and stop a trace around a scripted workflow. See the official tracing documentation for the available capture options in your installed release.
5. Run the recorded workflow headlessly in CI
- Generate a test interactively with Codegen, or write a test directly.
- Review locators and add assertions that verify the expected result.
- Set video and trace policies in
playwright.config.tsbased on whether you need every run or only failures and retries. - Run
npx playwright testin your CI job. - Collect the Playwright test output and configured artifacts after the runner exits and closes browser contexts.
- Open videos with a compatible media player and traces with
npx playwright show-trace.
Install the browsers required by your Playwright project using its documented browser installation command. Browser dependencies and operating-system requirements vary by environment; use the current Playwright installation guide for your runner rather than assuming a local setup will match a CI image.
6. Make recordings stable and useful
Use resilient locators and explicit outcomes
Prefer locators based on accessible roles and names, meaningful text, or stable test IDs. Generated selectors still need review: repeated labels, changing content, and ambiguous matches can make a test unreliable. Assert the result that matters—for example, that a confirmation appears or a value changes—instead of relying only on a click completing.
Wait for the right condition
Do not add arbitrary sleeps as the default synchronization strategy. Wait for a relevant navigation, locator state, or page response. Fixed delays can make recordings slow and still fail when a page takes longer than expected. Use a delay only when the behavior itself is time-dependent and the delay is intentional.
Control environment-dependent behavior
Set the viewport, locale, timezone, color scheme, geolocation, and authentication state when the site’s behavior depends on them. For repeatable runs, use consistent test data and avoid relying on third-party content or external services that may change independently.
Balance artifact coverage and storage
Recording video and retaining traces for every passing run creates more artifacts to upload, store, and review. Keeping artifacts only for failures or retries reduces routine output while preserving evidence for many debugging cases. Choose retention with your CI storage limits and the sensitivity of page content in mind: traces and videos can expose rendered data and should be handled like test artifacts.
7. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Codegen does not run headlessly | Codegen is an interactive browser-and-Inspector recorder. | Use Codegen to bootstrap the test, then run the resulting script or test headlessly. |
| No video appears | Video is disabled, the context did not close, or the artifact has not been finalized. | Enable a video mode or recordVideo, await context.close(), and collect files after shutdown. |
| Video exists only for some tests | The configured policy retains recordings only on failure or retry. | Use video: 'on' to record all tests, or keep the selective mode if that is the intended retention policy. |
| Trace is missing on a passing test | The trace mode may capture only retries or failures. | Review the configured trace mode; use on when every run needs a trace, then account for the larger artifact volume. |
| Test fails after Codegen generated a click | The target locator may be ambiguous, the page state changed, or the action was recorded before the page was ready. | Use a more specific role, name, or test ID; add an assertion; and wait for the target state that enables the action. |
| Test passes locally but fails in headless CI | Timing, viewport, browser installation, dependencies, authentication, or external page content differs. | Match the browser and context settings, install the project’s required browsers and dependencies, and inspect a failure trace. |
| Recording output is incomplete | The script exited or the browser context closed before the final action or file flush. | Await all page actions and close the context cleanly before process exit. |
| Puppeteer recording method is unavailable | The referenced Page.record() API is documented on the next-version site and is experimental. |
Check your installed Puppeteer version and its official API docs; do not assume the next-version API is available in a stable release. |
8. Or skip the browser setup
If you need a screenshot rather than a replayable interaction, video, or debugging trace, ScreenshotNeo returns an image or PDF from one API request. See the ScreenshotNeo API documentation for request options.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);
ScreenshotNeo removes cookie banners, popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. This captures a page image or PDF; it does not record your interactions as test code, video, or a debugging trace.
Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.
FAQ
Can I record interactions without opening a visible browser?
Codegen’s interactive recording workflow opens a browser and Inspector. To run without a visible window, execute a scripted test headlessly after generating or writing it.
Should I choose a video or a trace?
Choose video when a person needs to watch the session. Choose a trace when you need step-level page state and debugging evidence. A test script is the reusable artifact for replaying interactions.
Does ScreenshotNeo record a browser session?
No. ScreenshotNeo captures a page as an image or PDF. Use Playwright video or tracing when you need session recording or execution evidence.


