Run small, bounded JavaScript evaluations for page introspection (read a counter, check a flag, verify a title) without dumping unbounded DOM back to the model.
This page covers:
read() insteadEvaluate JS is for small signals, not scraping.
If the result could be unbounded (DOM dumps, huge arrays), don’t evaluate JS—use snapshots or read() instead.
Good fits:
document.titlewindow.__APP_STATE__.count)Avoid:
querySelectorAll dumpsIf you build a custom CAPTCHA solver, you can call a page-control JS hook from the handler to read or write small bits of page state in the same live session. Keep the JS bounded and focused on single values.
async def captcha_handler(ctx):
# Small, bounded JS to read/patch the page
challenge = await ctx.page_control.evaluate_js("/* read a token or sitekey */")
await ctx.page_control.evaluate_js("/* inject a solution token */")
return {"action": "wait_until_cleared"}Python runtime exposes a safe evaluate helper that returns a bounded, textual result.
from predicate.models import EvaluateJsRequest
result = await runtime.evaluate_js(EvaluateJsRequest(code="document.title"))
if result.ok:
print(result.text)
else:
print("error:", result.error)
evaluate_js toolBoth SDKs include a default evaluate_js tool in their Tool Registry pack.
from predicate.tools import ToolRegistry, ToolContext, register_default_tools
registry = ToolRegistry()
register_default_tools(registry, runtime)
ctx = ToolContext(runtime)
out = await registry.execute("evaluate_js", {"code": "document.title"}, ctx=ctx)
print(out.get("text") or out.get("value"))from predicate.models import EvaluateJsRequest
title = await runtime.evaluate_js(EvaluateJsRequest(code="document.title"))
runtime.assert_(lambda _snap: bool(title.ok and title.text and "Checkout" in title.text), "title_contains_checkout")
tool_call trace events