Google Custom Search API in Python
The call that still answers.
Google ends the Custom Search JSON API on January 1, 2027, and it is already closed to new customers. A new Google key no longer comes with it.
SpecStream answers the same GET /customsearch/v1 in Google's JSON. In Python, set the base address to https://api.specstream.ai and pass a SpecStream key as key. items[], start and queries.nextPage work as on Google.
It is the most accurate web search API in the world: 97.9 F-score on all 1,000 SimpleQA Verified questions, on the benchmarks page. Searches cost $5 per 1,000.
New accounts get $10 of credit, no card. It covers 2,000 searches.
The Custom Search call from Python: 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. cx is accepted and not used | 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, a different request and reply |
| Open to new customers | Yes. Create a key in a minute and start 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, read 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. A call of up to 10 results is $0.005 | $5 per 1,000 queries after 100 free queries a day, for existing customers | $1.50 per 1,000 queries on Search Standard Edition, $4.00 on Search Enterprise Edition |
| What Python 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 includes generated answers, at $4.00 per 1,000 queries |
| Results a call | num from 1 to 10, as on Google. Up to 100 in one search on GET /v1/web-search | 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 |
| What a call costs when it fails | A 429 with Retry-After charges nothing. With an Idempotency-Key, a retried call is charged once | 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 Python code that called Custom Search moves to SpecStream
The call with requests
This is the whole program. It reads items[] as Google's reply had them, and treats a missing items as no results, which is how Google answers a search that finds nothing.
import os
import requests
BASE = "https://api.specstream.ai" # was https://www.googleapis.com
KEY = os.environ["SPECSTREAM_API_KEY"]
reply = requests.get(
f"{BASE}/customsearch/v1",
params={"key": KEY, "q": "open source vector databases", "num": 10},
timeout=30,
)
if reply.status_code != 200:
raise RuntimeError(reply.json()["error"]["message"])
data = reply.json()
print(data["searchInformation"]["totalResults"], "results")
for item in data.get("items", []):
print(item["title"], item["link"], item["snippet"], sep="\n ")An error comes back in Google's shape, {"error": {"code", "message", "errors", "status"}}, so code that reads error.message keeps working.
The same call with urllib, no package to install
import json
import os
import urllib.parse
import urllib.request
params = urllib.parse.urlencode({
"key": os.environ["SPECSTREAM_API_KEY"],
"q": "open source vector databases",
"num": 10,
})
url = f"https://api.specstream.ai/customsearch/v1?{params}"
with urllib.request.urlopen(url, timeout=30) as response:
data = json.load(response)
for item in data.get("items", []):
print(item["title"], item["link"])Paging with start and queries.nextPage
start is 1-based, as on Google. Each reply carries queries.nextPage[0].startIndex while there are more results, so the loop asks for the next page until it is gone. Each page is one search at $0.005.
import os
import requests
URL = "https://api.specstream.ai/customsearch/v1"
KEY = os.environ["SPECSTREAM_API_KEY"]
def search(q, pages=3):
start, found = 1, []
for _ in range(pages):
data = requests.get(
URL, params={"key": KEY, "q": q, "num": 10, "start": start}, timeout=30
).json()
found += data.get("items", [])
next_page = data.get("queries", {}).get("nextPage")
if not next_page:
break
start = next_page[0]["startIndex"]
return found
for item in search("open source vector databases"):
print(item["link"])The parameters your code already sends
q, num and start work as on Google. exactTerms, orTerms, siteSearch and hq shape the search as they do there, and fields cuts the reply to the parts you name. The key also works in the X-Goog-Api-Key header or as a Bearer token. searchType=image is refused with a 400: this route returns web results.
$5 per 1,000 searches and the best scores published
A call of up to 10 results is $0.005, with no daily limit, and a 429 charges nothing. 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 fast search took 0.82 s at 1 search a second and 1.07 s at 20 a second.
What is kept from a search
Only the charge's account, key, request ID, price and time, on a key with zero retention: no request text and no answer after the reply. Set "zero_retention": true on the key when you create it, 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 returns every match for a request in plain words as structured rows at 5¢, 15¢ or $1 a row, and quotes the most a run can cost before it starts.
Other options for the Custom Search JSON API in Python
Vertex AI Search
Google's suggestion for searching up to 50 domains, at $1.50 per 1,000 queries on Search Standard Edition. It takes a POST to discoveryengine.googleapis.com with its own request and reply, so the Python code is rewritten. SpecStream answers the call your code already sends, on the whole web.
Grounding with Google Search in the Gemini API
A Gemini model searches and writes an answer grounded in the results. On Gemini 3 and newer it costs $14 per 1,000 search requests after 5,000 free a month. Your code gets the model's answer. SpecStream returns items[] to your code 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. Its guide describes the move as swapping the endpoint and updating how you read the response. On SpecStream the Python that reads Google's response stays.
How SpecStream scores
The same numbers as the benchmarks page, from the official tasks and scorers.
How to run the Python 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.
export SPECSTREAM_API_KEY="your key"
pip install requests3. Run the requests example above. In code that already calls Google, change https://www.googleapis.com or https://customsearch.googleapis.com to https://api.specstream.ai and the key. cx can stay in the call.
If your code uses Google's own client library, change one line. google-api-python-client and googleapis for Node both work against https://api.specstream.ai: set the address where the client is built, put the SpecStream key where Google's key went, and cse().list(q=..., cx=...) stays as it is. Tested on November 10, 2026 with versions 2.201.0 and 189.0.0.
# Python: google-api-python-client
from googleapiclient.discovery import build
service = build("customsearch", "v1", developerKey=SPECSTREAM_API_KEY,
client_options={"api_endpoint": "https://api.specstream.ai"})
reply = service.cse().list(q="open source vector databases", cx="any").execute()
// Node: googleapis
const customsearch = google.customsearch({ version: "v1", auth: SPECSTREAM_API_KEY, rootUrl: "https://api.specstream.ai/" });
const reply = await customsearch.cse.list({ q: "open source vector databases", cx: "any" });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 Python?
GET /customsearch/v1 with key, q and num using requests or urllib, 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.Do I need the google-api-python-client package?
requests is enough, as in the example above. If your code already uses google-api-python-client, keep it: pass client_options={"api_endpoint": "https://api.specstream.ai"} to build, put the SpecStream key in developerKey, and service.cse().list(q=..., cx=...).execute() works as before. Tested on November 10, 2026 with version 2.201.0.How do I get more than 10 results in Python?
start: 1, then 11, then 21, or read queries.nextPage[0].startIndex from each reply. On the same key, GET https://api.specstream.ai/v1/web-search returns up to 100 results in one search for $0.059.Do I still need a search engine ID (cx)?
cx is accepted and not used, so code that sends it runs unchanged. SpecStream searches the whole live web, and siteSearch keeps a search to one site.What does the Custom Search JSON API cost?
Why does my code get a KeyError on items?
items key, on Google and on SpecStream. Read it with data.get("items", []), as the examples here do.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.
- 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




