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 than curl_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.
  • status is approximate; rely on ok to detect success.
  • Each waitFor / waitForText has its own timeout (default 10 seconds); pass a trailing number of seconds to change it.
  • Only http, https, and self-contained data: 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 returns ok => 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 (or waitFor) step for the content you need; otherwise body is captured before the app has rendered.
  • Content rendered inside shadow DOM (web components, and Salesforce/Lightning sites) is handled: waitForText searches into shadow roots and the returned body inlines their markup. (waitFor with a CSS selector only matches the light DOM.)

See also: curl_request(), url_get_contents()