GuidesSEARCH APIS
Google Search API from JavaScript
Google's Custom Search JSON API sends CORS headers, so fetch() works from the page with no proxy, but Google closed it to new customers and ends it on 1 January 2027; existing customers get 100 free queries a day. For new projects, Serper returns Google results with CORS headers and 2,500 free queries, and SerpApi works through the free cors.dev proxy (no signup, GET and HEAD, about 600 requests a minute per IP) because its key rides in the URL. Fetching google.com/search itself through the proxy returned 429 or a script-only page with no results in our 28 October 2026 test.
Custom Search JSON API works in browsers
Google's Custom Search JSON API sends CORS headers, so you call it with fetch() directly, no proxy needed. On 28 October 2026, GET https://www.googleapis.com/customsearch/v1?key=<invalid>&cx=<invalid>&q=cors with Origin: https://example.com answered 400 with a 743-byte JSON error ("API key not valid. Please pass a valid API key.") and Access-Control-Allow-Origin: https://example.com. The customsearch.googleapis.com host, the /siterestrict variant and the OPTIONS preflight all echoed the origin the same way.
Each request needs an API key (key) and a Programmable Search Engine ID (cx). Results arrive in items, each with title, link and snippet, in JSON that follows the OpenSearch 1.1 specification; errors come back as an error object with code and message.
async function googleSearch(query, { key, cx, start = 1 }) {
const params = new URLSearchParams({ key, cx, q: query, start: String(start) });
const response = await fetch('https://www.googleapis.com/customsearch/v1?' + params);
const data = await response.json();
if (data.error) {
throw new Error(`Custom Search ${data.error.code}: ${data.error.message}`);
}
return (data.items ?? []).map(({ title, link, snippet }) => ({ title, link, snippet }));
}
// Results 11 to 20; start + num can never pass 100
const results = await googleSearch('cors proxy', {
key: 'YOUR_API_KEY',
cx: 'YOUR_SEARCH_ENGINE_ID',
start: 11,
});
console.log(results);num returns at most 10 results per request and start sets the first result, so start=11 is page 2. A query never yields more than 100 results, and start plus num above 100 is an error.
| Item | Value | Note |
|---|---|---|
| Free queries | 100 a day | Existing customers only |
| Paid queries | $5 per 1,000 | Existing customers only |
| Daily cap | 10,000 queries | Upper limit per day |
| Results per request | Up to 10 | Set with num |
| Results per query | Up to 100 | start plus num above 100 errors |
| New customers | Closed | Per Google's overview page |
| End of service | 1 January 2027 | Existing customers must move by then |
Closed to new customers, ending 2027
Google's overview page, last updated 18 February 2026 and read 28 October 2026, says: "The Custom Search JSON API is closed to new customers." Existing customers have until 1 January 2027 to move, and the pricing applies only to them until then.
Google calls Vertex AI Search a favorable alternative for searching up to 50 domains, and asks teams that need full web search to contact Google about its full web search solution. Whichever key you use, a key in browser code is readable by every visitor.
The Programmable Search Element widget
The Search Element is Google's embeddable search box and results page. Its markup carries only the engine ID, no API key, and it renders Google's own result UI, which can include ads; Google documents a separate ads-free paid version.
Google's January 2026 update positions it for site search: the free "Sites to search" feature covers up to 50 domains, and engines set to "Search the entire web" or more than 50 domains must move to another solution by 1 January 2027.
- Load the script
Add
<script async src="https://cse.google.com/cse.js?cx=YOUR_ENGINE_ID"></script>to the page. - Place the element
Put
<div class="gcse-search"></div>where the box and results go, or split them withgcse-searchboxandgcse-searchresults;gcse-searchbox-onlyandgcse-searchresults-onlyalso exist. - Configure it
Set options with
data-attributes such asdata-autoCompleteMaxCompletions="5"and hook into results through callbacks onwindow.__gcse.
Scraping google.com/search fails
https://www.google.com/search?q=cors, requested from a server in Germany on 28 October 2026, answered 200 with a page of about 94 KB that holds no results, only scripts and a note to click if the redirect does not happen. Through the free cors.dev proxy it answered either that same script-only page or 429 with a 3,213-byte page saying "Our systems have detected unusual traffic from your computer network", and hl=en&gl=us changed nothing.
The results page is HTML for people, not an API, and a proxy does not turn it into one.
SERP APIs that return Google results
- Serper (
google.serper.dev): Google results as JSON with CORS headers. The preflight answered204withAccess-Control-Allow-Origin: *andX-API-KEYallowed, and a bad key got a403with CORS headers. 2,500 free queries with no card, then $50 for 50,000 queries down to $0.30 per 1,000; credits last 6 months. - SerpApi (
serpapi.com): No CORS headers (401withoutAccess-Control-Allow-Origin,OPTIONSanswered404). The key rides in theapi_keyquery parameter, sohttps://proxy.cors.dev/forwards it as-is and returns CORS headers. Free plan 250 searches a month, paid from $25 for 1,000. - Brave Search API: Brave's own index, not Google's. No CORS headers,
405on the preflight, and the key goes inX-Subscription-Token, which the free proxy refuses with400 header_not_allowedand cors.dev Pro forwards. $5 per 1,000 requests with $5 of free credit a month. - Tavily (
api.tavily.com): Built for LLM apps, answered withAccess-Control-Allow-Origin: *, has a keyless mode and 1,000 free credits a month.
async function serperSearch(query, apiKey) {
const response = await fetch('https://google.serper.dev/search', {
method: 'POST',
headers: { 'X-API-KEY': apiKey, 'Content-Type': 'application/json' },
body: JSON.stringify({ q: query }),
});
const data = await response.json();
if (!response.ok) {
throw new Error(`Serper ${response.status}: ${data.message}`);
}
return data.organic ?? [];
}
const userKey = localStorage.getItem('serper_key');
const organic = await serperSearch('cors proxy', userKey);
for (const { position, title, link } of organic) {
console.log(position, title, link);
}| Option | Results from | Free allowance | Browser CORS | How to call it |
|---|---|---|---|---|
| Custom Search JSON API | 100 queries a day, existing customers | Yes | fetch() directly until 1 January 2027 | |
| SerpApi | 250 searches a month, 50 an hour | No | Free proxy, key in the URL | |
| Serper | 2,500 queries, no card | Yes | POST directly with X-API-KEY | |
| Brave Search API | Brave's own index | $5 credit a month | No | cors.dev Pro forwards the token header |
| google.com/search page | Google HTML | None | No | Not viable, 429 or no results |
The free proxy needs no signup, allows GET and HEAD at about 600 requests a minute per IP, and forwards query-string keys as-is. cors.dev Pro costs $5 a month for 500,000 requests, with a 7-day trial of 1,000 requests and no card, and adds POST and credential headers from origins you register.
Google autocomplete suggestions
For typeahead completions instead of result links, https://suggestqueries.google.com/complete/search?client=firefox&q=cors answered 200 with a 258-byte JSON array of 10 suggestions and no CORS header. Through the free proxy the same 258 bytes arrived with CORS headers. Google called it "a non-official, non-published API" in 2015; the Google autocomplete guide covers parameters, encodings and debouncing.
Good questions.
Can I still get a Google Custom Search JSON API key?
No. Google's overview page says the Custom Search JSON API is closed to new customers, and existing customers have until 1 January 2027 to move. For up to 50 domains Google points to Vertex AI Search; for full web search it asks you to contact Google.
Is there a free Google search API for JavaScript?
Not from Google for new projects. Serper gives 2,500 free queries without a card and works with fetch() directly; SerpApi's free plan gives 250 searches a month through https://proxy.cors.dev/. The Programmable Search Element is free for site search across up to 50 domains.
Which Google results API works with fetch() without a proxy?
Serper. Its preflight answered 204 with Access-Control-Allow-Origin: * and allows the X-API-KEY header, so a POST to https://google.serper.dev/search works from the page. Existing Custom Search JSON API customers can also call it directly until 1 January 2027.
Does a CORS proxy hide my Google search API key?
No. A key in browser JavaScript, in the URL or a header, is readable by every visitor, and cors.dev does not change that. Keep your own key on a backend for public products, or let each user bring their own key.
Can I show Google results on my site without an API key?
Yes, with the Programmable Search Element: load https://cse.google.com/cse.js?cx=YOUR_ENGINE_ID and add <div class="gcse-search"></div>. It needs only the engine ID and renders Google's own UI, which can include ads. Since Google's January 2026 update, it targets site search across up to 50 domains.