The Browserbase Search API lets you perform web searches programmatically and receive structured results directly, no browser session required. It’s designed for agents, research pipelines, and any workflow that needs real-time web search data.
Send a POST request to /v1/search with your query. Authenticate with the same x-bb-api-key header used across the Browserbase API.
import { Browserbase } from "@browserbasehq/sdk";
const bb = new Browserbase({ apiKey: process.env.BROWSERBASE_API_KEY! });
const response = await bb.search.web({
query: "browserbase",
numResults: 10, // up to 25 results
});
console.log(`Request ID: ${response.requestId}`);
for (const result of response.results) {
console.log(`${result.title} - ${result.url}`);
}
from browserbase import Browserbase
import os
bb = Browserbase(api_key=os.environ["BROWSERBASE_API_KEY"])
response = bb.search.web(
query="browserbase",
num_results=5,
)
print(f"Request ID: {response.request_id}")
for result in response.results:
print(f"{result.title} - {result.url}")
curl -X POST https://api.browserbase.com/v1/search \
-H "Content-Type: application/json" \
-H "x-bb-api-key: $BROWSERBASE_API_KEY" \
-d '{
"query": "browserbase",
"numResults": 10
}'
Request Parameters
| Parameter | Type | Required | Description |
|---|
query | string | Yes | The search query (1–200 characters) |
numResults | integer | No | Number of results to return (1–25, default: 10) |
Response
| Field | Type | Description |
|---|
requestId | string | Unique identifier for the request |
query | string | The search query that was executed |
results | array | List of search result objects |
Each result object contains:
| Field | Type | Always present | Description |
|---|
id | string | Yes | Unique identifier for the result |
url | string | Yes | URL of the search result |
title | string | Yes | Title of the search result |
author | string | No | Author of the content |
publishedDate | string | No | Publication date (ISO 8601) |
image | string | No | Image URL |
favicon | string | No | Favicon URL |
Combining Search with Browser Sessions
A common pattern is using the Search API to find relevant URLs, then opening them in browser sessions for deeper interaction — scraping content, filling forms, or taking screenshots.
import { Browserbase } from "@browserbasehq/sdk";
import { chromium } from "playwright-core";
const bb = new Browserbase({ apiKey: process.env.BROWSERBASE_API_KEY! });
const searchResponse = await bb.search.web({
query: "browserbase documentation",
numResults: 10,
});
for (const result of searchResponse.results) {
const session = await bb.sessions.create();
const browser = await chromium.connectOverCDP(session.connectUrl);
const page = browser.contexts()[0].pages()[0];
await page.goto(result.url);
const content = await page.textContent("body");
console.log(`Content from ${result.title}:`, content?.slice(0, 200));
await page.close();
await browser.close();
}
from browserbase import Browserbase
from playwright.sync_api import sync_playwright
import os
bb = Browserbase(api_key=os.environ["BROWSERBASE_API_KEY"])
search_response = bb.search.web(
query="browserbase documentation",
num_results=3,
)
with sync_playwright() as playwright:
for result in search_response.results:
session = bb.sessions.create()
browser = playwright.chromium.connect_over_cdp(session.connect_url)
page = browser.contexts[0].pages[0]
page.goto(result.url)
content = page.text_content("body")
print(f"Content from {result.title}:", content[:200] if content else "")
page.close()
browser.close()
Rate Limits
The Search API is rate limited to 120 requests per minute per project. Exceeding this returns a 429 status code.
For high-volume use cases, space out your requests or implement exponential
backoff in your retry logic.
Error Handling
| Status Code | Meaning |
|---|
200 | Success |
400 | Invalid request (empty query, numResults out of range) |
403 | Search API not enabled for your project |
429 | Rate limit exceeded |
503 | Search service temporarily unavailable |
500 | Internal server error |
try {
const response = await fetch("https://api.browserbase.com/v1/search", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-bb-api-key": process.env.BROWSERBASE_API_KEY!,
},
body: JSON.stringify({ query: "browserbase" }),
});
if (!response.ok) {
if (response.status === 429) {
console.log("Rate limited — retrying after delay");
} else if (response.status === 503) {
console.log("Service temporarily unavailable — retrying");
} else {
console.error(`Search failed: ${response.status}`);
}
return;
}
const data = await response.json();
console.log(data.results);
} catch (error) {
console.error("Request failed:", error);
}
import requests
import os
response = requests.post(
"https://api.browserbase.com/v1/search",
headers={
"Content-Type": "application/json",
"x-bb-api-key": os.environ["BROWSERBASE_API_KEY"],
},
json={"query": "browserbase"},
)
if response.status_code == 429:
print("Rate limited — retrying after delay")
elif response.status_code == 503:
print("Service temporarily unavailable — retrying")
elif not response.ok:
print(f"Search failed: {response.status_code}")
else:
data = response.json()
print(data["results"])