Google Custom Search API in JavaScript
The call that still answers.
Google ends the Custom Search JSON API on January 1, 2027, and it is closed to new customers. A new project gets no key, and Node.js code that calls it stops on that day.
SpecStream answers the same call. In googleapis 189.0.0 or @googleapis/customsearch 12.0.1, set rootUrl to https://api.specstream.ai/ and pass a SpecStream key as key. Both clients ran cse.list against it on November 10, 2026 and got 10 items.
Searches cost $5 per 1,000, the rate Google charges, with no cap of 10,000 a day. SpecStream scores 97.9 F-score on all 1,000 SimpleQA Verified questions, shown on the benchmarks page.
New accounts get $10 of credit, no card. It covers 2,000 searches.
The Custom Search call from Node.js: SpecStream, Google and Vertex AI Search
| SpecStream | Google Custom Search JSON API | Vertex AI Search | |
|---|---|---|---|
| The call | GET https://api.specstream.ai/customsearch/v1 with key, q, num and start. Any cx is accepted | GET https://www.googleapis.com/customsearch/v1 with q, an API key and cx, the ID of a Programmable Search Engine you configured | POST https://discoveryengine.googleapis.com/v1/{servingConfig}:search, with its own request and reply |
| Google's client library | googleapis 189.0.0 and @googleapis/customsearch 12.0.1 with rootUrl: "https://api.specstream.ai/". Both ran cse.list on November 10, 2026 and returned 10 items | The same client, on Google's address and a Google key, for existing customers until January 1, 2027 | Not the Custom Search client: the call is a POST to discoveryengine.googleapis.com, so the cse.list code is rewritten |
| Open to new customers | Yes. A key takes a minute and comes with $10 of credit, no card | No. Closed to new customers, and discontinued on January 1, 2027 | Yes, with a free trial of 10,000 queries per account a month |
| What it searches | The whole live web at the moment of the call. siteSearch keeps a search to one site | The Programmable Search Engine you configured | Up to 50 domains. For full web search, Google asks you to contact it |
| Price per 1,000 | $5 per 1,000 searches of up to 10 results, with no daily cap | $5 per 1,000 queries after 100 free queries a day, up to 10,000 a day, for existing customers | $1.50 per 1,000 queries on Search Standard Edition, $4.00 on Search Enterprise Edition |
| What your code reads | Google's JSON: items with title, link, snippet, displayLink, htmlTitle, htmlSnippet and formattedUrl, searchInformation.totalResults and queries.nextPage | An items array with the URL, title and text snippets of each result, in JSON | Search Enterprise Edition adds generated answers, at $4.00 per 1,000 queries |
| Results a call | num from 1 to 10, as on Google, and start for the next page | 1 to 10 results a call, and never more than 100 for a query | Billed per query: any API call to Enterprise Search counts as one |
| A busy or failed call | A busy call answers 429 in Google's error form with Retry-After, and is not charged | Its terms say you may be charged for each successful request | A request is any API call, direct or through an integration or the console |
Why Node.js code that called Custom Search moves to SpecStream
googleapis: the same call with one changed option
This is code that calls Google today, with googleapis 189.0.0:
import { google } from "googleapis";
const customsearch = google.customsearch({ version: "v1" });
const res = await customsearch.cse.list({
q: "web data api",
cx: process.env.GOOGLE_CSE_ID,
key: process.env.GOOGLE_API_KEY,
});
console.log(res.data.items.length, res.data.items[0].title);And the same code on SpecStream. rootUrl on google.customsearch is set to https://api.specstream.ai/ and the key is a SpecStream key. cse.list, its parameters and the code that reads res.data.items stay as they were. This is the call that ran on November 10, 2026 and printed 10 items.
import { google } from "googleapis";
const customsearch = google.customsearch({
version: "v1",
rootUrl: "https://api.specstream.ai/", // the one changed option
});
const res = await customsearch.cse.list({
q: "web data api",
cx: process.env.GOOGLE_CSE_ID, // any value is accepted
key: process.env.SPECSTREAM_API_KEY,
});
console.log(res.data.items.length, res.data.items[0].title);With @googleapis/customsearch 12.0.1 the option is the same, rootUrl on customsearch({ version: "v1", rootUrl }). It ran the same day and returned 10 items.
import { customsearch } from "@googleapis/customsearch";
const client = customsearch({ version: "v1", rootUrl: "https://api.specstream.ai/" });
const res = await client.cse.list({ q: "web data api", cx: "any", key: process.env.SPECSTREAM_API_KEY });
for (const item of res.data.items ?? []) console.log(item.title, item.link);The same call with fetch, no package to install
fetch is built into Node.js 18 and newer. The reply is Google's JSON: items with title, link and snippet, searchInformation.totalResults and queries.nextPage. A search that finds nothing has no items, as on Google, so the loop reads data.items ?? [].
const params = new URLSearchParams({
key: process.env.SPECSTREAM_API_KEY,
cx: "any",
q: "open source vector databases",
num: "10",
});
const reply = await fetch(`https://api.specstream.ai/customsearch/v1?${params}`);
if (reply.status === 429) {
console.log("busy, retry after", reply.headers.get("Retry-After"), "s");
} else {
const data = await reply.json();
if (!reply.ok) throw new Error(data.error.message);
console.log(data.searchInformation.totalResults, "results");
for (const item of data.items ?? []) {
console.log(item.title, item.link, item.snippet);
}
}An error comes back in Google's shape, {"error": {"code", "message", "errors", "status"}}, so code that reads error.message keeps working.
Paging with start and queries.nextPage
start is 1-based, as on Google. Each reply carries queries.nextPage while more results exist, so the loop stops when it is gone. Each page of up to 10 results is one search at $0.005.
const URL_BASE = "https://api.specstream.ai/customsearch/v1";
async function search(q, pages = 3) {
let start = 1;
const found = [];
for (let i = 0; i < pages; i++) {
const params = new URLSearchParams({ key: process.env.SPECSTREAM_API_KEY, cx: "any", q, num: "10", start: String(start) });
const data = await (await fetch(`${URL_BASE}?${params}`)).json();
found.push(...(data.items ?? []));
const next = data.queries?.nextPage;
if (!next) break;
start = next[0].startIndex;
}
return found;
}
for (const item of await search("open source vector databases")) console.log(item.link);The parameters your code already sends
The route honours nine parameters as Google does: q, num, start, hq, exactTerms, orTerms, excludeTerms, siteSearch and siteSearchFilter. fileType, dateRestrict, lowRange and highRange are accepted and not applied, so code that sends them still gets results. Any cx is accepted. Every parameter and every field is listed in the migration guide.
$5 per 1,000 searches and the best published scores
A call of up to 10 results is $0.005, with no cap of 10,000 a day, and a busy call that answers 429 is not charged. SpecStream scores 97.9 F-score on all 1,000 SimpleQA Verified questions (978 correct) and 64.0 item F1 and 43.4 row F1 on all 200 WideSearch tasks. On production on November 9, 2026, the median search took 0.82 s at 1 search a second and 1.07 s at 20 a second.
What is kept from a search
On a key with zero retention, only the charge's account, key, request ID, price and time: no request text and no answer after the reply. Set "zero_retention": true when you create the key, or later on the same key.
The same key reads pages and returns rows
The Extract API reads up to 20 pages or documents a call at $0.80 per 1,000 pages and scores 0.908 F1 on WCXB. Deep Search takes a request in plain words and returns every match as structured rows at 5¢, 15¢ or $1 a row, with the most a run can cost quoted before it starts.
Other options for the Custom Search JSON API in JavaScript and Node.js
Vertex AI Search
The product Google points Custom Search customers to, for up to 50 domains, at $1.50 per 1,000 queries on Search Standard Edition. Its call is a POST to discoveryengine.googleapis.com with a different request and reply, so the Node.js code that reads items is rewritten. SpecStream answers the cse.list call you already send, across the whole web.
Grounding with Google Search in the Gemini API
A Gemini model runs the searches and writes an answer grounded in the results, at $14 per 1,000 search requests on Gemini 3 and newer after 5,000 free a month. Your code receives the model's answer. SpecStream returns items with title, link and snippet at $5 per 1,000.
Brave Search API
A search API on Brave's own index at $5 per 1,000 requests, with $5 in free credits every month and 50 queries per second. Brave's own guide says moving from Google means swapping the endpoint and updating how you read the response. On SpecStream the code that reads Google's response stays as it is.
How SpecStream scores
The same numbers as the benchmarks page, from the official tasks and scorers.
How to run the Node.js example
1. Create a key under Agents & API in the workspace. A new account gets $10 of credit, no card, which covers 2,000 searches.
2. Put it in the environment and install the client if you use it.
export SPECSTREAM_API_KEY="your key"
npm install googleapis3. In code that uses googleapis, add rootUrl: "https://api.specstream.ai/" where google.customsearch is built and pass the SpecStream key as key. In code that calls the URL with fetch or axios, change https://www.googleapis.com or https://customsearch.googleapis.com to https://api.specstream.ai.
4. Check the address with curl. A 200 with items means the key and the route work.
curl "https://api.specstream.ai/customsearch/v1?key=$SPECSTREAM_API_KEY&cx=any&q=web+data+api&num=3"The same call from Python, with requests and with google-api-python-client, is on the Python page. What changes on January 1, 2027 is on the shutdown page.
When your product needs every match in place of a results page, write the request in plain words. SpecStream reads it back as the conditions every row must meet and the facts to bring back, quotes the most it can cost, and delivers the rows after you approve.
Frequently asked questions
Something we didn't answer? Talk to a human
How do I use the Google Custom Search API in JavaScript?
GET /customsearch/v1 with key, cx and q from fetch or googleapis, and read items. Google closed the API to new customers and ends it on January 1, 2027. The same call works at https://api.specstream.ai/customsearch/v1 with a SpecStream key.Is there an npm package for the Google Custom Search API?
googleapis and @googleapis/customsearch. On November 10, 2026, version 189.0.0 of the first and 12.0.1 of the second ran cse.list against SpecStream with rootUrl set to https://api.specstream.ai/, and each returned 10 items.Can I keep my googleapis customsearch Node example?
rootUrl: "https://api.specstream.ai/" to google.customsearch({ version: "v1" }) and send a SpecStream key as key. cse.list, cx and the code that reads res.data.items stay as they are.Which parameters does the route honour?
q, num, start, hq, exactTerms, orTerms, excludeTerms, siteSearch and siteSearchFilter. fileType, dateRestrict, lowRange and highRange are accepted and not applied, and any cx is accepted.What does the Google Custom Search API cost?
What happens when a call is busy?
429 in Google's error form with a Retry-After header, and it is not charged. Wait the number of seconds in Retry-After and send the call again.Sources
SpecStream wrote this page. Each figure about Google comes from Google's own pages, and each other figure from that company's own page. The client runs are from November 10, 2026.
- Google Custom Search JSON API overviewdevelopers.google.com/custom-search/v1/overview, read Nov 9, 2026
- Google Custom Search JSON API reference, cse.listdevelopers.google.com/custom-search/v1/reference/rest/v1/cse/list, read Nov 9, 2026
- Google Custom Search JSON API, using RESTdevelopers.google.com/custom-search/v1/using_rest, read Nov 9, 2026
- Google Custom Search terms of servicedevelopers.google.com/custom-search/terms, read Nov 9, 2026
- Programmable Search Engine blog: updates to our web search productsprogrammablesearchengine.googleblog.com/2026/01/updates-to-our-web-search-products.html, read Nov 9, 2026
- Google Cloud: Agent Search pricingcloud.google.com/generative-ai-app-builder/pricing, read Nov 9, 2026
- Google Cloud: servingConfigs.search methodcloud.google.com/generative-ai-app-builder/docs/reference/rest/v1/projects.locations.collections.engines.servingConfigs/search, read Nov 9, 2026
- Gemini API: Grounding with Google Searchai.google.dev/gemini-api/docs/google-search, read Nov 9, 2026
- Brave Search APIbrave.com/search/api/, read Nov 9, 2026
- Brave, alternatives to the Google Search APIbrave.com/learn/google-api-shutdown/, read Nov 9, 2026
- SpecStream benchmarksspecstream.ai/benchmarks, read Nov 10, 2026
- SpecStream pricingspecstream.ai/pricing, read Nov 10, 2026
- SpecStream for agentsspecstream.ai/agents.md, read Nov 10, 2026




