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/.

Free web scraping APIs called from a browser origin, checked October 2026
APIFree tierJavaScript renderingBrowser CORSNotes
FirecrawlKeyless scrape, or 1,000 credits a month with a free keyYes, 1 credit per pageYesCrawl, map and extract need a key
ScraperAPI1,000 credits a month, plus a 7-day trial with 5,000render=true costs 10 creditsYesKey in the query string
ScrapingBee1,000 trial credits, no cardOn by default, 5 creditsYesrender_js=false for a plain fetch
ZenRows5,000 credits a month5 creditsNoReadable through proxy.cors.dev
Scrapfly1,000 credits, one timeAdds 5 creditsNo, 403 when an Origin is sentReadable through proxy.cors.dev
Jina Reader20 requests a minute without a keyHeadless browser by defaultYes429 through proxies, call it directly
Apify$5 of usage a monthDepends on the ActorYesRuns ready-made scraper Actors
ScrapingAnt10,000 credits a monthOn by default, 10 creditsYes1 credit without the browser
Crawlbase1,000 credits, up to 5,000 after setupJavaScript requests cost 2xNoReadable through proxy.cors.dev
cors.dev free proxyNo key, no signupNoAdds CORS headersRaw 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/scrape with no key returned 200, Markdown and Access-Control-Allow-Origin: *. Call it directly, no proxy needed.
  • ScraperAPI: GET https://api.scraperapi.com/?api_key=KEY&url=TARGET echoed our origin in Access-Control-Allow-Origin. Call it directly.
  • ScrapingBee: GET https://app.scrapingbee.com/api/v1/?api_key=KEY&url=TARGET echoed our origin, and its preflight answered 200. Call it directly.
  • ZenRows: GET https://api.zenrows.com/v1/?apikey=KEY&url=TARGET sent no Access-Control-Allow-Origin and its preflight returned 401, so browsers block it. Through proxy.cors.dev its 401 for our test key came back readable.
  • Scrapfly: GET https://api.scrapfly.io/scrape?key=KEY&url=TARGET returned an empty 403 whenever the request carried an Origin header, so every browser call fails. Through proxy.cors.dev its JSON 401 for our test key came back readable.
  • Jina Reader: GET https://r.jina.ai/TARGET answered 200 with our origin echoed: 1,465 bytes of Markdown for example.com, 16,530 for news.ycombinator.com. Through proxy.cors.dev it answered 429 (Per IP rate limit exceeded), because proxy traffic shares IP addresses. Call it directly.
  • Apify: https://api.apify.com/v2/ sends Access-Control-Allow-Origin: * and allows the Authorization header. Call it directly.
  • ScrapingAnt: GET https://api.scrapingant.com/v2/general?url=TARGET&x-api-key=KEY sent Access-Control-Allow-Origin: *. Call it directly.
  • Crawlbase: GET https://api.crawlbase.com/?token=TOKEN&url=TARGET sent no Access-Control-Allow-Origin, so browsers block it; through proxy.cors.dev the 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.

Fetch a page through proxy.cors.dev and read its title and links
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:

  • GET and HEAD only; POST answers 405 with method_not_allowed in the X-Cors-Error response 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; Authorization and X-Api-Key headers get 400 header_not_allowed; other unsupported headers are dropped and named in X-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.

Read a page as Markdown from Jina Reader, called directly
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=true costs 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=false makes 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.