TL;DR
Browserbase's Fetch API is basically curl with a residential IP. That's useful — until you need anything beyond static HTML.
- No JavaScript rendering — you get the raw HTTP response, so React apps and SPAs come back as empty
<div id="root"></div>shells - 1 MB content limit — anything bigger returns a 502
- 10-second timeout — slow pages give you a 504 before they finish loading
- You end up needing browser sessions anyway — which means maintaining two completely separate code paths
ScrapeGraph skips all of that. One API call, JS rendering included, structured JSON output, no size caps.
What Browserbase Fetch Actually Does
Browserbase has two products: full browser sessions (headless Chromium) and a Fetch API. Fetch is the lightweight option — it sends an HTTP request through Browserbase's infrastructure using a real browser User-Agent, so you get past basic bot detection without spinning up a whole browser.
Here's what it looks like in Python:
from browserbase import Browserbase
bb = Browserbase(api_key="your-api-key")
response = bb.fetch(
url="https://example.com",
proxy=True
)
print(response.status_code)
print(response.content)And the Node.js version:
import Browserbase from "@browserbasehq/sdk";
const bb = new Browserbase({ apiKey: process.env.BROWSERBASE_API_KEY! });
const response = await bb.fetchAPI.create({
url: "https://example.com",
proxies: true,
});
console.log(response.statusCode);
console.log(response.content);You get custom headers, proxy routing, redirect handling, SSL config, and response metadata. For downloading a robots.txt or checking if a URL returns a 200, it works fine.
The problems start when you try to actually scrape something.
Where It Breaks Down
These aren't hidden gotchas — Browserbase documents them clearly. But the practical impact is bigger than the docs suggest.
No JavaScript Rendering
Fetch does not execute JavaScript. At all. That means any page that loads content after the initial HTML response comes back incomplete. SPAs, React apps, Next.js pages, anything with lazy loading, infinite scroll, or client-side data fetching — you get the skeleton HTML and nothing else.
Try fetching a modern e-commerce product page. The product grid loads via a JS API call after page render. Fetch returns an empty container div. The actual product data? Nowhere to be found.
This isn't an edge case. The majority of websites built in the last five years rely on JavaScript for content rendering.
The 1 MB Wall
Responses over 1 MB trigger a 502 error. That might sound generous until you realize how common large pages are. Product listing pages with inline images. Documentation sites. News articles with embedded media. Any page with a hefty DOM structure.
Browserbase's own docs suggest switching to a full browser session when you hit this limit. Which raises the question: why not just start with the browser session?
10-Second Timeout
The Fetch API gives up after 10 seconds. That keeps things snappy for fast sites, but it's a dealbreaker for pages behind cold CDN caches, slower servers, or sites with heavy server-side processing. You get a 504 and no data.
The Two-Code-Path Problem
This is the real issue. Every one of these limitations has the same fallback: use a browser session instead. But browser sessions have a completely different API surface, different pricing, different setup. You end up writing and maintaining two scraping implementations — one for "simple" pages and one for everything else.
And you never know which category a page falls into until your Fetch call fails.
How ScrapeGraph Handles This Differently
ScrapeGraph doesn't make you choose between a lightweight HTTP fetch and a full browser. There's one API that handles both scenarios automatically.
Tell It What You Want, Get JSON Back
Instead of fetching raw HTML and writing parsers, you describe the data you need:
from scrapegraph_py import Client
client = Client(api_key="your-api-key")
response = client.extract(
url="https://shop.example.com/products",
prompt="Extract all products with name, price, and stock status"
)
# Clean structured JSON, ready for your database
print(response['result'])No CSS selectors that break when the site redesigns. No BeautifulSoup. No XPath. The AI figures out where the data lives and pulls it into a structured format.
Don't need structured extraction? You can also grab the page as clean markdown — useful when you just want readable content without writing parsers:
from scrapegraph_py import Client
client = Client(api_key="your-api-key")
# Get the page as clean, readable markdown
result = client.scrape("https://shop.example.com/products")
print(result['markdown'])This gives you the full rendered page content (JavaScript included) as markdown — no selectors, no parsing, no 1 MB limit.
JS Rendering Is Just... On
There's no "fetch mode" vs "browser mode" toggle. ScrapeGraph renders JavaScript-heavy pages automatically. React apps, SPAs, dynamically loaded content — it all works through the same API call. You don't have to guess whether a page needs JS rendering or not.
No Arbitrary Limits
No 1 MB content cap. No 10-second hard timeout. Pages process normally regardless of size. If a site is slow, the request waits for it instead of throwing a 504 at you.
Side-by-Side Comparison
| Browserbase Fetch | ScrapeGraph | |
|---|---|---|
| JavaScript rendering | No | Yes, automatic |
| Content size limit | 1 MB (502 on exceed) | None |
| Timeout | 10 seconds (504) | Flexible |
| Output | Raw HTML | Structured JSON |
| Proxy support | Yes (explicit flag) | Built-in, automatic escalation |
| Natural language queries | No | Yes |
| Selector maintenance | You write and maintain them | AI adapts to site changes |
| Fallback for complex pages | Switch to browser sessions | Not needed — one code path |
A Concrete Example
Let's say you need product data from a JS-rendered e-commerce page. Here's what each approach looks like.
Browserbase Fetch:
from browserbase import Browserbase
from bs4 import BeautifulSoup
bb = Browserbase(api_key="your-api-key")
# Fetch raw HTML — hope the page doesn't use JS rendering
response = bb.fetch(url="https://shop.example.com/products")
# Parse manually with selectors
soup = BeautifulSoup(response.content, "html.parser")
products = soup.find_all("div", class_="product-card")
for product in products:
name = product.find("h3").text
price = product.find("span", class_="price").text
# These selectors break when the site updates its markupIf the page renders with JavaScript (and it probably does), products is an empty list. If the page is over 1 MB, you get a 502. Either way, you need to rewrite this using browser sessions.
ScrapeGraph:
from scrapegraph_py import Client
client = Client(api_key="your-api-key")
response = client.extract(
url="https://shop.example.com/products",
prompt="Extract all products with name, price, and availability"
)
products = response['result']Same result, fraction of the code, and it works whether the page uses JavaScript or not.
When Fetch Is Actually the Right Call
Not everything needs AI extraction. Browserbase Fetch makes sense for:
- Machine-readable files — robots.txt, sitemaps, JSON APIs, RSS feeds
- Uptime monitoring — checking status codes and response headers
- Static HTML pages — old-school server-rendered sites under 1 MB where you just need the raw HTML
If your scraping targets all fall into those categories, Fetch is simpler and cheaper. But most real-world scraping projects grow beyond that pretty quickly.
More Than Just Extract
ScrapeGraph isn't just an extraction API. The platform covers the full scraping workflow:
- Scrape — get clean Markdown, raw HTML, or screenshots from any URL, with stealth mode and custom wait configuration
- Search — find and extract data across the web from a natural language query, no URLs needed
- Crawl — follow links across entire sites with start/stop/resume controls and per-page extraction
- Monitor — schedule recurring scrapes with webhook notifications when content changes
All through the same SDK pattern. Create a client, call the method, get results.
Getting Started
Python:
pip install scrapegraph-pyfrom scrapegraph_py import Client
client = Client(api_key="your-api-key")
# AI extraction
response = client.extract(
url="https://example.com",
prompt="Extract the main heading and all navigation links"
)
# Or just get clean Markdown
markdown = client.scrape("https://example.com")Node.js:
npm install scrapegraph-jsimport { scrapegraphai } from "scrapegraph-js";
const sgai = scrapegraphai({ apiKey: "your-api-key" });
// AI extraction
const response = await sgai.extract("https://example.com", {
prompt: "Extract the main heading and all navigation links",
});
// Or just get clean Markdown
const markdown = await sgai.scrape("https://example.com");Both SDKs include retry logic, error handling, and TypeScript types out of the box.
Bottom Line
Browserbase Fetch API does one thing: HTTP requests through residential proxies. That's it. No JS, 1 MB cap, 10-second timeout. The moment your target doesn't fit those constraints, you're back to managing browser sessions.
ScrapeGraph handles the full spectrum — from simple static pages to complex JS-rendered apps — through a single API. You describe what data you want, and you get structured JSON back. No fallback code, no selector maintenance, no guessing which mode to use.
Try ScrapeGraph free — 500 credits, no card required.
Related Articles
- 7 Best Firecrawl Alternatives for AI Web Scraping in 2026 - Compare the top Firecrawl alternatives and find the right fit for your scraping needs
- Top Browser Use Alternatives for AI Web Scraping - Other browser automation tools and how they stack up
- Top 7 AI Web Scraping Tools: Smarter Scraping in 2026 - A broader look at the AI scraping landscape
- ScrapeGraphAI vs Diffbot: Which Data Extractor Wins in 2026 - Deep-dive comparison of two AI-first extraction platforms
- Web Scraping vs API: The Complete 2026 Comparison Guide - When to scrape and when to use an API
