Higher-level CDP abstraction methods injected by cdp.lua for convenience.
These are plain Lua functions - you can override or extend them on any page object.
page:open(url, [wait_until], [timeout_ms]) async
Navigate to a URL. wait_until is a CDP event name (default
"Page.loadEventFired"). Pass false to skip waiting.
Returns true or nil, error.
-- Default: wait for full load (30s timeout)
local ok, err = page:open("https://example.com")
-- Wait for DOM content instead of full load
page:open("https://example.com", "Page.domContentEventFired")
-- Custom timeout
page:open("https://example.com", "Page.loadEventFired", 15000)
-- Fire-and-forget: navigate without waiting
page:open("https://example.com", false)
page:wait_for_selector(selector, [opts]) async
Poll the DOM until a CSS selector exists. Supports shadow DOM and iframe
traversal. opts can be a number (timeout_ms) or a table.
| Option |
Type |
Default |
Description |
timeout_ms |
number |
10000 |
Max wait time in milliseconds. |
poll_ms |
number |
100 |
Poll interval in milliseconds. |
visible |
boolean |
false |
Only return true if the element is visible. |
scroll |
boolean |
true |
Scroll to the element or scroll down if not found. |
-- Simple timeout
local found, info = page:wait_for_selector(".content", 5000)
-- Full options
local found, info = page:wait_for_selector(".product", {
timeout_ms = 15000,
poll_ms = 200,
visible = true,
scroll = true
})
if found then
print("Tag: " .. info.tagName)
print("Text: " .. info.text)
end
page:wait_for_url(pattern, timeout_ms) async
Polls location.href until it matches the string
pattern. Returns the URL or nil, error.
-- Wait until the URL contains "/success"
local url = page:wait_for_url("/success", 10000)
if url then
print("Redirected to: " .. url)
end
page:wait_for_response([predicate], [timeout_ms]) async
Waits for Network.responseReceived. Optional
predicate function receives the event params, return true
when the desired response is found.
-- Wait for any response
local resp = page:wait_for_response(nil, 5000)
-- Wait for a specific API response
local resp = page:wait_for_response(function(params)
return params.response.url:find("/api/data") and params.response.status == 200
end, 10000)
page:wait_for_idle([timeout_ms], [quiet_ms]) async
Waits until the network has been quiet for quiet_ms (default
500). Uses performance.getEntriesByType("resource") to check for
in-flight requests.
-- Wait up to 10s for the page to be idle
page:open("https://example.com", false)
page:wait_for_idle(10000, 500)
page:scroll([opts]) async
Scrolls the page with configurable behavior. Useful for infinite-scroll
pages.
| Option |
Type |
Default |
Description |
max_scrolls |
number |
20 |
Maximum number of scroll steps. |
step |
number |
80% of viewport |
Pixels to scroll per step. |
delay_ms |
number |
250 |
Delay between scroll steps. |
until_selector |
string |
none |
Stop scrolling when this selector appears. |
until_bottom |
boolean |
true |
Stop when the bottom of the page is reached. |
-- Scroll until an element appears or bottom is hit
page:scroll({
max_scrolls = 50,
delay_ms = 500,
until_selector = ".load-more"
})
page:content() async
Returns the full rendered HTML
(document.documentElement.outerHTML).
local html = page:content()
print(string.sub(html, 1, 500)) -- First 500 chars
page:evaluate(js) async
Evaluates JavaScript in the page context and returns the result. Uses
Runtime.evaluate with returnByValue = true.
local title = page:evaluate("document.title")
local count = page:evaluate("document.querySelectorAll('.item').length")
local data = page:evaluate("JSON.stringify(window.__INITIAL_STATE__)")
page:click(selector, [opts]) async
Clicks a CSS selector. By default uses el.click() in JavaScript.
opts.real = true dispatches real mouse events via
Input.dispatchMouseEvent.
-- Standard click (JS dispatch)
page:click(".submit-btn")
-- Real hardware-level mouse events (better anti-bot)
page:click(".buy-now", { real = true })
page:type(selector, text, [opts]) async
Types text into a selector. By default sets el.value and
dispatches input/change events. opts.real = true uses
Input.insertText for true keystroke simulation.
-- Standard input
page:type("#search", "hello world")
-- Real keystroke simulation
page:type("#username", "admin", { real = true })
page:screenshot(path, [opts]) async
Takes a screenshot and saves it to path. Returns the path on
success.
| Option |
Type |
Default |
Description |
format |
string |
"png" |
Image format: "png" or "jpeg". |
quality |
number |
none |
JPEG quality (1-100). Only applies to JPEG. |
full_page |
boolean |
false |
Capture the full page (not just viewport). |
fullPage |
boolean |
false |
Alias for full_page. |
fromSurface |
boolean |
true |
Capture from the surface (set to false for DPI-aware capture).
|
-- Basic screenshot (PNG)
page:screenshot("debug.png")
-- Full-page JPEG
page:screenshot("fullpage.jpg", {
format = "jpeg",
quality = 80,
full_page = true
})
page:set_extra_headers({
["Accept-Language"] = "en-US",
["X-Custom"] = "my-value"
})
page:set_user_agent(user_agent, [opts]) async
Overrides the User-Agent via Network.setUserAgentOverride.
opts can include accept_language and
platform.
page:set_user_agent("Mozilla/5.0 ...", {
accept_language = "en-US,en;q=0.9",
platform = "Linux"
})
page:cookies([urls]) async
Returns all cookies. If urls is provided, filters cookies by the
given URLs. Uses Network.getAllCookies (without URLs) or
Network.getCookies (with URLs).
-- All cookies
local all = page:cookies()
-- Cookies for specific URLs
local filtered = page:cookies({ "https://example.com" })
for _, c in ipairs(filtered) do
print(c.name, c.value)
end
page:set_cookies(cookies) async
Sets cookies via Network.setCookies. Each cookie should have
name, value, and optionally domain,
path, etc.
page:set_cookies({
{ name = "session", value = "abc123", domain = "example.com", path = "/" },
{ name = "theme", value = "dark", domain = "example.com" }
})
page:block_resources(types) async
Blocks network requests matching resource types or URL patterns. Accepts type
names like "image", "font", "media",
"stylesheet", "script", or custom URL patterns.
-- Block images and fonts
page:block_resources({ "image", "font" })
-- Block specific URL patterns
page:block_resources({ "*.analytics.js", "*.tracking.com/*" })