GuidesSEARCH APIS

SerpApi from browser JavaScript

SerpApi answers browser requests without an Access-Control-Allow-Origin header and its preflight returns 404, so fetch() from a page fails even with a valid key. Because the key travels in the api_key query parameter, the free proxy at https://proxy.cors.dev/ carries the request as-is: no signup, GET and HEAD, about 600 requests a minute per IP. We tested 4 SerpApi endpoints on 28 October 2026, and the free SerpApi plan gives 250 searches a month.

Why fetch() to SerpApi fails in browsers

On 28 October 2026 we sent GET https://serpapi.com/search.json?engine=google&q=cors&api_key=<invalid key> with Origin: https://example.com, the header a browser page sends. SerpApi answered 401 with a 97-byte JSON error and no Access-Control-Allow-Origin header. The keyless locations.json answered 200 without that header too, so successful responses are blocked the same way and fetch() rejects with a CORS error.

An OPTIONS request to the same URL answered 404 without CORS headers. A plain GET needs no preflight, but any custom header such as Authorization makes the browser send one first, and that preflight fails.

SerpApi's official package, serpapi on npm (version 2.2.1, getJson({ engine, q, api_key })), documents Node.js 7.10.1 and newer and Deno, not browsers. Run it on a server.

Call SerpApi through the free proxy

The same test URL prefixed with https://proxy.cors.dev/ came back with the identical 401 and 97-byte body, now with Access-Control-Allow-Origin set to the page origin. That proves the api_key query parameter reaches SerpApi and the answer reaches your code.

  1. Build the URL

    Put engine, q and api_key into URLSearchParams on https://serpapi.com/search.json.

  2. Prefix the proxy

    Prepend https://proxy.cors.dev/ and call fetch() without custom headers.

  3. Check both error layers

    Read X-Cors-Error for proxy refusals, then SerpApi's error field, before you use organic_results.

Search SerpApi from the browser through the free proxy
const PROXY = 'https://proxy.cors.dev/';

async function serpSearch(query, apiKey) {
  const params = new URLSearchParams({ engine: 'google', q: query, api_key: apiKey });
  const response = await fetch(PROXY + 'https://serpapi.com/search.json?' + params);

  const proxyError = response.headers.get('X-Cors-Error');
  if (proxyError) throw new Error(`cors.dev refused the request: ${proxyError}`);

  const data = await response.json();
  if (data.error) throw new Error(`SerpApi ${response.status}: ${data.error}`);

  return data.organic_results ?? [];
}

const apiKey = localStorage.getItem('serpapi_key');
const results = await serpSearch('cors proxy', apiKey);

for (const { position, title, link } of results) {
  console.log(position, title, link);
}

The free proxy needs no signup and no key. It allows GET and HEAD, about 600 requests a minute per IP, responses up to 6 MiB and a 30-second upstream deadline, with no caching. An Authorization header gets 400 with X-Cors-Error: header_not_allowed, and SerpApi never needs one.

cors.dev Pro ($5 a month for 500,000 requests, 7-day trial with 1,000 requests, no card) adds POST and credential headers such as X-Subscription-Token, from origins you register. SerpApi does not need it, because its key travels in the URL.

Where your SerpApi key should live

A key in browser code, in a URL or a header, is readable by anyone who opens the page or its network tab. cors.dev does not hide it, and whoever holds your key can spend your searches.

  • Prototypes and internal tools: Your own key in the page is acceptable when only you or your team load it.
  • Bring-your-own-key apps: Each user pastes their own SerpApi key, for example into localStorage, and spends their own searches.
  • Public products on your key: Call SerpApi from your backend and send only the results to the page.

SerpApi endpoints tested in the browser

SerpApi endpoints from browser JavaScript, checked October 2026
EndpointNeeds a keyDirect fetch()Through the free proxy
search.json, engine=googleYes401 without CORS headers, blocked401 with CORS headers, 97 bytes
search.json, engine=google_autocompleteYes401 without CORS headers, blocked401 with CORS headers
locations.jsonNo200 without CORS headers, blocked200 with CORS headers, 1,196 bytes
account.jsonYes401 without CORS headers, blocked401 with CORS headers

