API Reference
API Reference
Generated from voidcrawl
v0.4.1. Only symbols in__all__are listed.
Configuration
BrowserConfig
Configuration for launching or connecting to a single browser instance.
Controls headless/headful mode, stealth patches, proxy routing, and
custom Chrome flags. Pass an instance to BrowserSession or
embed one inside PoolConfig.
Attributes:
headlessbool— Run Chrome without a visible window. Defaults toTrue.stealthbool— Apply anti-detection patches (navigator overrides, etc.). Defaults toTrue.no_sandboxbool— Disable the Chrome sandbox. Required in some Docker environments. Defaults toFalse.proxystr | None— Upstream HTTPS proxy URL, e.g."http://proxy:8080".chrome_executablestr | None— Path to a custom Chrome/Chromium binary. WhenNone, the bundled Chromium discovery is used.extra_argslist[str]— Additional command-line flags forwarded to Chrome.user_data_dirstr | None— Persistent Chrome user data directory. Use this for same-profile anti-bot validation and long-lived local sessions.ws_urlstr | None— Connect to an already-running Chrome instance via its WebSocket debugger URL instead of launching a new one.portint | None— Pin Chrome’s--remote-debugging-portfor a launched browser, so another process can attach to it viaws_urland adopt one of its tabs withBrowserSession.attach_page.None(default) lets the OS pick a free ephemeral port.debugbool— Wrap pages in an interactive step-debugger. WhenTrue,BrowserSession.new_pagereturns avoidcrawl.debug.DebugPageandvoidcrawl.actions.Flow.runautomatically pauses before each action. Requires thedebugextra (uv add 'voidcrawl[debug]'). Defaults toFalse.steppingbool— Pause before every action whendebug=True. Set toFalseto run freely without stopping. Defaults toTrue.highlightbool— Flash a red CSS outline on targeted elements whendebug=True. Defaults toTrue.step_delayfloat— Seconds to wait between actions in non-stepping mode whendebug=True. Defaults to0.3.
model_dump
model_dump() -> dict[str, object]
PoolConfig
Configuration for a pool of reusable browser tabs.
Controls how many Chrome processes to launch, how many concurrent tabs each process may hold, and when tabs are recycled or evicted. Attributes:
browsersint— Number of Chrome processes in the pool. Defaults to1.tabs_per_browserint— Maximum concurrent tabs per Chrome process. Defaults to4.tab_max_usesint— Hard-recycle a tab after this many navigations. Prevents memory leaks in long-running crawls. Defaults to50.tab_max_idle_secsint— Evict a tab that has been idle longer than this many seconds. Defaults to60.acquire_timeout_secsint— Maximum seconds to wait inBrowserPool.acquirewhen all tabs are checked out.0means wait indefinitely. Defaults to30.chrome_ws_urlslist[str]— Pre-existing Chrome WebSocket debugger URLs. When non-empty, the pool connects to these instead of launching new processes, and browsers is ignored.browserBrowserConfig— SharedBrowserConfigapplied to every Chrome process launched by the pool.
from_docker
from_docker(headful: bool = False, host: str = 'localhost', ports: list[int] | None = None, tabs_per_browser: int = 4, check: bool = True) -> PoolConfig
Build a PoolConfig for a VoidCrawl Docker container.
Selects the correct default ports for headless or headful mode and optionally probes the Chrome endpoints before returning so you get a clear error message if the container is not running. Args:
headfulbool— Connect to the headful Docker container (ports 19222/19223). Defaults toFalse(headless, ports 9222/9223).hoststr— Hostname where the Docker container is reachable. Defaults to"localhost".portslist[int] | None— Override the default port list. WhenNone, the defaults resolve in this order: explicitCDP_PORTSenv var (comma-separated), elseCDP_PORT_BASE+[0, 1], else[9222, 9223]for headless /[19222, 19223]for headful.tabs_per_browserint— Max concurrent tabs per Chrome process. Defaults to4.checkbool— Probe each Chrome endpoint before returning and raiseRuntimeErrorwith a setup hint if unreachable. Defaults toTrue.
Returns: PoolConfig — class:PoolConfig with chrome_ws_urls pre-populated.
Raises:
RuntimeError— Whencheck=Trueand a Chrome endpoint is unreachable. The error message includes thedockercommand needed to start the container.
from_env
from_env() -> PoolConfig
Build a PoolConfig from environment variables.
Reads the following variables (all optional):
+------------------------+---------------------------------+---------+
| Variable | Description | Default |
+========================+=================================+=========+
| CHROME_WS_URLS | Comma-separated ws/http URLs | — |
+------------------------+---------------------------------+---------+
| BROWSER_COUNT | Chrome processes to launch | 1 |
+------------------------+---------------------------------+---------+
| TABS_PER_BROWSER | Max concurrent tabs per browser | 4 |
+------------------------+---------------------------------+---------+
| TAB_MAX_USES | Hard recycle threshold | 50 |
+------------------------+---------------------------------+---------+
| TAB_MAX_IDLE_SECS | Idle eviction timeout | 60 |
+------------------------+---------------------------------+---------+
| ACQUIRE_TIMEOUT_SECS| Max seconds for acquire() | 30 |
+------------------------+---------------------------------+---------+
| CHROME_NO_SANDBOX | Set to "1" to disable | — |
+------------------------+---------------------------------+---------+
| CHROME_HEADLESS | Set to "0" for headful | 1 |
+------------------------+---------------------------------+---------+
| AUTO_EVICT | Set to "0" to disable | 1 |
+------------------------+---------------------------------+---------+
Returns: PoolConfig — A fully-populated PoolConfig.
from_profile
from_profile(profile: ScaleProfile = 'balanced', env: str = 'auto') -> PoolConfig
Build a PoolConfig from a resource-aware scale profile.
Measures current system resources and returns a pool configuration tuned to the requested aggressiveness level. Args:
profileScaleProfile— One of"minimal","balanced"(default), or"advanced".envstr— Environment hint passed tovoidcrawl.scale.compute_scale."auto"(default) detects automatically from system facts.
Returns: PoolConfig — class:PoolConfig sized for the detected resources.
Raises:
- “ — exc:
~voidcrawl.scale.InsufficientResourcesError: When the machine lacks the minimum resources to launch Chrome.
model_dump
model_dump() -> dict[str, object]
Sessions & Pools
BrowserPool
Pool of reusable browser tabs across one or more Chrome processes.
Manages a semaphore-bounded set of recycled tabs. Tabs are navigated
to about:blank on release rather than closed, making subsequent
acquires near-instant. Tabs are hard-recycled after
PoolConfig.tab_max_uses navigations and evicted after
PoolConfig.tab_max_idle_secs of inactivity.
Args:
configPoolConfig— Pool sizing and browser launch options.
acquire
acquire() -> _AcquireContext
Check out a tab from the pool as an async context manager.
The tab is automatically returned to the pool when the context
exits, even on exception.
Returns: _AcquireContext — An async context manager yielding a PooledTab.
warmup
warmup() -> None
Pre-open tabs across all browser sessions.
Call after entering the pool context to eliminate cold-start
latency on the first acquire calls.
BrowserSession
Async context manager wrapping a single Chromium instance via CDP.
Use as an async with block. On entry the browser is launched (or
connected to, if BrowserConfig.ws_url is set); on exit the
process is terminated and resources are freed.
Args:
configBrowserConfig | None— Browser launch options. Defaults toBrowserConfig()(headless + stealth).
attach_page
attach_page(target_id: str) -> Page
Adopt an existing tab by its CDP target_id.
Unlike new_page, this opens no new tab and does not re-apply
stealth — it wraps the live tab the browser already has. Use it from a
second process attached via BrowserConfig.ws_url to drive the
exact tab another driver is on (e.g. to solve a captcha in place, so the
minted token lands in that tab). Obtain target_id from
Page.target_id (or from the VoidCrawl MCP session_open
result).
Args:
target_idstr— The CDP target id of the tab to adopt.
Returns: Page — class:Page handle bound to the existing tab.
close
close() -> None
Shut down the browser process immediately.
Called automatically on __aexit__; only needed if you want
to close the browser without leaving the async with block.
new_page
new_page(url: str | None = None) -> Page
Open a blank tab, or navigate a new tab to url when provided.
When BrowserConfig.debug is True, returns a
voidcrawl.debug.DebugPage wrapper that automatically
triggers interactive step-debugging when passed to
voidcrawl.actions.Flow.run.
Args:
urlstr | None— The URL to load in the new tab.
Returns: Page — The new tab handle (or a debug wrapper when debug=True).
page
page(url: str | None = None) -> _PageContext
Create a page context that always closes its tab.
The tab is closed on success, exception, timeout, and cancellation. If close also fails while another exception is active, the original exception is preserved.
version
version() -> str
Return the browser version string (e.g. "Chrome/126.0.6478.126").
Returns: str — The Chrome/Chromium product version reported by the browser.
websocket_url
websocket_url() -> str
The browser’s CDP WebSocket endpoint (ws://…).
Hand this to another process (with a tab’s target_id) so it can
attach to the same Chrome via BrowserConfig(ws_url=…) and adopt
that tab with attach_page.
Returns: str — The ws:// debugger URL of the underlying browser.
Page
A single browser tab created via BrowserSession.new_page.
add_init_script
add_init_script(script: str) -> None
Install JavaScript before each subsequent document executes.
arm_download
arm_download(dir: str, max_bytes: int | None = None) -> DownloadCapture
Arm an action-triggered download capture into dir.
Perform the triggering action next (e.g. click_by_role), then
pass the returned capture to wait_download. Use for downloads
started by a page action — a “Download” button, a generated/cross-origin
URL (Google Drive) — rather than download, which needs a URL.
voidcrawl.capture_download brackets these as a context manager.
ax_box_in_frame
ax_box_in_frame(frame_url_pattern: str, role: str, name: str, nth: int = 0) -> list[float]
Locate an AX role + name inside a frame; return its on-page
rectangle [x, y, width, height] in CSS pixels.
Same cross-frame, closed-shadow-piercing resolution as
click_ax_in_frame, but returns the geometry instead of clicking
— so you can drive a humanized click yourself (curved approach via
dispatch_mouse_event, press at a jittered point in the box).
Empty name matches any node of that role.
ax_outline_in_frame
ax_outline_in_frame(frame_url_pattern: str, depth: int | None = None) -> str
Compact accessibility outline of a specific (possibly cross-origin)
frame — pierces closed shadow roots. Discover the role / accessible name
to pass to click_ax_in_frame.
ax_tree_outline
ax_tree_outline(depth: int | None = None) -> str
Return the AX tree as a compact, indented role "name" outline.
Readable counterpart to get_full_ax_tree: text-noise and hidden
nodes are pruned. Same output the MCP session_ax_tree tool renders.
click_ax_in_frame
click_ax_in_frame(frame_url_pattern: str, role: str, name: str, nth: int = 0, humanize: bool = False) -> None
Click an element by AX role + name inside a specific frame.
The cross-frame, shadow-piercing analogue of click_by_role:
roots the AX tree at the frame matched by frame_url_pattern and
descends into closed shadow roots, then clicks the match at its
box-model centre with a real compositor mouse event (a trusted
click, unlike a DOM .click()). Reaches widgets the page’s own JS
cannot — e.g. Cloudflare Turnstile’s “Verify you are human” checkbox in
a closed shadow root inside a cross-origin challenges.cloudflare.com
iframe. Empty name matches any node of that role.
Cross-origin google.com / cloudflare frames must be in-process: launch
the session with extra_args=["disable-site-isolation-trials"].
click_by_role
click_by_role(role: str, name: str, nth: int = 0, humanize: bool = False) -> None
Click the nth element matching accessibility role + name.
Markup-independent analogue of click_element: resolves via the AX
tree, bridges to the DOM, scrolls into view, and clicks. Raises if no
such node exists.
Args:
rolestr— Computed accessibility role, e.g."button","link".namestr— Computed accessible name (exact match).nthint— 0-based index when several nodes match.humanizebool— Click at the element’s box-model centre with a humanized compositor pointer path (curved, min-jerk, tremor) instead of a DOM.click(). Off by default.
click_element
click_element(selector: str) -> None
Click the first element matching selector.
click_xy
click_xy(x: float, y: float, humanize: bool = False) -> None
Click at (x, y) with a trusted compositor event (press → release).
With humanize=True the cursor first travels a human-like path there
(see move_mouse). The programmatic analogue of the
click_visual_coords MCP tool.
close
close() -> None
Close this tab and release its resources.
content
content() -> str
Return the full page HTML.
delete_cookie
delete_cookie(name: str, domain: str | None = None, path: str | None = None) -> None
Delete a cookie by name, optionally scoped to a domain and path.
detect_captcha
detect_captcha() -> str | None
Probe DOM for captcha / bot-wall markers.
Returns one of "recaptcha", "hcaptcha", "turnstile",
"cloudflare_challenge", "datadome" — or None.
dispatch_key_event
dispatch_key_event(event_type: str, key: str | None = None, code: str | None = None, text: str | None = None, modifiers: int | None = None) -> None
Send a low-level CDP Input.dispatchKeyEvent.
dispatch_mouse_event
dispatch_mouse_event(event_type: str, x: float, y: float, button: str = 'left', click_count: int = 1, delta_x: float | None = None, delta_y: float | None = None, modifiers: int | None = None) -> None
Send a low-level CDP Input.dispatchMouseEvent.
download
download(url: str, dir: str, timeout: float = 120.0, max_bytes: int | None = None) -> DownloadOutcome
Download url into directory dir through this page’s browser context (cookies / fingerprint preserved).
The stream aborts past max_bytes. Treat dir as quarantine and pass
the result to scan_file before trusting the file. The CDP
download behavior is reset before this returns.
Args:
urlstr— Absolute URL of the file to download.dirstr— Directory the file is saved into.timeoutfloat— Download timeout in seconds.max_bytesint | None— Abort past this many bytes (default 100 MiB).
eval_js
eval_js(expression: str) -> object
Alias for evaluate_js — short form used by MCP tooling.
eval_js_in_frame
eval_js_in_frame(frame_url_pattern: str, expression: str) -> object
Alias for evaluate_js_in_frame.
evaluate_js
evaluate_js(expression: str) -> object
Evaluate a JavaScript expression and return the result.
evaluate_js_in_frame
evaluate_js_in_frame(frame_url_pattern: str, expression: str) -> object
Evaluate expression inside a (possibly cross-origin) iframe.
The frame is selected by a substring of its URL. The expression runs in
that frame’s own execution context (document is the frame’s
document) — the way to reach an iframe whose contentDocument is null
from the parent under the same-origin policy.
Args:
frame_url_patternstr— Substring of the target frame’s URL, e.g."recaptcha/api2/bframe".expressionstr— JavaScript expression or IIFE string.
Raises:
RuntimeError— if no frame matches, or the matched frame has no scriptable execution context.
expect_response
expect_response(pattern: str, timeout: float = 30.0, max_response_bytes: int = 2097152, max_total_bytes: int = 8388608) -> ResponseExpectation
expect_responses
expect_responses(patterns: dict[str, str], timeout: float = 30.0, max_response_bytes: int = 2097152, max_total_bytes: int = 8388608) -> ResponseExpectation
frame_urls
frame_urls() -> list[str]
List the URLs of every frame on the page, in no particular order.
Handy for discovering the right frame_url_pattern to pass to
evaluate_js_in_frame.
get_cookies
get_cookies() -> list[dict[str, Any]]
Return all cookies matching the current page URL.
get_full_ax_tree
get_full_ax_tree(depth: int | None = None) -> list[dict[str, Any]]
Return the browser-computed accessibility (AX) tree.
Wraps CDP Accessibility.getFullAXTree. The result is a flat list of
AX node dicts linked by childIds/parentId; each node carries
role, computed name, properties (state), and
backendDOMNodeId. Call after the page has rendered.
Args:
depthint | None— Maximum descendant depth to traverse.Nonereturns the whole tree.
goto
goto(url: str, timeout: float = 30.0, capture_endpoints: bool = False, wait_until: str = 'networkidle') -> PageResponse
Navigate to url and wait for network idle in one shot. Args:
urlstr— The URL to load.timeoutfloat— Maximum seconds to wait for network idle.capture_endpointsbool— WhenTrue, record the data-plane network endpoints (XHR + Fetch request URLs) seen during the load and surface them asPageResponse.endpoints.
move_mouse
move_mouse(x: float, y: float, humanize: bool = False) -> None
Move the virtual cursor to (x, y) via CDP Input.dispatchMouseEvent.
With humanize=True the cursor travels a realistic curved, minimum-jerk,
lightly-tremored path (multiple MouseMoved events) from its last
position; otherwise it jumps in one event. No page-world JS is injected.
navigate
navigate(url: str) -> None
Navigate to url without waiting for any load event.
pdf_bytes
pdf_bytes() -> bytes
Render the page as a PDF and return the raw bytes.
query_ax_tree
query_ax_tree(role: str | None = None, name: str | None = None) -> list[dict[str, Any]]
Query the AX tree (Accessibility.queryAXTree) for matching nodes.
The semantic analogue of query_selector_all: addresses by computed
role / accessible name rather than markup. Name matching is
exact. Passing neither returns every node under the document root.
query_selector
query_selector(selector: str) -> str | None
Return inner HTML of the first matching element.
query_selector_all
query_selector_all(selector: str) -> list[str]
Return inner HTML of every matching element.
reset_download
reset_download() -> None
Reset this page’s CDP download behavior to Chrome’s default. Call to release an armed-but-unused capture (e.g. on an error path).
screenshot
screenshot(path: str | None = None, bbox: tuple[int, int, int, int] | None = None) -> bytes | str
Capture a PNG screenshot with optional disk output and/or crop. Args:
pathstr | None— If set, writes PNG to this path and returns the path. If omitted, returns raw bytes.bboxtuple[int, int, int, int] | None— Optional(x, y, width, height)in CSS pixels.
screenshot_png
screenshot_png() -> bytes
Capture a full-page screenshot as PNG bytes.
set_cookie
set_cookie(name: str, value: str, domain: str | None = None, path: str | None = None, secure: bool | None = None, http_only: bool | None = None) -> None
Set a cookie on the current page.
set_geolocation
set_geolocation(latitude: float, longitude: float, accuracy: float | None = None) -> None
Override geolocation and grant the geolocation permission.
navigator.geolocation reads require a secure context (https /
localhost), not data: URLs. accuracy defaults to 50 metres.
set_headers
set_headers(headers: dict[str, str]) -> None
Set extra HTTP headers for subsequent requests.
set_locale
set_locale(locale: str) -> None
Override the locale (Intl + Accept-Language), e.g. "fr-FR".
set_timezone
set_timezone(timezone_id: str) -> None
Override the timezone by IANA id, e.g. "America/New_York".
target_id
target_id() -> str
Return the CDP target id of this page (stable across same-tab
navigations). Pass to BrowserSession.attach_page to re-adopt
this exact tab from another connection.
title
title() -> str | None
Return the document title, or None.
type_into
type_into(selector: str, text: str) -> None
Focus and type text into the first matching element.
url
url() -> str | None
Return the current page URL, or None.
wait_download
wait_download(capture: DownloadCapture, timeout: float = 120.0) -> DownloadOutcome
Wait for the armed capture to land a new download. Resets the page’s download behavior. The capture is consumed (single wait).
wait_for_navigation
wait_for_navigation() -> None
Block until the current navigation completes.
wait_for_network_idle
wait_for_network_idle(timeout: float = 30.0) -> str | None
Wait for network activity to settle.
wait_for_selector
wait_for_selector(selector: str, timeout: float = 30.0) -> None
Wait until a CSS selector matches. Event-driven — no polling.
PooledTab
A tab checked out from a voidcrawl.BrowserPool.
Exposes the same page-interaction methods as Page but must
not be closed manually — return it to the pool via the async context
manager or voidcrawl.BrowserPool.release.
Attributes:
use_countint— How many times this tab has been acquired (0 on first use).
arm_download
arm_download(dir: str, max_bytes: int | None = None) -> DownloadCapture
Arm an action-triggered download capture; see Page.arm_download.
ax_box_in_frame
ax_box_in_frame(frame_url_pattern: str, role: str, name: str, nth: int = 0) -> list[float]
Locate an AX role + name inside a frame; return its on-page
rectangle [x, y, width, height] in CSS pixels.
Same cross-frame, closed-shadow-piercing resolution as
click_ax_in_frame, but returns the geometry instead of clicking
— so you can drive a humanized click yourself (curved approach via
dispatch_mouse_event, press at a jittered point in the box).
Empty name matches any node of that role.
ax_outline_in_frame
ax_outline_in_frame(frame_url_pattern: str, depth: int | None = None) -> str
Compact accessibility outline of a specific (possibly cross-origin)
frame — pierces closed shadow roots. Discover the role / accessible name
to pass to click_ax_in_frame.
ax_tree_outline
ax_tree_outline(depth: int | None = None) -> str
Return the AX tree as a compact, indented role "name" outline.
Readable counterpart to get_full_ax_tree: text-noise and hidden
nodes are pruned. Same output the MCP session_ax_tree tool renders.
click_ax_in_frame
click_ax_in_frame(frame_url_pattern: str, role: str, name: str, nth: int = 0, humanize: bool = False) -> None
Click an element by AX role + name inside a specific frame.
The cross-frame, shadow-piercing analogue of click_by_role:
roots the AX tree at the frame matched by frame_url_pattern and
descends into closed shadow roots, then clicks the match at its
box-model centre with a real compositor mouse event (a trusted
click, unlike a DOM .click()). Reaches widgets the page’s own JS
cannot — e.g. Cloudflare Turnstile’s “Verify you are human” checkbox in
a closed shadow root inside a cross-origin challenges.cloudflare.com
iframe. Empty name matches any node of that role.
Cross-origin google.com / cloudflare frames must be in-process: launch
the session with extra_args=["disable-site-isolation-trials"].
click_by_role
click_by_role(role: str, name: str, nth: int = 0, humanize: bool = False) -> None
Click the nth element matching accessibility role + name.
Markup-independent analogue of click_element: resolves via the AX
tree, bridges to the DOM, scrolls into view, and clicks. Raises if no
such node exists.
Args:
rolestr— Computed accessibility role, e.g."button","link".namestr— Computed accessible name (exact match).nthint— 0-based index when several nodes match.humanizebool— Click at the element’s box-model centre with a humanized compositor pointer path (curved, min-jerk, tremor) instead of a DOM.click(). Off by default.
click_element
click_element(selector: str) -> None
Click the first element matching selector. Args:
selectorstr— CSS selector string.
click_xy
click_xy(x: float, y: float, humanize: bool = False) -> None
Click at (x, y) with a trusted compositor event (press → release).
With humanize=True the cursor first travels a human-like path there
(see move_mouse). The programmatic analogue of the
click_visual_coords MCP tool.
content
content() -> str
Return the full page HTML (document.documentElement.outerHTML).
delete_cookie
delete_cookie(name: str, domain: str | None = None, path: str | None = None) -> None
Delete a cookie by name, optionally scoped to a domain and path. Args:
namestr— Cookie name.domainstr | None— Cookie domain.pathstr | None— Cookie path.
dispatch_key_event
dispatch_key_event(event_type: str, key: str | None = None, code: str | None = None, text: str | None = None, modifiers: int | None = None) -> None
Send a low-level CDP Input.dispatchKeyEvent.
Args:
event_typestr—"keyDown","keyUp","rawKeyDown", or"char".keystr | None— DOMKeyboardEvent.keyvalue (e.g."Enter").codestr | None— Physical key code (e.g."KeyA").textstr | None— Character to insert (e.g."a").modifiersint | None— Bit field for modifier keys.
dispatch_mouse_event
dispatch_mouse_event(event_type: str, x: float, y: float, button: str = 'left', click_count: int = 1, delta_x: float | None = None, delta_y: float | None = None, modifiers: int | None = None) -> None
Send a low-level CDP Input.dispatchMouseEvent.
Args:
event_typestr— One of"mousePressed","mouseReleased","mouseMoved", or"mouseWheel".xfloat— Horizontal page coordinate.yfloat— Vertical page coordinate.buttonstr—"left","right", or"middle".click_countint— Number of clicks (usually1).delta_xfloat | None— Horizontal scroll delta (mouseWheelonly).delta_yfloat | None— Vertical scroll delta (mouseWheelonly).modifiersint | None— Bit field for modifier keys (Ctrl=1, Shift=2, etc.).
download
download(url: str, dir: str, timeout: float = 120.0, max_bytes: int | None = None) -> DownloadOutcome
Download url into directory dir; see Page.download.
eval_js
eval_js(expression: str) -> object
Alias for evaluate_js — short form used by MCP tooling.
eval_js_in_frame
eval_js_in_frame(frame_url_pattern: str, expression: str) -> object
Alias for evaluate_js_in_frame.
evaluate_js
evaluate_js(expression: str) -> object
Evaluate a JavaScript expression and return the result. Args:
expressionstr— JavaScript expression or IIFE string.
evaluate_js_in_frame
evaluate_js_in_frame(frame_url_pattern: str, expression: str) -> object
Evaluate expression inside a (possibly cross-origin) iframe.
The frame is selected by a substring of its URL. The expression runs in
that frame’s own execution context (document is the frame’s
document) — the way to reach an iframe whose contentDocument is null
from the parent under the same-origin policy.
Args:
frame_url_patternstr— Substring of the target frame’s URL, e.g."recaptcha/api2/bframe".expressionstr— JavaScript expression or IIFE string.
Raises:
RuntimeError— if no frame matches, or the matched frame has no scriptable execution context.
frame_urls
frame_urls() -> list[str]
List the URLs of every frame on the page, in no particular order.
Handy for discovering the right frame_url_pattern to pass to
evaluate_js_in_frame.
get_cookies
get_cookies() -> list[dict[str, Any]]
Return all cookies matching the current page URL.
Each cookie is a dict with keys: name, value, domain,
path, expires, size, httpOnly, secure, session, etc.
get_full_ax_tree
get_full_ax_tree(depth: int | None = None) -> list[dict[str, Any]]
Return the browser-computed accessibility (AX) tree.
Wraps CDP Accessibility.getFullAXTree. The result is a flat list of
AX node dicts linked by childIds/parentId; each node carries
role, computed name, properties (state), and
backendDOMNodeId. Call after the page has rendered.
Args:
depthint | None— Maximum descendant depth to traverse.Nonereturns the whole tree.
goto
goto(url: str, timeout: float = 30.0, capture_endpoints: bool = False) -> PageResponse
Navigate to url and wait for network idle in one shot. Args:
urlstr— The URL to load.timeoutfloat— Maximum seconds to wait for network idle.capture_endpointsbool— WhenTrue, record the data-plane network endpoints (XHR + Fetch request URLs) seen during the load and surface them asPageResponse.endpoints— sanitized (query/fragment/userinfo stripped, secret-like path segments redacted), deduplicated, sorted, and capped.
Returns: PageResponse — class:PageResponse with HTML, final URL, status code, PageResponse — and redirect flag.
move_mouse
move_mouse(x: float, y: float, humanize: bool = False) -> None
Move the virtual cursor to (x, y) via CDP Input.dispatchMouseEvent.
With humanize=True the cursor travels a realistic curved, minimum-jerk,
lightly-tremored path (multiple MouseMoved events) from its last
position; otherwise it jumps in one event. No page-world JS is injected.
navigate
navigate(url: str) -> None
Navigate to url without waiting for any load event. Args:
urlstr— The URL to load.
query_ax_tree
query_ax_tree(role: str | None = None, name: str | None = None) -> list[dict[str, Any]]
Query the AX tree (Accessibility.queryAXTree) for matching nodes.
The semantic analogue of query_selector_all: addresses by computed
role / accessible name rather than markup. Name matching is
exact. Passing neither returns every node under the document root.
query_selector
query_selector(selector: str) -> str | None
Return the inner HTML of the first element matching selector, or None.
Args:
selectorstr— CSS selector string.
query_selector_all
query_selector_all(selector: str) -> list[str]
Return the inner HTML of every element matching selector. Args:
selectorstr— CSS selector string.
reset_download
reset_download() -> None
Reset this tab’s CDP download behavior to Chrome’s default.
screenshot_png
screenshot_png() -> bytes
Capture a full-page screenshot as PNG bytes.
set_cookie
set_cookie(name: str, value: str, domain: str | None = None, path: str | None = None, secure: bool | None = None, http_only: bool | None = None) -> None
Set a cookie on the current page. Args:
namestr— Cookie name.valuestr— Cookie value.domainstr | None— Cookie domain (default: current page domain).pathstr | None— Cookie path.securebool | None— Mark as Secure.http_onlybool | None— Mark as HttpOnly.
set_geolocation
set_geolocation(latitude: float, longitude: float, accuracy: float | None = None) -> None
Override geolocation and grant the geolocation permission.
navigator.geolocation reads require a secure context (https /
localhost), not data: URLs. accuracy defaults to 50 metres.
set_headers
set_headers(headers: dict[str, str]) -> None
Set extra HTTP headers for all subsequent requests from this tab. Args:
headersdict[str, str]— Header name-value pairs.
set_locale
set_locale(locale: str) -> None
Override the locale (Intl + Accept-Language), e.g. "fr-FR".
set_timezone
set_timezone(timezone_id: str) -> None
Override the timezone by IANA id, e.g. "America/New_York".
title
title() -> str | None
Return the document title, or None.
type_into
type_into(selector: str, text: str) -> None
Focus the first element matching selector and type text. Args:
selectorstr— CSS selector string.textstr— The text to type.
url
url() -> str | None
Return the current page URL, or None.
wait_download
wait_download(capture: DownloadCapture, timeout: float = 120.0) -> DownloadOutcome
Await an armed capture; see Page.wait_download.
wait_for_navigation
wait_for_navigation() -> None
Block until the current navigation completes.
wait_for_network_idle
wait_for_network_idle(timeout: float = 30.0) -> str | None
Wait for network activity to settle. Args:
timeoutfloat— Maximum seconds to wait.
Returns: str | None — "networkIdle" or "networkAlmostIdle" on success, str | None — None on timeout.
wait_for_selector
wait_for_selector(selector: str, timeout: float = 30.0) -> None
Wait until a CSS selector matches. Event-driven — no polling.
Raises VoidCrawlError if timeout seconds elapse
without a match.
Action Framework
ActionNode
Abstract base for all browser actions.
Subclass and implement run to create a custom action. Use
JsActionNode when the action can be expressed as a single
JavaScript snippet; subclass ActionNode directly for CDP-level
actions that need voidcrawl.actions.Tab.dispatch_mouse_event
or voidcrawl.actions.Tab.dispatch_key_event.
run
run(tab: Tab) -> object
Execute this action against tab. Args:
tabTab— Any object satisfying thevoidcrawl.actions.Tabprotocol (e.g.PageorPooledTab).
Returns: object — The action result — type varies by action.
Flow
An ordered sequence of actions executed against a single tab.
Actions run sequentially in the order added; each result is captured
in the returned FlowResult.
Args:
actionslist[ActionNode] | None— Initial list of actions. May beNoneor omitted to start with an empty flow and useadd.
add
add(action: ActionNode) -> Flow
Append an action and return self for chaining. Args:
actionActionNode— The action to append.
Returns: Flow — This instance, for builder-style chaining.
run
run(tab: Tab) -> FlowResult
Execute all actions sequentially against tab.
When tab is a voidcrawl.debug.DebugPage (i.e. the
session was started with BrowserConfig(debug=True)), execution
is automatically routed through an interactive
voidcrawl.debug.DebugSession instead of running silently.
Args:
tabTab— Any object satisfying theTabprotocol.
Returns: FlowResult — One result per action.
FlowResult
Aggregated result of a Flow execution.
Attributes:
resultslist[object]— Ordered list of return values, one per action.lastobject— The return value of the final action, orNonefor empty flows (read-only property).
JsActionNode
Action executed by evaluating a JavaScript snippet in the page.
Subclasses set the js class attribute (via load_js or
inline_js) and store their parameters as instance attributes
in __init__. At execution time, all instance attributes are
serialised to JSON and injected as the __params object visible
inside the snippet.
By default params returns vars(self); override it only
if you need to transform or filter attributes.
params
params() -> dict[str, Any]
Return the parameters injected as __params in the JS snippet.
Defaults to vars(self). Override to transform, rename, or
filter attributes before they reach JavaScript.
Returns: dict[str, Any] — A JSON-serialisable dict of parameter names to values.
run
run(tab: JsTab) -> object
Evaluate the JS snippet in tab with the current params.
Args:
tabJsTab— Any object satisfyingvoidcrawl.actions.JsTab.
Returns: object — The JSON-deserialised return value from the snippet.
JsSource
Immutable wrapper around a JavaScript snippet string.
Created via load_js (file-based) or inline_js
(string literal). Used as the js class attribute on
JsActionNode subclasses.
Args:
jsstr— Raw JavaScript source code.
JsTab
Minimal protocol for JavaScript-only actions.
Any object with an async evaluate_js method satisfies this
protocol — including Page, PooledTab, and test
mocks. Used by voidcrawl.actions.JsActionNode.
eval_js
eval_js(expression: str) -> object
Alias for evaluate_js — short form used by MCP tooling.
Args:
expressionstr— JavaScript expression or IIFE string.
Returns: object — The JSON-deserialised return value from the browser.
evaluate_js
evaluate_js(expression: str) -> object
Evaluate a JavaScript expression in the page and return the result. Args:
expressionstr— JavaScript expression or IIFE string.
Returns: object — The JSON-deserialised return value from the browser.
Tab
Full protocol covering JS evaluation and CDP input commands.
Both Page and PooledTab satisfy this protocol.
CDP-level actions (e.g. voidcrawl.actions.CdpClick) require
this protocol rather than the simpler JsTab.
dispatch_key_event
dispatch_key_event(event_type: str, key: str | None = None, code: str | None = None, text: str | None = None, modifiers: int | None = None) -> None
Send a low-level CDP Input.dispatchKeyEvent.
Args:
event_typestr—"keyDown","keyUp","rawKeyDown", or"char".keystr | None— DOMKeyboardEvent.keyvalue (e.g."Enter").codestr | None— Physical key code (e.g."KeyA").textstr | None— Character to insert (e.g."a").modifiersint | None— Bit field for modifier keys.
dispatch_mouse_event
dispatch_mouse_event(event_type: str, x: float, y: float, button: str = 'left', click_count: int = 1, delta_x: float | None = None, delta_y: float | None = None, modifiers: int | None = None) -> None
Send a low-level CDP Input.dispatchMouseEvent.
Args:
event_typestr— One of"mousePressed","mouseReleased","mouseMoved", or"mouseWheel".xfloat— Horizontal page coordinate.yfloat— Vertical page coordinate.buttonstr— Mouse button —"left","right", or"middle".click_countint— Number of clicks (usually1).delta_xfloat | None— Horizontal scroll delta (mouseWheelonly).delta_yfloat | None— Vertical scroll delta (mouseWheelonly).modifiersint | None— Bit field for modifier keys (Ctrl=1, Shift=2, etc.).
inline_js
inline_js(code: str) -> JsSource
Create a JsSource from an inline string literal.
Args:
codestr— Raw JavaScript source code.
Returns: JsSource — The wrapped JavaScript source.
load_js
load_js(path: str | Path) -> JsSource
Load JavaScript from a .js file on disk.
Absolute paths are used as-is. Relative paths are resolved from the
caller’s source file, so load_js("click_at.js") works when
the .js lives next to the calling .py.
Args:
pathstr | Path— Filesystem path to the.jsfile.
Returns: JsSource — The loaded JavaScript source.
Built-in Actions
AntibotChallenge
An anti-bot vendor is actively challenging the response.
Signature-based (header/status/body), distinct from the DOM-based
CaptchaDetected. Not raised on the fetch / fetch_many
path — those surface the verdict as the non-fatal
PageResponse.antibot annotation instead; this is reserved for
explicit detect/routing callers that opt into failing on a wall.
AntibotVerdict
Signature-based anti-bot / CDN vendor fingerprint of a response. Attributes:
vendorslist[str]— Canonical vendor tags detected (e.g."cloudflare","datadome"), sorted.challengedbool—Truewhen an active wall/challenge fired (rotate), vs. mere CDN presence (no action needed).challenge_vendorstr | None— Vendor whose challenge fired, whenchallenged.corpus_versionstr— Signature corpus the verdict was produced against — record alongside captures for replay-grade provenance.evidencestr— Which tier matched —"none"/"headers"/"body".
Attr
Attr(css: str, attr: str, sanitize: Callable[[str | None], str | None] | None = None) -> Any
Declare a field extracted from an element attribute.
CSS selectors are validated at class-definition time; strings
containing <, >, or null bytes raise ValueError.
Args:
cssstr— CSS sub-selector relative to the root element. Pass""to target the root element itself.attrstr— HTML attribute name (e.g."href","src").sanitizeCallable[[str | None], str | None] | None— Optional callable applied to the extracted value before Pydantic validation. Usesafe_urlto block dangerous URL schemes on link/image fields.
Returns: Any — A Pydantic FieldInfo carrying the selector, attribute, and Any — sanitizer metadata.
BrowserClosedError
CaptchaDetected
DOM markers indicate a captcha / bot-wall challenge on the page.
CapturedResponse
A passively observed response with an opt-in bounded body.
bytes
bytes() -> bytes
json
json() -> Any
text
text() -> str
CdpClick
Click at (x, y) via CDP Input.dispatchMouseEvent.
Sends a mousePressed followed by mouseReleased. More
realistic than JS-level clicks — useful for pages that inspect
event coordinates.
Args:
xfloat— Horizontal page coordinate.yfloat— Vertical page coordinate.buttonstr— Mouse button —"left","right", or"middle".
run
run(tab: Tab) -> None
Dispatch mousePressed then mouseReleased at (x, y).
Args:
tabTab— Tab-like object to send the click events to.
CdpClickAndHold
Mouse-down, hold for duration_ms, then mouse-up via CDP.
Useful for triggering long-press menus or drag initialisation. Args:
xfloat— Horizontal page coordinate.yfloat— Vertical page coordinate.duration_msint— How long to hold the button, in milliseconds.buttonstr— Mouse button —"left","right", or"middle".
run
run(tab: Tab) -> None
Press, hold for duration_ms, then release at (x, y).
Args:
tabTab— Tab-like object to send the mouse events to.
CdpHover
Move the virtual mouse cursor to (x, y) via CDP.
Sends a mouseMoved event. Unlike Hover, this moves
the actual CDP cursor position, which is needed for subsequent
CdpClick calls to land correctly.
Args:
xfloat— Horizontal page coordinate.yfloat— Vertical page coordinate.
run
run(tab: Tab) -> None
Dispatch a mouseMoved event to (x, y).
Args:
tabTab— Tab-like object to send the hover event to.
CdpScroll
Scroll via a CDP mouseWheel event fired at (x, y).
For most use cases prefer the convenience subclasses
CdpScrollDown, CdpScrollUp,
CdpScrollLeft, and CdpScrollRight.
Args:
xfloat— Horizontal page coordinate for the wheel event origin.yfloat— Vertical page coordinate for the wheel event origin.delta_xfloat— Horizontal scroll amount (positive = right).delta_yfloat— Vertical scroll amount (positive = down).
run
run(tab: Tab) -> None
Dispatch a mouseWheel event at (x, y).
Args:
tabTab— Tab-like object to send the scroll event to.
CdpScrollDown
Scroll down by pixels at (x, y) via CDP.
Args:
pixelsfloat— Distance to scroll in pixels. Defaults to100.xfloat— Horizontal origin for the wheel event.yfloat— Vertical origin for the wheel event.
CdpScrollLeft
Scroll left by pixels at (x, y) via CDP.
Args:
pixelsfloat— Distance to scroll in pixels. Defaults to100.xfloat— Horizontal origin for the wheel event.yfloat— Vertical origin for the wheel event.
CdpScrollRight
Scroll right by pixels at (x, y) via CDP.
Args:
pixelsfloat— Distance to scroll in pixels. Defaults to100.xfloat— Horizontal origin for the wheel event.yfloat— Vertical origin for the wheel event.
CdpScrollUp
Scroll up by pixels at (x, y) via CDP.
Args:
pixelsfloat— Distance to scroll in pixels. Defaults to100.xfloat— Horizontal origin for the wheel event.yfloat— Vertical origin for the wheel event.
CdpTypeText
Type text character-by-character via CDP Input.dispatchKeyEvent.
Each character produces a keyDown/keyUp pair. This is more
realistic than SetInputValue and triggers per-keystroke
event listeners.
Args:
textstr— The string to type.
run
run(tab: Tab) -> None
Dispatch keyDown/keyUp pairs for each character in text.
Args:
tabTab— Tab-like object to send the key events to.
ChromeProfileBusy
Chrome’s own SingletonLock prevented profile launch.
ClearInput
Clear an input field and fire an input event via JS.
Args:
selectorstr— CSS selector targeting the<input>or<textarea>.
ClickAt
Click the element at page coordinates (x, y) via JS events.
Uses document.elementFromPoint to resolve the target and
dispatches synthetic mouse events.
Args:
xint— Horizontal page coordinate (pixels from left).yint— Vertical page coordinate (pixels from top).
ClickElement
Click the first element matching a CSS selector via JS.
Raises a JS Error if no element matches.
Args:
selectorstr— CSS selector string (e.g."#submit-btn").
CollectNetworkRequests
Retrieve all network entries captured by InstallNetworkObserver.
Returns a list of dicts, each containing:
name— the full URL of the requesttype— the initiator type ("script","img","fetch", etc.)duration— round-trip time in millisecondssize— transfer size in bytes (0 if unavailable)
Pass clear=True to reset the log after collection.
GetAttribute
Read an HTML attribute from the first matching element.
Returns None if the element is not found. The result is
available as the return value of run (str | None).
Args:
selectorstr— CSS selector targeting the element.attrstr— Attribute name (e.g."href","data-id").
run
run(tab: JsTab) -> str | None
GetText
Read textContent from the first matching element.
Returns None if the element is not found. The result is
available as the return value of run (str | None).
Args:
selectorstr— CSS selector targeting the element.
run
run(tab: JsTab) -> str | None
Hover
Dispatch mouseenter + mouseover on an element via JS.
Triggers CSS :hover styles and JS hover handlers without
moving the CDP-level cursor.
Args:
selectorstr— CSS selector targeting the element to hover.
InstallNetworkObserver
Install a PerformanceObserver that records network requests.
Call this after navigation completes (e.g. after
wait_for_network_idle). The observer uses buffered: true
to retroactively capture all resource entries from the current
navigation, plus any future requests.
Use CollectNetworkRequests to retrieve the captured entries.
The observer stores entries on window.__vc_network_log.
params
params() -> dict[str, object]
ManagedProfileSnapshot
close
close() -> None
ManagedProfileSplit
close
close() -> None
NavigationError
NavigationTimeoutError
PageResponse
Result of Page.goto / PooledTab.goto.
Attributes:
htmlstr— Full outer HTML after network idle.urlstr— Final URL after any redirects.status_codeint | None— HTTP status of the last response, orNonewhen served from cache / service worker.redirectedbool—Truewhen at least one HTTP redirect occurred.headersdict[str, str]— Final Document response headers (lowercased names; last value wins on duplicates). Empty when no network response was captured.antibotAntibotVerdict | None— Anti-bot / CDN vendor fingerprint, orNonewhen no network response was captured.endpointslist[str] | None— Data-plane network endpoints (XHR + Fetch request URLs) — a sorted, deduplicated set ofscheme://host/pathwith query, fragment, and userinfo stripped and secret-like path segments redacted at the source.Noneunlesscapture_endpoints=Truewas passed togoto;[]when requested but none were seen.endpoints_truncatedbool—Truewhen the endpoint set hit its cap and further endpoints were dropped.endpoint_sanitizer_versionstr | None— Which redaction-rule version producedendpoints(record it alongside the set for replay-grade provenance).NoneiffendpointsisNone.
ProfileBusy
Another voidcrawl process holds the profile lock (non-blocking acquire).
ProfileHandle
Live lease on a Chrome profile.
Use as an async context manager, or call release explicitly.
Obtain one via voidcrawl.acquire_profile or
voidcrawl.with_profile.
new_page
new_page(url: str) -> Page
path
path() -> str
release
release() -> None
ProfileLeaseExpired
Timed out waiting for the profile lock.
ProfileNotFound
No matching profile directory in the platform default dirs.
ProfileRegistry
VoidCrawl-managed standalone Chromium profile registry.
Profiles live under $VOIDCRAWL_PROFILE_ROOT or the platform data-dir
default, and each profile path is a standalone Chrome user_data_dir.
Methods return metadata only; cookie and localStorage values are never read.
clone_profile
clone_profile(source_id_or_path: str, id: str, description: str | None = None, labels: tuple[str, ...] | list[str] = ()) -> dict[str, object]
create_pool
create_pool(name: str, profile_ids: list[str] | tuple[str, ...], max_active: int = 3) -> dict[str, object]
create_profile
create_profile(id: str, description: str | None = None, labels: tuple[str, ...] | list[str] = ()) -> dict[str, object]
default
default() -> ProfileRegistry
delete_profile
delete_profile(id: str) -> bool
describe_profile
describe_profile(id: str) -> dict[str, object]
fork_profile
fork_profile(source: str = 'Default', copies: int = 2) -> ManagedProfileSplit
Fork a closed native Chrome profile into concurrent instances.
source may be a discovered profile name such as "Default" or
an explicit native profile-directory path. The source Chrome must be
closed so its cookie databases and storage are quiescent. Each result
is a temporary standalone user_data_dir containing the selected
profile as Default plus Chrome’s root Local State metadata.
The copies start with the same login state and profile identity, then intentionally diverge. They are deleted when the async context exits.
list_pools
list_pools() -> list[dict[str, object]]
list_profiles
list_profiles() -> list[dict[str, object]]
resolve_pool
resolve_pool(name: str) -> dict[str, object]
snapshot_profile
snapshot_profile(id: str) -> ManagedProfileSnapshot
Create a quiesced, temporary clone that cleans itself up.
Use the returned object as an async context manager. The source’s OS lease is held while copying; lock and Chrome Singleton files are excluded from the snapshot.
split_profile
split_profile(id: str, copies: int = 2) -> ManagedProfileSplit
Prepare isolated copies of one profile for concurrent Chrome instances.
The returned async context manager performs the copy work off the
asyncio thread. It takes one source lease across the complete split, so
every copy starts from the same quiesced baseline. Each path is a
separate Chrome user_data_dir and can therefore run concurrently
without a SingletonLock conflict.
This is copy-on-start isolation, not live synchronization: cookies, storage, and other writes diverge once the Chrome instances launch and are not merged back into the source.
Example::
async with registry.split_profile("work", copies=2) as split: first_path, second_path = split.paths # Launch one BrowserSession per path.QueryAll
Query all elements matching selector and extract fields from each.
Each entry in fields maps a result key to either:
- a CSS sub-selector string — the matched element’s
textContent(trimmed) is returned, orNoneif nothing matches. - a
(sub_selector, attr)tuple — the named attribute of the matched element is returned, orNoneif nothing matches.
Pass an empty string "" as the sub-selector to target the root
element itself rather than a descendant.
Pass a voidcrawl.schema.Schema subclass as fields
to receive typed model instances instead of raw dicts.
Args:
selectorstr— CSS selector for the root elements to iterate over.fieldsdict[str, str | tuple[str, str]] | type[Schema]— Mapping of result key → sub-selector or(sub_selector, attribute)tuple, or avoidcrawl.schema.Schemasubclass whose field declarations are used automatically.
Example — raw dicts::
QueryAll( ".article", {"title": "h2", "url": ("a", "href"), "date": ".byline"},)Example — typed Schema::
class Article(vc.Schema): title: str = vc.Text("h2") url: str | None = vc.Attr("a", "href")
QueryAll(".article", Article)params
params() -> dict[str, Any]
run
run(tab: JsTab) -> list[_T]
ResponseExpectation
Async context returned by Page.expect_response(s).
ResponseTimeoutError
ScaleReport
Computed pool recommendations for a profile and resource snapshot.
print_report
print_report() -> None
Print a human-readable summary. Uses rich markup if available.
to_dict
to_dict() -> dict[str, object]
Serialise to a JSON-compatible dict (for --json scripted mode).
to_pool_config
to_pool_config() -> PoolConfig
Convert to a voidcrawl.PoolConfig ready for
voidcrawl.BrowserPool.
Schema
Base class for declarative DOM extraction models.
Subclass this and annotate fields with Text or Attr
to declare how each field is extracted from the DOM. Pass the
subclass to voidcrawl.actions.QueryAll to receive typed
instances instead of raw dicts.
Example::
class Article(Schema): headline: str = Text("h2") url: str | None = Attr("a", "href", sanitize=safe_url) excerpt: str | None = Text(".summary", sanitize=strip_tags)ScrollBy
Scroll the window by a relative offset via window.scrollBy.
Args:
dxint— Horizontal delta in pixels (positive = right). Defaults to0.dyint— Vertical delta in pixels (positive = down). Defaults to0.
ScrollTo
Scroll the window to an absolute position via window.scrollTo.
Args:
xint— Horizontal scroll offset in pixels. Defaults to0.yint— Vertical scroll offset in pixels. Defaults to0.
SelectOption
Select a <select> option by value and fire a change event.
Args:
selectorstr— CSS selector targeting the<select>element.valuestr— Thevalueattribute of the<option>to select.
SetAttribute
Set an HTML attribute on the first matching element.
Raises a JS Error if no element matches the selector.
Args:
selectorstr— CSS selector targeting the element.attrstr— Attribute name to set.valuestr— Attribute value to assign.
run
run(tab: JsTab) -> None
SetInputValue
Bulk-set an input’s value and fire input/change events.
This does not simulate individual keystrokes — use
CdpTypeText for realistic per-character typing.
Args:
selectorstr— CSS selector targeting the<input>or<textarea>.textstr— The value to assign.
Text
Text(css: str, sanitize: Callable[[str | None], str | None] | None = None) -> Any
Declare a field extracted from an element’s textContent.
The css string is a sub-selector relative to the root element
matched by voidcrawl.actions.QueryAll’s selector
argument. Pass "" to target the root element itself.
CSS selectors are validated at class-definition time; strings
containing <, >, or null bytes raise ValueError.
Args:
cssstr— CSS sub-selector whosetextContent(trimmed) is used as the field value.Noneis returned when no element matches.sanitizeCallable[[str | None], str | None] | None— Optional callable applied to the extracted value before Pydantic validation. Usesafe_urlorstrip_tags, or supply your own(str | None) -> str | Nonefunction.
Returns: Any — A Pydantic FieldInfo carrying the selector and sanitizer Any — metadata.
VoidCrawlError
Base class for all voidcrawl errors raised from the native extension.
WaitForSelector
Poll until a CSS selector matches an element, with timeout.
Polls at a short interval inside the browser context. Resolves as
soon as document.querySelector(selector) is non-null, or throws
a JS Error when timeout seconds elapse.
Args:
selectorstr— CSS selector to wait for.timeoutfloat— Maximum wait time in seconds. Defaults to10.0.
WaitForTimeout
Sleep for ms milliseconds inside the browser context.
This pauses the JS execution inside the page, not the Python event loop. Useful for waiting on animations or debounced handlers. Args:
msint— Delay in milliseconds.
acquire_profile
acquire_profile(name: str, lease_timeout: float = 300.0, headless: bool = True) -> ProfileHandle
Acquire an exclusive lease on a Chrome profile. Args:
namestr— Profile directory name as Chrome stores it (e.g."Default","Profile 1").lease_timeoutfloat— Seconds to poll for the lock before giving up.0means fail immediately if busy.headlessbool— Run Chrome in headless mode (default). SetFalsefor a visible window — useful for a one-time manual login before the profile is used for scraping.
Raises:
ProfileBusy— Another voidcrawl process holds the lock and the timeout is zero.ProfileLeaseExpired— Timed out waiting for the lock.ProfileNotFound— No matching profile directory in the platform default dirs.
list_profiles
list_profiles() -> list[tuple[str, str]]
Return [(name, path), ...] for every Chrome profile discovered.
Only directories containing a Preferences file are returned.
safe_url
safe_url(value: str | None) -> str | None
Return None for javascript:, data:, and vbscript: URLs.
Use this on any Attr field that extracts a URL (href,
src, action, etc.) to prevent unsafe schemes from propagating.
Args:
valuestr | None— Raw attribute value from the DOM, orNone.
Returns: str | None — The original value, or None if a dangerous scheme was detected.
strip_tags
strip_tags(value: str | None) -> str | None
Strip HTML tag-like substrings from value.
Useful when a field may contain inline markup — removes anything that
looks like <tag> or </tag> using a simple regex. Not a full
HTML sanitiser; use on plain-text fields that shouldn’t contain markup.
Args:
valuestr | None— Raw text value from the DOM, orNone.
Returns: str | None — The value with tag-like substrings removed, or None unchanged.
with_profile
with_profile(name: str, lease_timeout: float = 300.0, headless: bool = True) -> AsyncIterator[ProfileHandle]
Async context manager: acquire, yield, release.
Example::
async with with_profile("Default") as handle: page = await handle.new_page("https://linkedin.com/in/me") html = await page.content()Pass headless=False to see the Chrome window (e.g. for a
manual login flow).
Debug
DebugSession
Interactive step debugger for browser actions.
Queue actions via add (or add_flow), then call
start to execute them with an interactive debug control.
Args:
tabTab— The page or pooled tab to run actions against.start_urlstr | None— URL to navigate to when rewinding. Required for back/restart — if omitted those commands are disabled.steppingbool— IfTrue(default), pause before every action. IfFalse, run freely and only pause at breakpoints.step_delayfloat— Seconds to wait after each action in non-stepping mode (ignored when paused at a prompt). Defaults to0.3.highlightbool— Flash a CSS outline on selector-targeted elements before executing the action. Defaults toTrue.nav_settle_secsfloat— Seconds to wait after triggering a rewind navigation before replaying actions. Increase if pages are slow to load. Defaults to0.5.
add
add(action: ActionNode) -> DebugSession
Append a single action to the execution queue. Args:
actionActionNode— The action to enqueue.
Returns: DebugSession — This session, for chaining.
add_flow
add_flow(flow: Flow) -> DebugSession
Append every action from a Flow to the queue.
Args:
flowFlow— The flow whose actions to enqueue.
Returns: DebugSession — This session, for chaining.
start
start() -> FlowResult
Run the queued actions with interactive debug control.
Prints a command prompt before each action (or only at breakpoints, depending on stepping). The user can type:
- n / Enter — execute the current action and advance
- c — continue running until the next breakpoint
- b — rewind one step (re-navigates and replays)
- r — restart from the beginning
- l — list all queued actions with position marker
- h — show history of executed actions and results
- q — quit the session early
Returns:
FlowResult— Aggregated results collected so far.
vc_breakpoint
vc_breakpoint() -> _T
Mark an action class as a debugger breakpoint.
When a DebugSession encounters an action whose class is
marked with this decorator, it pauses execution regardless of
whether stepping mode is active.
Args:
cls_T— The action class to mark.
Returns: _T — The same class, with an internal marker attribute set.