Overview
The Evaluation API allows you to execute custom JavaScript in the context of a page. Use it to:
Extract data from the DOM
Modify page content
Check element states
Call JavaScript functions
Access window/document objects
Execute JavaScript
Get Title
Count Links
Python
JavaScript
curl -X POST http://localhost:9867/tabs/tab_abc123/evaluate \
-H "Content-Type: application/json" \
-d '{"expression": "document.title"}'
Request Body
JavaScript expression to evaluate
Response (200 OK)
{
"result" : "Example Domain"
}
The result field contains the return value of the JavaScript expression.
Examples
Get Page Title
curl -X POST http://localhost:9867/tabs/tab_abc123/evaluate \
-d '{"expression": "document.title"}'
Response:
{
"result" : "Example Domain"
}
Count Elements
curl -X POST http://localhost:9867/tabs/tab_abc123/evaluate \
-d '{"expression": "document.querySelectorAll(\"button\").length"}'
Response:
curl -X POST http://localhost:9867/tabs/tab_abc123/evaluate \
-d '{"expression": "document.body.innerText"}'
Response:
{
"result" : "Example Domain \n This domain is for use in illustrative examples..."
}
Get All Links
curl -X POST http://localhost:9867/tabs/tab_abc123/evaluate \
-d '{"expression": "Array.from(document.querySelectorAll(\"a\")).map(a => ({text: a.textContent, href: a.href}))"}'
Response:
{
"result" : [
{ "text" : "More information..." , "href" : "https://www.iana.org/domains/example" }
]
}
Check Element Visibility
curl -X POST http://localhost:9867/tabs/tab_abc123/evaluate \
-d '{"expression": "document.querySelector(\"#element\").offsetHeight > 0"}'
Response:
Get Computed Styles
curl -X POST http://localhost:9867/tabs/tab_abc123/evaluate \
-d '{"expression": "getComputedStyle(document.querySelector(\"h1\")).color"}'
Response:
{
"result" : "rgb(0, 0, 0)"
}
Get Local Storage
curl -X POST http://localhost:9867/tabs/tab_abc123/evaluate \
-d '{"expression": "JSON.stringify(localStorage)"}'
Response:
{
"result" : "{ \" key \" : \" value \" }"
}
Set Local Storage
curl -X POST http://localhost:9867/tabs/tab_abc123/evaluate \
-d '{"expression": "localStorage.setItem(\"key\", \"value\")"}'
import requests
BASE = "http://localhost:9867"
tab_id = "tab_abc123"
# Navigate to page
requests.post( f " { BASE } /tabs/ { tab_id } /navigate" ,
json = { "url" : "https://news.ycombinator.com" })
# Extract all story titles
resp = requests.post( f " { BASE } /tabs/ { tab_id } /evaluate" , json = {
"expression" : """
Array.from(document.querySelectorAll('.titleline > a'))
.map(a => ({
title: a.textContent,
url: a.href
}))
"""
})
stories = resp.json()[ "result" ]
print ( f "Found { len (stories) } stories: \n " )
for i, story in enumerate (stories[: 10 ], 1 ):
print ( f " { i } . { story[ 'title' ] } " )
print ( f " { story[ 'url' ] } \n " )
Complex Evaluation Example
const BASE = "http://localhost:9867" ;
const tabId = "tab_abc123" ;
// Extract product data from e-commerce page
const resp = await fetch ( ` ${ BASE } /tabs/ ${ tabId } /evaluate` , {
method: "POST" ,
headers: { "Content-Type" : "application/json" },
body: JSON . stringify ({
expression: `
{
title: document.querySelector('h1.product-title')?.textContent,
price: document.querySelector('.price')?.textContent,
inStock: document.querySelector('.in-stock') !== null,
rating: parseFloat(document.querySelector('.rating')?.textContent),
images: Array.from(document.querySelectorAll('.product-image img'))
.map(img => img.src),
description: document.querySelector('.description')?.textContent.trim()
}
`
})
});
const product = ( await resp . json ()). result ;
console . log ( product );
Error Handling
JavaScript Error (500)
curl -X POST http://localhost:9867/tabs/tab_abc123/evaluate \
-d '{"expression": "nonexistent.property"}'
Response:
{
"error" : "evaluate: ReferenceError: nonexistent is not defined" ,
"statusCode" : 500
}
Syntax Error (400)
curl -X POST http://localhost:9867/tabs/tab_abc123/evaluate \
-d '{"expression": "document.querySelector("}'
Response:
{
"error" : "invalid expression syntax" ,
"statusCode" : 400
}
Tab Not Found (404)
curl -X POST http://localhost:9867/tabs/nonexistent/evaluate \
-d '{"expression": "document.title"}'
Response:
{
"error" : "tab not found" ,
"statusCode" : 404
}
Best Practices
Return Simple Data Types
JavaScript objects are serialized to JSON. Stick to simple types:
# ✅ Good: Returns array of strings
curl -X POST $BASE /tabs/ $TAB /evaluate \
-d '{"expression": "Array.from(document.querySelectorAll(\"h2\")).map(h => h.textContent)"}'
# ❌ Bad: Returns DOM nodes (can't serialize)
curl -X POST $BASE /tabs/ $TAB /evaluate \
-d '{"expression": "document.querySelectorAll(\"h2\")"}'
Use JSON.stringify for Objects
curl -X POST http://localhost:9867/tabs/tab_abc123/evaluate \
-d '{"expression": "JSON.stringify({title: document.title, url: location.href})"}'
Then parse on the client side:
resp = requests.post( f " { BASE } /tabs/ { tab_id } /evaluate" ,
json = { "expression" : "JSON.stringify( {title: document.title, url: location.href} )" })
data = json.loads(resp.json()[ "result" ])
print (data[ "title" ])
Handle Null/Undefined
// Use optional chaining and defaults
const expression = `
{
title: document.querySelector('h1')?.textContent || 'No title',
price: document.querySelector('.price')?.textContent || 'N/A'
}
` ;
# Extract table data
expression = """
Array.from(document.querySelectorAll('table tr')).map(row =>
Array.from(row.querySelectorAll('td')).map(cell => cell.textContent.trim())
)
"""
resp = requests.post( f " { BASE } /tabs/ { tab_id } /evaluate" ,
json = { "expression" : expression})
table_data = resp.json()[ "result" ]
Use Cases
Check Login State
# Check if user is logged in
resp = requests.post( f " { BASE } /tabs/ { tab_id } /evaluate" , json = {
"expression" : "document.querySelector('.logout-button') !== null"
})
is_logged_in = resp.json()[ "result" ]
Wait for Element
import time
# Poll for element to appear
for _ in range ( 10 ):
resp = requests.post( f " { BASE } /tabs/ { tab_id } /evaluate" , json = {
"expression" : "document.querySelector('#result') !== null"
})
if resp.json()[ "result" ]:
break
time.sleep( 0.5 )
Modify Page Content
# Hide ads
curl -X POST http://localhost:9867/tabs/tab_abc123/evaluate \
-d '{"expression": "document.querySelectorAll(\".ad\").forEach(el => el.style.display = \"none\")"}'
# Change page title
curl -X POST http://localhost:9867/tabs/tab_abc123/evaluate \
-d '{"expression": "document.title = \"New Title\""}'
# Get all form input values
resp = requests.post( f " { BASE } /tabs/ { tab_id } /evaluate" , json = {
"expression" : """
Object.fromEntries(
Array.from(document.querySelectorAll('input, select, textarea'))
.map(el => [el.name || el.id, el.value])
.filter(([name]) => name)
)
"""
})
form_data = resp.json()[ "result" ]
Limitations
Cannot return DOM nodes or functions (must serialize to JSON)
Long-running scripts may timeout
Page must be fully loaded before evaluation
Cross-origin restrictions apply (same as browser)
Next Steps
Snapshot API Get structured page data
Actions API Interact with page elements
Navigation Navigate before evaluation
Cookies Manage cookies and storage