locations.json?q=Austin&limit=3 needs no key, so it works through the free proxy with nothing to protect. Each location has canonical_name, country_code, target_type, reach and gps. Use it to look up a valid location value for searches.

Look up SerpApi locations without a key
const params = new URLSearchParams({ q: 'Austin', limit: '3' });
const response = await fetch('https://proxy.cors.dev/https://serpapi.com/locations.json?' + params);

if (!response.ok) {
  throw new Error(`HTTP ${response.status} ${response.headers.get('X-Cors-Error') ?? ''}`);
}

const locations = await response.json();

for (const { canonical_name, target_type, reach } of locations) {
  console.log(canonical_name, target_type, reach);
}
// Austin,Texas,United States City 6440000

SerpApi pricing and the free plan

We read SerpApi's pricing page on 28 October 2026. Plans are month-to-month and you can cancel anytime.

SerpApi plans, checked October 2026
PlanPrice per monthSearches per monthSearches per hour
Free$025050
Starter$251,000200
Developer$755,0001,000
Production$15015,0003,000
Big Data$27530,0006,000

Bigger plans: Searcher at $725 for 100,000 searches, Volume at $1,475 for 250,000, Infrastructure at $2,750 for 500,000, and Cloud plans from $3,750 for 1 million up to $69,375 for 35 million a month.

Only successful searches count; cached and errored searches are not charged. SerpApi refunds within 7 days unless more than 20% of the searches were used.

SerpApi alternatives for browser apps

Search APIs from browser JavaScript, checked October 2026
APIFree allowanceWhere the key goesBrowser CORScors.dev route
SerpApi250 searches a month, 50 an hourapi_key query parameterNone, OPTIONS answers 404Free proxy
Serper2,500 queries, no cardX-API-KEY headerAccess-Control-Allow-Origin: *None, call it directly
Brave Search API$5 credit a month, about 1,000 requestsX-Subscription-Token headerNone, OPTIONS answers 405cors.dev Pro
Google Custom Search JSON API100 queries a day, existing customers onlykey query parameterEchoes the page originNone, call it directly
Tavily1,000 credits a monthAuthorization headerAccess-Control-Allow-Origin: *None, call it directly

Serper, another Google results API, answered its preflight with 204, Access-Control-Allow-Origin: * and X-API-KEY in the allowed headers, and an invalid key got a 403 carrying the same CORS header. Call it directly; the key is just as visible in the page. It gives 2,500 free queries without a card, and paid credits run from $50 for 50,000 queries to $3,750 for 12.5 million ($0.30 per 1,000), valid for 6 months.

Brave runs its own index but sends no CORS headers and needs the X-Subscription-Token header, which only cors.dev Pro forwards. Google closed the Custom Search JSON API to new customers and ends it on 1 January 2027.

Good questions.

Can I use the serpapi npm package in the browser?

Its README documents Node.js 7.10.1 and newer and Deno, not browsers, so run serpapi 2.2.1 on a server. In the browser, call search.json with fetch() through https://proxy.cors.dev/ instead.

Why does the cors.dev proxy return 400 header_not_allowed for my SerpApi request?

The free proxy refuses credential headers such as Authorization or X-Api-Key with 400 and X-Cors-Error: header_not_allowed. SerpApi reads the key from the api_key query parameter, so drop the header and keep the key in the URL.

Does a CORS proxy hide my SerpApi key?

No. Anything in browser code, URL or header, is visible to every visitor in the network tab, and cors.dev does not change that. Use your own key in the browser only for prototypes and internal tools, and call SerpApi from your backend for a public product.

Do failed searches count against my SerpApi plan?

No. SerpApi counts only successful searches; cached and errored searches are not charged. The free plan allows 250 successful searches a month and 50 an hour.

Do I need cors.dev Pro to call SerpApi?

No. SerpApi uses GET with the key in the query string, which the free proxy forwards as-is, with no signup and about 600 requests a minute per IP. Pro ($5 a month for 500,000 requests) is for APIs that need POST or a key header, such as Brave's X-Subscription-Token.