Browser Context (upcoming)
Available in version 1.1.72 (not yet live).
Launch, quit, manage, and inspect the browser context and pages your TaskBot uses.
// @zw-run-locally
// Quick start (abridged)
await zw.browserContext.launch({
launchConfig: {
launchOptions: { headless: true },
},
/* More options available */
});
await zw.log("Context info", await zw.browserContext.getContextInfo());
await zw.browserContext.quit();1. Core Concepts
Launching the browser context
Launch with zw.browserContext.launch() (ZeroWork-managed). This ensures:
No-code blocks use the same context.
Lifecycle is managed for you. To opt out of auto-quit, pass
runConfig.keepAlive: true.(Re)launches reapply your launch arguments.
Note: If you need a custom launch flow or a self-managed context, see Advanced: Custom and self-managed contexts below.
Active page
A TaskBot has one active page at a time. No-code web-interaction blocks act on the active page. If you create a page in code and want no-code blocks to use it, set it with zw.browserContext.setActivePage(page).
Context (re)launch
A TaskBot automatically (re)launches a context in these cases:
Open Link building block β launches one if none exists, otherwise reuses.
Write JS set to run in the browser β launches one if none exists, otherwise reuses.
A call to
zw.browserContext.launch()β launches one and, depending onpolicy.makeMain, either replaces the existing context or creates a parallel one.Launch Browser building block β launches one and replaces the existing context.
Recovery after staleness or a crash.
Performance optimizations in long-running TaskBots.
π‘ Common gotcha: Closing the last tab (e.g., with Switch or Close Tab) ends the context. The next Open Link block creates a fresh context from defaults.
Avoid surprises (e.g., βI launched a headless browser and it suddenly became headful mid-runβ) with these best practices:
Use
zw.browserContext.launch()to launch. Don't use custom context launch flows likeplaywright.chromium.launch(). (If you need a custom launch flow, you can passcontextProvider.)Add cookies, scripts, and permissions via
zw.browserContext.launch()orzw.browserContext.setDefaults()so that they reapply on (re)launches. Don't use ad hoc calls likecontext.addCookies().
Sticky mode (sticky profiles)
Sticky profiles follow special rules.
One browser instance per profile. Same
stickyProfileIdβ the same live browser instance across TaskBots (multiple isolated tabs).Later launches attach to the live browser instance and ignore conflicting browser-level args (e.g.,
headless). Other arguments likecookies,scriptsandonContextReadystill apply on attach (deduplicated).Quitting from one run closes that runβs tabs, but if other TaskBots are still using the browser instance it remains running and only quits when the last user leaves.
Lifecycle
Contexts are closed and cleared automatically.
When a run ends, the context and browser quit unless
runConfig.keepAliveistrueor a shared sticky profile is still in use by other TaskBots.If
runConfig.keepAliveistruebut there are no open or eligible tabs, the context and browser still quit.If the browser stays open because of
runConfig.keepAlive, the Desktop Agent cleans up when it detects manual closure (for example, when you close the window by clicking X). The listener also stays active after a TaskBot run, so cleanup is guaranteed even when no TaskBot is running.
β οΈ Caution:
headless: true+keepAlive: truecan leave an invisible instance consuming resources or, ifmode: "sticky", blocking a sticky profile. The UI blocks this combination, but the API allows itβuse with care.
Advanced: Custom or self-managed contexts
Custom launch flow Provide a callback via
contextProviderinzw.browserContext.launch()when you need options the standardzwAPI doesnβt cover (e.g., launching with Firefox). See examples here.Self-managed context Pass
policy.makeMain: falseinzw.browserContext.launch()to opt out of lifecycle and relaunch policy. No-code blocks keep using the main context. To rejoin the managed flow later, usezw.browserContext.adoptContext(). See examples here.
2. Launch the Browser β launch()
launch()At a Glance
async
await zw.browserContext.launch(args: CustomLaunchArgs)β launches a new browser context and returns it.
Launch Arguments β CustomLaunchArgs
CustomLaunchArgs Defaults used when you pass no arguments
All options are optional. If you call zw.browserContext.launch() with no arguments, it inherits the Browser Launch Settings configured for this TaskBot or any values previously set via zw.browserContext.setDefaults(). If you set policy.inheritDefaults: false, any option you donβt specify falls back to the built-in baseline defaults (the default: comments in the type definitions).
Note how mode affects the default baseline when policy.inheritDefaults: true:
If you donβt pass
mode,modeand its corresponding settings are inherited from the current defaults.If you pass
mode: "sticky", defaults are taken from the sticky profile settings for thestickyProfileIdyou provide.If the current defaults use
mode: "sticky"but you passmode: "incognito", ZeroWork switches to the built-in baseline defaults and ignores the current defaults.
Mode β launchConfig.mode and launchConfig.stickyProfileId
launchConfig.mode and launchConfig.stickyProfileIdmode(default:"incognito")Selects how ZeroWork launches and manages the browser context.
"incognito": Launches an isolated browser session."sticky": Launches in a sticky browser profile. Multiple TaskBots with the samestickyProfileIdshare the same browser instance in parallel tabs (see Sticky Profiles further below).
stickyProfileIdSelects which sticky profile to use (only relevant in sticky mode). Ignored whenmode: "incognito".
Maximize Flag β launchConfig.maximize
launchConfig.maximizemaximize(default:true) Maximizes the window. Ignored inheadlessmode (headlessmust use an explicitlaunchConfig.contextOptions.viewport, see Context Options further below).
Bypass Detection Flag β launchConfig.bypassDetection
launchConfig.bypassDetectionbypassDetection(default:false) Hardens bot detection bypass measures and keeps TaskBots indistinguishable from human users to Cloudflare and similar anti-bot systems. (Called previouslypowerModein beta versions.)βΉοΈ Trade-offs: In
bypassDetectionmode, some launch and context options are unavailable (see Launch Options and Context Options further below) and file uploads larger than ~50 MB are blocked (downloads are unaffected).
Cookies β launchConfig.cookies
launchConfig.cookiesProvide cookies up front so they are reapplied on every context (re)launch.
Each cookie must include at least name, value, and domain (and path, where relevant).
You can either provide the cookie array or, if you have cookies copied from multiple websites, an array of cookie arrays.
π‘ Tip! Avoid adding cookies in code later via
context.addCookies()β those wonβt automatically reapply on context relaunch.
Example
Scripts β launchConfig.scripts
launchConfig.scriptsScripts are injected before any page loads and reinjected on context (re)launch.
Each script item is either { path } or { content } (when using path, provide an absolute path).
π‘ Tip! Avoid adding scripts in code later via
context.addInitScript()β those wonβt automatically reapply on context relaunch.
Example
Launch Options β launchConfig.launchOptions
launchConfig.launchOptionsargsUse with care: custom flags can break bot detection bypass measures. Note:--user-data-dirand--profile-directoryare reserved. WhenbypassDetectionistrue,--remote-debugging-portis also reserved. If you pass a reserved flag (for example--user-data-dir), that flag is ignored.executablePathBy default, your Chrome path is auto-detected and used. You can override it with any Chromium-based browser (e.g., Chrome, Brave, Vivaldi, Chromium). You can find the executable path by opening chrome://version in your browser. Note: Some Chromium forks (e.g., Opera) diverge too much and may not work.headless(default:false)Runs in the background and uses fewer resources.proxyFor SOCKS5, prefix withsocks5://. SOCKS5 auth isnβt supported βusernameandpasswordapply to HTTP proxies only.More options when
bypassDetectionis disabled WhenlaunchConfig.bypassDetectionisfalse, PlaywrightβsBrowserType.launchoptions are available. For the full list, see launch β Arguments here.
Example
Context Options β launchConfig.contextOptions
launchConfig.contextOptionspermissionsZeroWork always grants"clipboard-read"and"clipboard-write"so that the Save From Clipboard building block works.β οΈ Avoid adding permissions in code later via
context.grantPermissions()β those wonβt automatically reapply on context relaunch.
userAgentUnless you know exactly what youβre doing, prefer not to change it. If you changeuserAgent, anti-detection may no longer be fully guaranteed.viewport(default:{ width: 1440, height: 900 }) Takes effect whenmaximizeis disabled or whenheadlessis enabled.extraHTTPHeadersDiscouraged, because it can break bot detection bypass measures. Use with care.More options when
bypassDetectionis disabled WhenlaunchConfig.bypassDetectionis disabled, PlaywrightβsBrowser.newContextoptions are available. For the full list, see newContext β Arguments here.β οΈ Warning! Using Playwright API to set options like
geolocation,extraHTTPHeaders, etc. can harm the built-in bot detection bypass measures.
Examples
Headless with explicit viewport
Record a video
Callback when Ready β launchConfig.onContextReady
launchConfig.onContextReadyRuns whenever the context is (re)launched.
Example
Context Provider β launchConfig.contextProvider β Advanced
launchConfig.contextProvider β AdvancedProvide a custom launch callback. Use it when you need a custom-launched context but still want no-code blocks to use it and want to benefit from lifecycle management and relaunch policy.
Use cases
You must use a browser the ZeroWork launch API doesnβt support out of the box (for example, Firefox instead of Chromium).
You need a 100% pristine context without ZeroWorkβs built-in anti-detection measures or defaults.
Example
Launching Firefox
Because you supply the context, you control launchOptions (headless, proxy, etc.), contextOptions (viewport, permissions, etc.), window size, and any anti-detection choices. ZeroWork adopts your context, applies cookies and scripts, then runs onContextReady. Use this only if you need full control over browser creation and understand the trade-offs.
These arguments are ignored when contextProvider is set
launchConfig.launchOptionslaunchConfig.contextOptionslaunchConfig.maximize,launchConfig.bypassDetection
The rest of the arguments apply β including their corresponding defaults if policy.inheritDefaults is true or left undefined (default is true).
β οΈ Exception: Here,
modeis always treated as"incognito". If you passmode: "sticky", ZeroWork throws an error because sticky mode isnβt supported whencontextProvideris used. Naturally, you fully control what happens insidecontextProvider, so you can launch with your own persistent browser profile there (e.g., with PlaywrightβslaunchPersistentContext()). ZeroWork just wonβt treat it as sticky mode, meaning thereβs no built-in browser instance sharing and no profile locking.
Run Config β runConfig
runConfigkeepAlive(default:false) Keeps the browser open after the run ends.π‘
keepAlive: trueis ignored if, at run end, no pages remain. The context then closes. Tabs on about:blank or ZeroWork launch pages donβt count unless they are tied to Write JS in-browser code execution.βΉοΈ In sticky profiles,
keepAliveapplies only to this runβs tabs. Iftrue, your tabs remain open; iffalse, your tabs close. The browser instance itself stays running as long as another TaskBot in the same profile is using it. It quits only when the last user leaves and no kept-alive tabs remain.β οΈ With sticky profiles, prefer leaving
keepAlivefalse. After a long device sleep, the connection can drop while the browser stays open, blocking the profile until you restart the Desktop Agent or quit that browser. Only one browser instance can use a profile at a time.
bringToFront(default:true) Brings newly opened tabs to the front (applies to no-code blocks that open tabs).
Policy Options β policy
policyinheritDefaults(default:true) Inherits values from Browser Launch Settings or any values previously saved viazw.browserContext.setDefaults()for options you donβt specify. Note that if you passlaunchConfig.mode: "sticky", the inherited defaults come from the sticky profileβs settings (based onstickyProfileId). Likewise, if the current defaultsβ mode is set to"sticky"but you explicitly passmode: "incognito", ZeroWork falls back to the built-in baseline defaults and ignores the current defaults. Example: If Browser Launch Settings have Run in background on and you donβt setheadlessinlaunchConfig.launchOptions,headlesswill be inherited astrue.makeMain(default:true) β advanced Iftrue, the launched context becomes the main context. The previous main context is closed (unless itsrunConfig.keepAlivesetting istrue). If you set it tofalse, you partially lose automatic lifecycle, retries, and no-code blocks will keep using the old context.β οΈ Leave
makeMainattrueunless youβre deliberately running a self-managed context for an advanced use case. If you do, see Adopt Self-Managed Contexts for more details further below.π‘
makeMain: falseis ignored if you launch a context with a sticky profile that is already launched and has already been made main elsewhere. This is because launches of the same sticky browser profile all share the same browser instance, see Sticky Profiles for more details further below.
setAsDefaults(default:trueifmakeMainistrue, otherwisefalse) β advanced Sets these options for future launches as well as automatic relaunches (e.g., after a staleness or crash recovery) for the rest of the TaskBot run.β οΈ If you set
setAsDefaultstofalse, a later relaunch may revert to older defaults. Likewise, if you setsetAsDefaultstotruewhilemakeMainisfalse, the main context may relaunch with unexpected, unrelated settings. Prefer keeping the default.
3. Defaults β setDefaults(), getDefaults(), resetDefaults()
setDefaults(), getDefaults(), resetDefaults()Defaults are the settings a TaskBot uses when launching or relaunching contexts. You can ensure that any subsequent launch or relaunch uses the settings you want by setting defaults.
See Core Concepts β Context (re)launch for a list of cases when a browser context is (re)launched.
At a Glance
async
await zw.browserContext.getDefaults()β returnsCustomLaunchArgs.async
await zw.browserContext.setDefaults(args:CustomLaunchArgs)β updates the TaskBot-level default launch settings for the current run.async
await zw.browserContext.resetDefaults()β resets the TaskBot-level default launch settings to whatβs defined in Browser Launch Settings.
Notes
zw.browserContext.getDefaults()excludespolicy, which is only meaningful when launching or setting defaults.In
setDefaults(), onlypolicy.inheritDefaultsis accepted (makeMainandsetAsDefaultsare ignored β they have no effect when setting defaults).
Examples
Set all subsequent (re)launches to headless
Discover a sticky profileβs ID
4. Context β getContextInfo(), getContext()
getContextInfo(), getContext()At a Glance
zw.browserContext.getContext()β returns the current main browser context.async/sync*
await zw.browserContext.getContextInfo()β returns:
*async in browser, sync locally (see Local vs. Browser Execution).
Working with the returned context
You can call any Playwright BrowserContext API. For the full list of available methods, properties and events, see here.
β οΈ Avoid adding cookies, scripts, and permissions via the context API (e.g.,
context.addCookies()). Instead, pass them tozw.browserContext.launch()orzw.browserContext.setDefaults()(e.g.,zw.browserContext.launch({ launchConfig: { cookies: [] } })) so that they reapply on relaunch.
β οΈ Avoid changing user agent, timezone, locale, or geolocation (e.g.,
context.setGeolocation()), as this can harm the built-in anti-detection measures.
Examples
Add a listener
Clear cookies
Relaunch non-headless if the current context is headless
5. Sticky Browser Profiles β clearProfile(), cloneProfile(), listProfiles()
clearProfile(), cloneProfile(), listProfiles()Sticky profiles let multiple TaskBots share one browser session (same cookies/storage/fingerprint) via a persistent, shared user data directory.
At a Glance
async
await zw.browserContext.clearProfile({ stickyProfileId: number })β clears the profile, or refuses to clear if the profile is in use.async
await zw.browserContext.cloneProfile({ cloneTo: { stickyProfileId: number }, cloneFrom: { profilePath: string } })β clones the profile, or refuses to clone if the target profile is in use. You can find the profile path by openingchrome://versionin your browser and copying the Profile Path value.async
await zw.browserContext.listProfiles()β lists available profiles.
Behavior
Parallel TaskBots, one instance: One shared browser instance (with multiple isolated tabs) per
stickyProfileId.In-use lock: If a profile is in use, both
clearProfileandcloneProfilewill fail to avoid breaking active runs.Create and discover: You can create sticky profiles in Browser Launch Settings at creator.zerowork.io. You canβt create them via the API, but you can:
Create one in the UI (Browser Launch Settings).
Click Save to create the profile. Then open the profile again β the Profile ID appears at the bottom left. Copy it from there, or run
zw.browserContext.listProfiles()to discover it.Use that profile ID as
stickyProfileIdprogrammatically.
contextProviderand sticky mode:contextProviderisnβt supported in sticky mode. Ifmodeis"sticky"andcontextProvideris provided, ZeroWork throws an error.
Shared Browser Side Effects
Non-deterministic tab order across independent TaskBots. If you need to switch programmatically, match by URL and/or TaskBot ID. Example
Attach semantics β when a browser instance is already live for that profile ID and a launch event attaches to it, browser-level arguments are ignored and others are applied. By default, applied items affect the whole context, so other TaskBots sharing the instance will see them (except
keepAliveandbringToFront, which apply to this runβs tabs only). Ignored on attach:launchConfig.launchOptionslaunchConfig.contextOptionslaunchConfig.bypassDetection,launchConfig.maximize
Applied:
runConfigβ applies to this run's tabs only.launchConfig.scriptsβ scripts that already ran are ignored; any new scripts are applied (context-wide).launchConfig.cookiesβ duplicate cookies by the samename+domain+pathare ignored; any new cookies are applied (context-wide).β οΈ Be careful not to pass conflicting cookies or two distinct cookies with the same
name/domain/path(duplicates will be ignored).
launchConfig.onContextReadyβ runs on every attach (gate it if you want it to run only on true (re)launches). Gate example:
Anti-patterns
keepAlivecaution. We donβt recommend settingrunConfig.keepAlivetotrueinzw.browserContext.launch()orzw.browserContext.setDefaults()when using sticky profiles. After a long device sleep, the connection can drop while the browser stays open, blocking the profile until you restart the Desktop Agent or quit that browser. Only one browser instance can use a profile at a time. Prefer leavingrunConfig.keepAlive: falsefor sticky profiles.
6. Quit Browser β quit()
quit()At a Glance
async
await zw.browserContext.quit(opts?: { forceQuit?: boolean })β closes the current context and the browser instance.
Behavior
Closes the current runβs pages and attempts to close the browser/context.
Since
zw.browserContext.quit()is called explicitly, thekeepAlivesetting is ignored.In sticky profiles:
If other TaskBots are still using the same instance, pages from this run close, but the browser instance does not quit.
If no other TaskBots are using the instance, the browser quits fully.
forceQuit: trueforces termination even if mode is"sticky"and browser is actively shared. Use with care.
π‘Contexts are automatically managed and closed when needed. See Core Concepts β Lifecycle. You only need to call
zw.browserContext.quit()if it's part of your logic. Otherwise, lifecycle management is handled out of the box.
7. Active Page & Pages β setActivePage(), getActivePage(), isActivePage(), createPage(), listPages()
setActivePage(), getActivePage(), isActivePage(), createPage(), listPages()At a Glance
async
await zw.browserContext.setActivePage(page: Page, options?: { forceContextMismatch?: boolean })β makes a Page the βactive pageβ used by no-code building blocks that do web interactions.zw.browserContext.getActivePage()β returnsPage | null, i.e. the page (if any) currently used by the TaskBot and its no-code building blocks.zw.browserContext.isActivePage(page: Page)β returnsbooleanasync
await zw.browserContext.createPage({ url?: string, context?: BrowserContext })β creates a new page and returnsPagezw.browserContext.listPages()β returns:
Whatβs an active page?
The active page is the page that no-code web-interaction blocks act on. There can be only one active page at a time. You can open other pages in code, but unless you set one as active, no-code blocks wonβt use it.
Example
Notes & caveats
createPage β create in custom context β advanced
By default, pages are created in the current main context. If you need to create a page in a self-managed, non-main context, you can pass it in context, and the page will be created there instead.
Context mismatch & forceContextMismatch
If the page belongs to a different browser context than the current main context, an error is thrown similar to:
The page you provided belongs to a different browser context than the current main context. If you must use a custom launch flow, provide
contextProviderinzw.browserContext.launch(). If you must use a self-managed context, usezw.browserContext.adoptContext()to adopt it before callingzw.browserContext.setActivePage(). While not recommended, you can also setforceContextMismatchtotrue.
forceContextMismatch(default:false) β advancedConsider it an escape hatch. Setting to
trueis not recommended.If set to
true, the page is made active even if it belongs to a foreign context. No-code blocks will now operate on the active page, but inconsistencies can arise when Switch or Close Tabs is used, when a context relaunches, or when you usezw.browserContext.getContext().If you must launch a custom context, explore
contextProviderinzw.browserContext.launch()first. For more advanced use cases and self-managed contexts, explorezw.browserContext.adoptContext().
Two ways to hit a mismatch
Launching a second context with
makeMain: falseand creating a page there.Creating a context entirely outside
zw.browserContext.launch()(e.g., using the PlaywrightBrowserTypeAPI).
Bad (illustrative) pattern
8. Adopt Self-Managed Contexts (Advanced)
For advanced use cases, you can create additional (non-main), self-managed contexts via zw.browserContext.launch() and then let ZeroWork adopt one of them as the active, managed context.
At a Glance
async
await zw.browserContext.adoptContext(context: BrowserContext)β adopts a non-main context launched byzw.browserContext.launch()(withpolicy.makeMain: false).
β οΈ Contexts created directly via the Playwright
BrowserTypeAPI are not accepted. If you need a custom launch flow, provide it viacontextProviderinzw.browserContext.launch().
Example
Switching between two launched (non-main) contexts
Notes
Largely unavailable in browser execution. The
zw.browserContext.*API is available mostly for local code execution. Only inspection methodszw.browserContext.getContextInfo()andzw.browserContext.getDefaults()are supported in the browser.
Last updated