API Reference
API Reference
Generated from voidcrawl
v0.0.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 :class:BrowserSession or
embed one inside :class: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.ws_urlstr | None: Connect to an already-running Chrome instance via its WebSocket debugger URL instead of launching a new one.
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.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: Shared :class:BrowserConfigapplied to every Chrome process launched by the pool.
from_env
from_env() -> PoolConfig
Build a :class: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 |
+------------------------+---------------------------------+---------+
| CHROME_NO_SANDBOX | Set to "1" to disable | - |
+------------------------+---------------------------------+---------+
| CHROME_HEADLESS | Set to "0" for headful | 1 |
+------------------------+---------------------------------+---------+
Returns: PoolConfig. A fully-populated :class:PoolConfig.
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
:attr:PoolConfig.tab_max_uses navigations and evicted after
:attr: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 :class: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 :meth: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 :attr: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).
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) -> Page
Open a new tab and navigate to url. Args:
urlstr: The URL to load in the new tab.
Returns: Page. class:Page handle for the new tab.
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.
Page
A single browser tab created via :meth:BrowserSession.new_page.
Provides navigation, content extraction, JavaScript evaluation, media capture, DOM queries, user-interaction helpers, and low-level CDP input dispatch.
click_element
click_element(selector: str) -> None
Click the first element matching selector. Args:
selectorstr: CSS selector string.
close
close() -> None
Close this tab and release its resources.
content
content() -> str
Return the full page HTML (document.documentElement.outerHTML).
Returns: str. The complete outer HTML of the document element.
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.).
evaluate_js
evaluate_js(expression: str) -> object
Evaluate a JavaScript expression and return the result.
The return value is deserialised to a native Python type
(dict, list, str, int, float, bool, or None).
Args:
expressionstr: JavaScript expression or IIFE string.
Returns: object. The deserialised result of the expression.
goto
goto(url: str, timeout: float = 30.0) -> str | None
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.
Returns: str | None. "networkIdle" or "networkAlmostIdle" on success, or None on timeout.
navigate
navigate(url: str) -> None
Navigate to url without waiting for any load event. Args:
urlstr: The URL to load.
pdf_bytes
pdf_bytes() -> bytes
Render the page as a PDF and return the raw bytes.
Only works in headless mode.
Returns: bytes. Raw PDF file data.
query_selector
query_selector(selector: str) -> str | None
Return the outer HTML of the first element matching selector, or None.
Args:
selectorstr: CSS selector string.
Returns: str | None. Outer HTML string of the matched element, or None if no match.
query_selector_all
query_selector_all(selector: str) -> list[str]
Return the outer HTML of every element matching selector. Args:
selectorstr: CSS selector string.
Returns: list[str]. List of outer HTML strings, one per matched element.
screenshot_png
screenshot_png() -> bytes
Capture a full-page screenshot as PNG bytes.
Returns: bytes. Raw PNG image data.
set_headers
set_headers(headers: dict[str, str]) -> None
Set extra HTTP headers for all subsequent requests from this page. Args:
headersdict[str, str]: Header name-value pairs.
title
title() -> str | None
Return the document title, or None.
Returns: str | None. The document.title string, or None if unavailable.
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.
Returns: str | None. The page URL as a string, or None if unavailable.
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, or None on timeout.
wait_for_stable_dom
wait_for_stable_dom(timeout: float = 10.0, min_length: int = 5000, stable_checks: int = 5) -> bool
Wait until the DOM stabilises (stops changing).
Polls the HTML length repeatedly and resolves once it stays constant across stable_checks consecutive checks. Args:
timeoutfloat: Maximum seconds to wait.min_lengthint: Minimum HTML length before checking stability.stable_checksint: Consecutive unchanged polls required.
Returns: bool. True if the DOM stabilised, False on timeout.
PooledTab
A tab checked out from a :class:~voidcrawl.BrowserPool.
Exposes the same page-interaction methods as :class:Page but must
not be closed manually; return it to the pool via the async context
manager or :meth:~voidcrawl.BrowserPool.release.
Attributes:
use_countint: How many times this tab has been acquired (0 on first use).
click_element
click_element(selector: str) -> None
Click the first element matching selector. Args:
selectorstr: CSS selector string.
content
content() -> str
Return the full page HTML (document.documentElement.outerHTML).
Returns: str. The complete outer HTML of the document element.
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.).
evaluate_js
evaluate_js(expression: str) -> object
Evaluate a JavaScript expression and return the result.
The return value is deserialised to a native Python type
(dict, list, str, int, float, bool, or None).
Args:
expressionstr: JavaScript expression or IIFE string.
Returns: object. The deserialised result of the expression.
goto
goto(url: str, timeout: float = 30.0) -> str | None
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.
Returns: str | None. "networkIdle" or "networkAlmostIdle" on success, or None on timeout.
navigate
navigate(url: str) -> None
Navigate to url without waiting for any load event. Args:
urlstr: The URL to load.
query_selector
query_selector(selector: str) -> str | None
Return the outer HTML of the first element matching selector, or None.
Args:
selectorstr: CSS selector string.
Returns: str | None. Outer HTML string of the matched element, or None if no match.
query_selector_all
query_selector_all(selector: str) -> list[str]
Return the outer HTML of every element matching selector. Args:
selectorstr: CSS selector string.
Returns: list[str]. List of outer HTML strings, one per matched element.
screenshot_png
screenshot_png() -> bytes
Capture a full-page screenshot as PNG bytes.
Returns: bytes. Raw PNG image data.
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.
title
title() -> str | None
Return the document title, or None.
Returns: str | None. The document.title string, or None if unavailable.
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.
Returns: str | None. The page URL as a string, or None if unavailable.
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, or None on timeout.
wait_for_stable_dom
wait_for_stable_dom(timeout: float = 10.0, min_length: int = 5000, stable_checks: int = 5) -> bool
Wait until the DOM stabilises (stops changing).
Polls the HTML length repeatedly and resolves once it stays constant across stable_checks consecutive checks. Args:
timeoutfloat: Maximum seconds to wait.min_lengthint: Minimum HTML length before checking stability.stable_checksint: Consecutive unchanged polls required.
Returns: bool. True if the DOM stabilised, False on timeout.
Action Framework
ActionNode
Abstract base for all browser actions.
Subclass and implement :meth:run to create a custom action. Use
:class:JsActionNode when the action can be expressed as a single
JavaScript snippet; subclass ActionNode directly for CDP-level
actions that need :meth:~voidcrawl.actions.Tab.dispatch_mouse_event
or :meth:~voidcrawl.actions.Tab.dispatch_key_event.
run
run(tab: Tab) -> object
Execute this action against tab. Args:
tabTab: Any object satisfying the :class:~voidcrawl.actions.Tabprotocol (e.g. :class:Pageor :class:PooledTab).
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 :class:FlowResult.
Args:
actionslist[ActionNode] | None: Initial list of actions. May beNoneor omitted to start with an empty flow and use :meth:add.
add
add(action: ActionNode) -> Flow
Append an action and return self for chaining. Args:
actionActionNode: The action to append.
Returns: Flow. class:Flow instance (for builder-style chaining).
run
run(tab: Tab) -> FlowResult
Execute all actions sequentially against tab. Args:
tabTab: Any object satisfying the :class:~voidcrawl.actions.Tabprotocol.
Returns: FlowResult. class:FlowResult containing one result per action.
FlowResult
Aggregated result of a :class: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 :func:load_js or
:func: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 :meth: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 :meth:params.
Args:
tabJsTab: Any object satisfying :class:~voidcrawl.actions.JsTab.
Returns: object. The JSON-deserialised return value from the snippet.
JsSource
Immutable wrapper around a JavaScript snippet string.
Created via :func:load_js (file-based) or :func:inline_js
(string literal). Used as the js class attribute on
:class: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 :class:Page, :class:PooledTab, and test
mocks. Used by :class:~voidcrawl.actions.JsActionNode.
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 :class:Page and :class:PooledTab satisfy this protocol.
CDP-level actions (e.g. :class:~voidcrawl.actions.CdpClick) require
this protocol rather than the simpler :class: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 :class:JsSource from an inline string literal.
Args:
codestr: Raw JavaScript source code.
Returns: JsSource. class:JsSource wrapping code.
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. class:JsSource containing the file contents.
Built-in Actions
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 :class:Hover, this moves
the actual CDP cursor position, which is needed for subsequent
:class: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
:class:CdpScrollDown, :class:CdpScrollUp,
:class:CdpScrollLeft, and :class: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 :class: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.
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").
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 :meth:run (str | None).
Args:
selectorstr: CSS selector targeting the element.attrstr: Attribute name (e.g."href","data-id").
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 :meth:run (str | None).
Args:
selectorstr: CSS selector targeting the element.
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.
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.
SetInputValue
Bulk-set an input’s value and fire input/change events.
This does not simulate individual keystrokes; use
:class:CdpTypeText for realistic per-character typing.
Args:
selectorstr: CSS selector targeting the<input>or<textarea>.textstr: The value to assign.
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.