Quickstart: first session in five minutes
Create an API key, start a hardened browser session, navigate deterministically and run one model-backed extraction, in about five minutes.
Last updated:
What you will build
This page takes you from nothing to structured data in about five minutes. You will create an API key, start one browser session, navigate it with a deterministic step that costs no inference, and run a single model-backed extraction that returns typed JSON.
Everything happens over one HTTP API. The TypeScript and Python SDKs wrap it; the cURL tab shows the raw requests so you can see there is no magic in between. All you need is an account and a terminal.
From key to data
Store your key as BROWSERBERG_API_KEY, pick a tab, and run it as one file. Each sample creates a short-lived session, opens example.com and extracts the heading.
Requires: api-key inference
import { Browserberg } from '@browserberg/sdk';
const bb = new Browserberg({
apiKey: process.env.BROWSERBERG_API_KEY!,
baseUrl: 'https://browserberg.com',
// Extraction is a model call; give it more room than the 30 s default.
timeoutMs: 180_000,
});
// Released automatically when the block exits, even on an error.
await using session = await bb.sessions.create({ ttlSeconds: 300 });
// Deterministic navigation: a plain step, no model call.
await session.act({
steps: [{
encodedId: null, action: 'navigate', role: 'none',
description: 'open example.com', value: 'https://example.com',
}],
});
// One instruction against the live page, one typed result back.
const result = await session.extract({
instruction: 'the page heading and the first paragraph',
jsonSchema: {
type: 'object',
properties: {
heading: { type: 'string' },
firstParagraph: { type: 'string' },
},
required: ['heading'],
},
});
console.log(JSON.stringify(result.data, null, 2));
console.log('inference calls:', result.provenance.inferenceCalls);
import json
import os
from browserberg import Browserberg, ObservedAction
# Extraction is a model call; give it more room than the 30 s default.
bb = Browserberg(
os.environ["BROWSERBERG_API_KEY"], base_url="https://browserberg.com", timeout=180.0
)
with bb.sessions.create(ttl_seconds=300) as session:
# Deterministic navigation: a plain step, no model call.
session.act(steps=[ObservedAction(
encoded_id=None, action="navigate", role="none",
description="open example.com", value="https://example.com",
)])
# One instruction against the live page, one typed result back.
result = session.extract(
instruction="the page heading and the first paragraph",
schema={
"type": "object",
"properties": {
"heading": {"type": "string"},
"firstParagraph": {"type": "string"},
},
"required": ["heading"],
},
)
print(json.dumps(result.data, indent=2))
BASE="https://browserberg.com"
AUTH="Authorization: Bearer $BROWSERBERG_API_KEY"
JSON="Content-Type: application/json"
ID=$(curl -s -X POST "$BASE/v1/sessions" -H "$AUTH" -H "$JSON" -d '{"ttlSeconds": 300}' \
| python3 -c 'import json,sys; print(json.load(sys.stdin)["session"]["id"])')
curl -s -X POST "$BASE/v1/sessions/$ID/act" -H "$AUTH" -H "$JSON" -d '{
"steps": [{ "encodedId": null, "action": "navigate", "role": "none",
"description": "open example.com", "value": "https://example.com" }]
}' > /dev/null
curl -s -X POST "$BASE/v1/sessions/$ID/extract" -H "$AUTH" -H "$JSON" \
-d '{"instruction": "the page heading"}' \
| python3 -c 'import json,sys; print(json.dumps(json.load(sys.stdin)["data"], indent=2))'
curl -s -X DELETE "$BASE/v1/sessions/$ID" -H "$AUTH" > /dev/null
{
"heading": "Example Domain",
"firstParagraph": "This domain is for use in documentation examples without needing permission. Avoid use in operations."
}
inference calls: 1
What just happened
Four details in that file are worth a second look. await using (and the with block in Python) releases the session when the block exits, even on an error. You pay for browser time, so a session you forget to close is the one mistake that costs money. The navigate call is a plain step with no instruction: deterministic, repeatable, and it makes no model call at all.
The extract call is the only line that pays for inference. It carries a JSON Schema, so the answer comes back as typed data rather than prose you would have to parse a second time.
Every verb response ends with a provenance block: inferenceCalls, planCacheHit, tier and a requestId. That is how you tell a cached replay from a paid model call, from the response itself rather than from your invoice.
Tip · Prefer no code at all?
The MCP server drives the same kind of session from a coding agent: six tools, no SDK, one config block. See the MCP server page in this section.