state object. Variables, pages, and listeners persist between calls. Browser tabs are shared, but state is not.playwriter session new # => 1 playwriter session new # => 2 # List all sessions with their stored keys playwriter session list # ID State Keys # -------------- # 1 myPage, userData # 2 -
-s <id> to all commands to use a specific session:playwriter -s 1 -e "state.users = ['Alice', 'Bob']" playwriter -s 2 -e "console.log(state.users)" # undefined (isolated)
state object persists between execute calls within the same session. Use it to store pages, data, listeners, and anything else you need across calls:// Call 1: store data state.page = context.pages().findLast(p => p.url() === 'about:blank') ?? await context.newPage() await state.page.goto('https://example.com') state.results = [] // Call 2: data is still there console.log(state.results.length) // 0 state.results.push(await state.page.title())
context.pages() returns all browser tabs with Playwriter enabled, shared across all sessions. Multiple agents see the same tabs. To avoid interference, always get your own page:// First call: grab an empty tab or create one, navigate immediately state.page = context.pages().findLast(p => p.url() === 'about:blank') ?? await context.newPage() await state.page.goto('https://example.com') // Store in state.page and use it for ALL subsequent operations
about:blank tab between execute calls.if (!state.page || state.page.isClosed()) { state.page = context.pages().findLast(p => p.url() === 'about:blank') ?? await context.newPage() } await state.page.goto('https://example.com')
context.pages() if the user explicitly asks you to control a specific tab:const pages = context.pages().filter(x => x.url().includes('myapp.com')) if (pages.length === 0) throw new Error('No myapp.com page found') state.targetPage = pages[0]
playwriter by default. Use the shortest clear single-word name with no spaces, such as docs, shop, test, or scrape.# Tabs created by this session join a group named "docs" playwriter session new --tab-group docs # Pick the group color yourself (any Chrome color) playwriter session new --tab-group docs --tab-group-color blue # Rename the group later — moves the session's existing tabs playwriter session update 1 --tab-group research # Change only the color — also works on the default playwriter group playwriter session update 1 --tab-group-color red
playwriter session new --tab-group scrape --tab-group-color grey
--tab-group. That keeps many open tabs readable instead of one mixed strip:playwriter session new --tab-group agent1 --tab-group-color blue playwriter session new --tab-group agent2 --tab-group-color pink
playwriter session new --tab-group done --tab-group-color grey
playwriter group only moves tabs that session created. Manually enabled tabs and other sessions' tabs stay in the default group. Renaming a custom group moves everything in it, including tabs you dragged in.--tab-group-color, each custom group gets a deterministic color derived from its name (the default playwriter group stays green). The flag accepts every Chrome group color: grey, blue, red, yellow, green, pink, purple, cyan, orange. playwriter session list shows the group per session in the GROUP column.# Reset a session (reconnect browser, clear state) playwriter session reset 1 # Delete a session playwriter session delete 1 # List all sessions playwriter session list
| Variable | Description |
state | Persisted object, isolated per session |
page | Default page (shared, prefer state.page) |
context | Browser context, access all pages via context.pages() |
require | Load Node.js modules (path, fs, crypto, etc.) |
fetch | Standard fetch API |
Buffer, URL, URLSearchParams | Standard globals |
setTimeout, setInterval | Timers |
crypto, process | Node.js globals |
window.open, OAuth login flows, target=_blank) are auto-relocated to tabs in the main window by the extension. The new tab appears in context.pages():await state.page.locator('button:has-text("Login with Google")').click() await state.page.waitForTimeout(1000) // New tab is the last page const pages = context.pages() const loginPage = pages[pages.length - 1] await loginPage.locator('[data-email]').first().click()
[WARNING] New page opened from current page (index N, initial url: ...) message pointing to the new tab.state.page.removeAllListeners()
browser.close() or context.close(). Only close pages you created yourself.