chrome_run()
Render a URL in headless Chrome and return the fully-rendered HTML. Unlike curl_request(), which returns the raw server response, chrome_run() runs the page's JavaScript — so it works with single-page apps, lazy-loaded content, and pages that only build their markup client-side.
You can optionally pass a recipe: a list of interaction steps (wait for an element, click, fill a field) that run after the page loads, before the HTML is captured.
Syntax
chrome_run(url, recipe?)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
url |
string | yes | The page URL to render. |
recipe |
array | no | A list of [verb, ...args] steps run in order after load. |
Recipe verbs
| Step | Description |
|---|---|
["waitFor", selector, seconds?] |
Wait until a CSS selector exists (default 10s). |
["waitForText", text, selector?, seconds?] |
Wait until text appears inside selector (default body, 10s). |
["click", selector] |
Click the first matching element. |
["setField", selector, value] |
Set an input/textarea/select value (fires input + change). |
["wait", ms] |
Pause for a fixed number of milliseconds (max 30000). |
["scrollBottom"] |
Scroll to the bottom of the page (triggers lazy-loading). |
Selectors are standard CSS selectors (e.g. input[name=q], #submit, .results). An unknown verb, a missing selector, or a waitFor timeout stops the recipe and returns ok => false with the error.
Returns
A response array:
| Key | Description |
|---|---|
ok |
true if the page rendered and every recipe step succeeded |
url |
Final URL after any redirects or navigation |
status |
Best-effort HTTP status of the main document (approximate — check ok) |
body |
The final rendered HTML (same key as curl_request) |
error |
Error message when ok is false |
Example
$resp = chrome_run("https://example.com/products", [
["setField", "input[name=q]", "widgets"],
["click", "#search"],
["waitFor", ".results .item"]
]);
if ( $resp["ok"] ) {
$names = preg_match_all_gf('/class="item-name">([^<]+)/', $resp["body"], 1);
sys_log("First result: " . $names);
} else {
sys_log("Render failed: " . $resp["error"]);
}
Example output
[
"ok" => true,
"url" => "https://example.com/products?q=widgets",
"status" => 200,
"body" => "<html>…rendered DOM…</html>",
"error" => ""
]
Notes
chrome_run()is much heavier thancurl_request()— it boots a real browser per call. Use it only when a page needs JavaScript; prefer curl_request() for plain HTTP or JSON APIs.statusis approximate; rely onokto detect success.- Each
waitFor/waitForTexthas its own timeout (default 10 seconds); pass a trailing number of seconds to change it. - Only
http,https, and self-containeddata:URLs are allowed. Requests to internal or private addresses —localhost, cloud metadata (169.254.169.254), and private LAN ranges — are blocked, and the target hostname is pinned to its resolved public IP to prevent DNS-rebinding. If a redirect lands on a blocked address the call returnsok => false. - To extract data from the returned HTML, combine with strip_tags_nice(), preg_match_gf(), or preg_match_all_gf().
- Single-page apps load content asynchronously — after the initial page load there may be nothing useful yet. Always add a
waitForText(orwaitFor) step for the content you need; otherwisebodyis captured before the app has rendered. - Content rendered inside shadow DOM (web components, and Salesforce/Lightning sites) is handled:
waitForTextsearches into shadow roots and the returnedbodyinlines their markup. (waitForwith a CSS selector only matches the light DOM.)
See also: curl_request(), url_get_contents()