GuidesSCRAPING APIS
Free web scraping APIs for JavaScript
Six of the 9 scraping APIs we tested on 28 October 2026 send CORS headers, so browser code can call them directly; ZenRows, Scrapfly and Crawlbase cannot be read from a web page. Firecrawl's scrape endpoint and Jina Reader answer without any key, and monthly free tiers run from 1,000 credits (Firecrawl, ScraperAPI) to 10,000 (ScrapingAnt). For the raw HTML of public pages, the free cors.dev tier needs no key or signup: GET and HEAD, about 600 requests a minute per IP, responses up to 6 MiB, no JavaScript rendering.
Free scraping APIs compared
On 28 October 2026 we called 9 scraping APIs with Origin: https://example.com and a test key, checked each response for an Access-Control-Allow-Origin header, then called the same URL through https://proxy.cors.dev/.
| API | Free tier | JavaScript rendering | Browser CORS | Notes |
|---|---|---|---|---|
| Firecrawl | Keyless scrape, or 1,000 credits a month with a free key | Yes, 1 credit per page | Yes | Crawl, map and extract need a key |
| ScraperAPI | 1,000 credits a month, plus a 7-day trial with 5,000 | render=true costs 10 credits | Yes | Key in the query string |
| ScrapingBee | 1,000 trial credits, no card | On by default, 5 credits | Yes | render_js=false for a plain fetch |
| ZenRows | 5,000 credits a month | 5 credits | No | Readable through proxy.cors.dev |
| Scrapfly | 1,000 credits, one time | Adds 5 credits | No, 403 when an Origin is sent | Readable through proxy.cors.dev |
| Jina Reader | 20 requests a minute without a key | Headless browser by default | Yes | 429 through proxies, call it directly |
| Apify | $5 of usage a month | Depends on the Actor | Yes | Runs ready-made scraper Actors |
| ScrapingAnt | 10,000 credits a month | On by default, 10 credits | Yes | 1 credit without the browser |
| Crawlbase | 1,000 credits, up to 5,000 after setup | JavaScript requests cost 2x | No | Readable through proxy.cors.dev |
| cors.dev free proxy | No key, no signup | No | Adds CORS headers | Raw HTML, 6 MiB, about 600 a minute per IP |
None of the free tiers asks for a card. Firecrawl, ScraperAPI, ZenRows, ScrapingAnt and Apify refill every month; ScrapingBee, Scrapfly and Crawlbase give credits once, at signup.
Which scraping APIs answer a browser
- Firecrawl:
POST https://api.firecrawl.dev/v2/scrapewith no key returned200, Markdown andAccess-Control-Allow-Origin: *. Call it directly, no proxy needed. - ScraperAPI:
GET https://api.scraperapi.com/?api_key=KEY&url=TARGETechoed our origin inAccess-Control-Allow-Origin. Call it directly. - ScrapingBee:
GET https://app.scrapingbee.com/api/v1/?api_key=KEY&url=TARGETechoed our origin, and its preflight answered200. Call it directly. - ZenRows:
GET https://api.zenrows.com/v1/?apikey=KEY&url=TARGETsent noAccess-Control-Allow-Originand its preflight returned401, so browsers block it. Throughproxy.cors.devits401for our test key came back readable. - Scrapfly:
GET https://api.scrapfly.io/scrape?key=KEY&url=TARGETreturned an empty403whenever the request carried anOriginheader, so every browser call fails. Throughproxy.cors.devits JSON401for our test key came back readable. - Jina Reader:
GET https://r.jina.ai/TARGETanswered200with our origin echoed: 1,465 bytes of Markdown for example.com, 16,530 for news.ycombinator.com. Throughproxy.cors.devit answered429(Per IP rate limit exceeded), because proxy traffic shares IP addresses. Call it directly. - Apify:
https://api.apify.com/v2/sendsAccess-Control-Allow-Origin: *and allows theAuthorizationheader. Call it directly. - ScrapingAnt:
GET https://api.scrapingant.com/v2/general?url=TARGET&x-api-key=KEYsentAccess-Control-Allow-Origin: *. Call it directly. - Crawlbase:
GET https://api.crawlbase.com/?token=TOKEN&url=TARGETsent noAccess-Control-Allow-Origin, so browsers block it; throughproxy.cors.devthe response came back readable.
Raw HTML with proxy.cors.dev and DOMParser
If the content you need is in the page's initial HTML and the site does not block bots, you do not need a scraping API at all. On 28 October 2026 we fetched example.com (577 bytes), news.ycombinator.com (34,286 bytes) and the English Wikipedia CORS article (172,477 bytes) through https://proxy.cors.dev/; all three returned 200 with Access-Control-Allow-Origin echoing the page origin. Fetched directly, the same pages sent no CORS header.
Pass the HTML string to DOMParser to get a document that supports querySelectorAll. Resolve relative links against the target page with new URL(href, pageUrl), or they point at your own app.
async function scrapePage(pageUrl) {
const res = await fetch('https://proxy.cors.dev/' + pageUrl);
if (!res.ok) {
throw new Error(`HTTP ${res.status}: ${res.headers.get('X-Cors-Error') ?? 'upstream error'}`);
}
const html = await res.text();
const doc = new DOMParser().parseFromString(html, 'text/html');
const links = [...doc.querySelectorAll('a[href]')]
.filter((a) => URL.canParse(a.getAttribute('href'), pageUrl))
.map((a) => ({
text: a.textContent.trim(),
href: new URL(a.getAttribute('href'), pageUrl).href,
}));
return { title: doc.title, links };
}
const page = await scrapePage('https://news.ycombinator.com/');
console.log(page.title, page.links.length);The free tier needs no signup and no key. Its limits:
GETandHEADonly;POSTanswers405withmethod_not_allowedin theX-Cors-Errorresponse header.- About 600 requests a minute per IP, a 30-second upstream deadline, responses up to 6 MiB (6,291,456 bytes), up to 20 redirects, and no caching.
- HTML exactly as the server sends it: no JavaScript rendering, no anti-bot bypass, browser cookies never forwarded.
- Query-string API keys are forwarded as-is;
AuthorizationandX-Api-Keyheaders get400header_not_allowed; other unsupported headers are dropped and named inX-Cors-Dropped-Headers.
Markdown without a key
Jina Reader (GET https://r.jina.ai/TARGET) loads the target page in a headless browser by default and returns Markdown text with CORS headers attached. Without a key you get 20 requests a minute; a free key raises that to 500 a minute and adds 10 million free tokens.
async function readAsMarkdown(pageUrl) {
const res = await fetch('https://r.jina.ai/' + pageUrl);
if (res.status === 429) {
throw new Error('Jina Reader rate limit: wait a minute or use a free key');
}
if (!res.ok) throw new Error(`Jina Reader HTTP ${res.status}`);
return res.text();
}
const markdown = await readAsMarkdown('https://example.com/');
console.log(markdown);Firecrawl (POST https://api.firecrawl.dev/v2/scrape) also works without a key when you send {"url": ..., "formats": ["markdown"]}, returning 200 and Access-Control-Allow-Origin: *. Keyless use is free and capped per IP address per day by a request count and a credit count that Firecrawl does not publish (going over returns 429), and crawl, map, extract and batch scrape require a key.
What the credits pay for
- Firecrawl: a free key gives 1,000 credits a month, 10 scrape and 2 crawl requests a minute, and 2 concurrent browsers. A basic scrape costs 1 credit per page, JSON extraction adds 4, and Hobby is $19 a month for 5,000 credits.
- ScraperAPI: 1,000 credits a month and 5 concurrent requests, plus a 7-day trial with 5,000 credits. A standard request costs 1 credit,
render=truecosts 10, Google and Bing pages cost 25; Hobby is $49 a month for 100,000 credits. - ScrapingBee: 1,000 trial credits. Headless rendering is on by default at 5 credits;
render_js=falsemakes it a 1-credit plain request. Premium proxies cost 10 or 25 credits; Hobby is $19 a month for 75,000 credits. - ZenRows: 5,000 credits a month, 5 concurrent requests, failed requests free. A standard page is 1 credit, JavaScript rendering 5, premium proxies 10, both 25.
- Scrapfly: 1,000 credits once. A datacenter request costs 1 credit, browser rendering adds 5, residential proxies cost 25; Discovery is $30 a month for 200,000 credits.
- ScrapingAnt: 10,000 credits a month. The default headless browser with JavaScript rendering costs 10 credits, a plain request 1, residential proxies 25.
- Crawlbase: 1,000 credits at signup, up to 5,000 after account setup steps; JavaScript requests cost twice as much.
- Apify: $5 of platform usage a month at $0.2 per compute unit; Starter is $19 a month. Rendering depends on the Actor you run.
API keys in browser code
Any API key in browser code, in a query string or a header, is visible to every visitor in DevTools, and cors.dev does not hide or protect it. Keep your own production key on a backend; direct browser calls fit internal tools, prototypes, and bring-your-own-key apps where each user pastes their own key into the UI.
The free tier forwards query-string keys to ZenRows, Scrapfly and Crawlbase, but answers Authorization and X-Api-Key headers with 400 header_not_allowed and POST with 405.
For POST, PUT, PATCH and DELETE, bodies up to 1 MiB, and Authorization or custom API headers, cors.dev Pro is $5 a month for 500,000 requests, with 3,000 requests a minute per account and 100 in flight; the 7-day trial includes 1,000 requests, no card. You sign in with Google at cors.dev, create a Connection that lists your exact page origins and API hosts, and send its key in X-Cors-Key. That key is a publishable identifier that only works from your registered origins, not a secret.
Good questions.
Is there a free web scraping API that needs no API key?
Yes: Jina Reader (GET https://r.jina.ai/TARGET) and Firecrawl (POST https://api.firecrawl.dev/v2/scrape) both return Markdown with CORS headers and no key. Jina allows 20 requests a minute without a key; Firecrawl caps keyless use per IP per day at a limit it does not publish, then answers 429. For raw HTML without JavaScript rendering, prefix any public URL with https://proxy.cors.dev/: no key, about 600 requests a minute per IP.
Can I call ScraperAPI or ScrapingBee from browser JavaScript?
Yes, both ScraperAPI and ScrapingBee echoed our Origin header in Access-Control-Allow-Origin on 28 October 2026, so fetch works directly from browser code. Put your key in the api_key query parameter as usual, keeping in mind that anyone who opens DevTools on your page can read that key.
Why does ZenRows fail with a CORS error in the browser?
ZenRows sends no Access-Control-Allow-Origin header and answers preflights with 401, so the browser blocks the response; Scrapfly and Crawlbase fail the same way. All three take the key in the query string, so you can prefix the full API URL with https://proxy.cors.dev/. The proxy calls the API without your page's Origin header and adds CORS headers, and the key stays visible in your code.
How many credits does a JavaScript-rendered page cost?
ScrapingBee and ScrapingAnt turn headless browser rendering on by default for 5 credits and 10 credits per request, though both drop to 1 credit if you turn the browser off (render_js=false on ScrapingBee). ZenRows charges 5 credits for JavaScript rendering, Scrapfly adds 5 to the base cost, ScraperAPI charges 10 with render=true, and Crawlbase charges double for JavaScript requests. Firecrawl renders pages in its standard 1-credit scrape.
Can cors.dev render JavaScript or get past bot protection?
No, proxy.cors.dev is a plain HTTP proxy that returns the exact HTML the target server sends back, without running a headless browser, bypassing anti-bot protections, or forwarding browser cookies. If a site requires JavaScript rendering or residential proxies, call a scraping API like Firecrawl, ScrapingBee, ScrapingAnt or Jina Reader instead.