Skip to content
CrawlerData
Menu
Guides

Google Custom Search API alternatives: what to use before it shuts down on January 1, 2027

The Custom Search JSON API is closed to new users and ends January 1, 2027. What Google offers instead, SERP API options, and a field-by-field migration.

CrawlerData teamPublished 10 min read

Contents

Google’s Custom Search JSON API is closed to new customers, and existing customers have until January 1, 2027 to move off it. If your product calls customsearch/v1 today, you need a replacement before then. This guide covers what Google itself offers instead, the third-party options, and a field-by-field migration to a SERP API with working Python.

What Google announced

The notice sits at the top of the Custom Search JSON API overview. As of October 2026 it says:

  • “The Custom Search JSON API is closed to new customers.”
  • “Vertex AI Search is a favorable alternative for searching up to 50 domains.”
  • For full web search, Google asks you to contact it through a form “to express your interest in and get more information about our full web search solution.”
  • “Existing Custom Search JSON API customers have until January 1, 2027 to transition to an alternative solution.”

The same page still lists the pricing for existing customers: 100 queries a day free, then $5 per 1,000 queries, up to 10,000 queries a day.

So there are two different problems, depending on how you used it:

  1. You searched your own site or a fixed list of sites. Google points you to Vertex AI Search.
  2. You searched the whole web (a Programmable Search Engine set to search the entire web). Google has no self-serve replacement listed. You fill in a form.

What Google offers instead

Google Cloud’s documentation carries a banner saying “Vertex AI Search is being renamed to Agent Search” (Google Cloud docs, as of October 2026). The docs describe two kinds of custom search: searching “within your public websites” and searching “within data stores containing your proprietary data.”

That is a site search product. You index sites and data you choose, and it searches them. It does not return Google’s public web results for any query, which is why Google’s notice handles “full web search” separately. It also has its own setup (a Google Cloud project, data stores, domain verification for websites) and its own pricing, so treat it as a new integration, not a key swap.

A partner-only full web search API

Search Engine Journal reported on September 11, 2026 that Google had documented a Web Search Service API whose main method performs a “full web search”, and that every request needs a client ID tied to a partner agreement. The article notes the pages did not say how to become a partner or what it costs. Until Google publishes terms, you cannot plan a migration around it.

Your options, side by side

If you need Google’s web results, the practical options are third-party APIs. They fall into two groups:

  • SERP APIs fetch Google’s results page for your query and return it as JSON. The output is Google’s ranking, which is closest to what Custom Search set to “search the entire web” gave you. Examples: SerpApi, Serper, DataForSEO and CrawlerData.
  • Independent search engine APIs return results from their own index, not Google’s. Brave Search API is the best-known example. Results will differ from Google’s, which may or may not matter for your use.
Option Results from Price, as of Oct 2026 Free to start Source
Custom Search JSON API (existing customers only) Google $5 per 1,000 after 100 free a day, max 10k a day 100 queries a day Google
Vertex AI Search / Agent Search Your sites and data stores Google Cloud pricing Not covered here Google Cloud
Brave Search API Brave’s own index $5 per 1,000 queries, pay as you go $5 of free credits a month Brave
SerpApi Google From $25 for 1,000 searches a month 250 searches a month Pricing
Serper Google $50 for 50k credits down to $0.30 per 1,000 2,500 queries serper.dev
CrawlerData Google $50 for 50k credits down to $0.30 per 1,000 50 credits (work email) Pricing

A few notes on the table:

  • Serper’s packs and ours have the same prices, the same credit amounts and the same 6-month validity.
  • Brave’s figure is from Brave’s own page about the Google shutdown. Check its dashboard for current plans.
  • For more providers, including DataForSEO’s queue-based pricing, see the cheapest SERP API comparison.

Choose CrawlerData if…

  • You need Google’s public web results after January 1, 2027, for rank checks, research or grounding an LLM in what Google shows, or you are a new customer who can’t sign up for the JSON API.
  • You want the whole results page, not just ten links. AI Overview with its cited sources, People Also Ask, ads, the local pack, top stories, the knowledge panel and related searches come back in the same response.
  • You need more than 10,000 queries a day. There is no daily cap, and batches run on the fast or regular queue with a webhook or polling, at the same price as live requests.
  • You want to pay per request without a subscription. Packs run from $1.00 down to $0.30 per 1,000 requests, credits are valid for 6 months, and failed requests are never charged.

Field mapping: Custom Search to a SERP API

The rest of this guide migrates a Custom Search call to the CrawlerData Google Search API. Other SERP APIs differ in names, but the shape of the work is the same.

Request parameters

The Custom Search request is a GET to https://customsearch.googleapis.com/customsearch/v1 (reference). Ours is a POST to https://api.crawlerdata.com/v1/jobs with a JSON body.

Custom Search CrawlerData google-search Notes
key Authorization: Bearer header Keep the key in an environment variable.
cx none No engine ID needed: you search Google directly.
q query Same query string, operators included.
gl country 2-letter code, one of 31 countries. Default us.
hl language 2-letter code. Default en.
num (1 to 10) none One request returns one results page.
start (start + num ≤ 100) page (1 to 10) page = (start - 1) // 10 + 1.
siteSearch site: in query For example site:docs.python.org asyncio.
none device desktop or mobile.

Response fields

Custom Search CrawlerData Notes
items[] organic_results[]
items[].title organic_results[].title
items[].link organic_results[].link The real destination URL.
items[].snippet organic_results[].snippet
items[].displayLink organic_results[].displayed_link Different format: ours is what Google shows, such as https://stackoverflow.com › pricing. Derive the host from link if you need www.example.com.
items[].formattedUrl use link
searchInformation.totalResults (string) search_information.total_results (number)
none position, ads, ai_overview, people_also_ask, local_pack, top_stories, knowledge_panel, related_searches Parts of the results page Custom Search did not return.

Before and after, in Python

Here is a typical Custom Search call:

import os
import requests

def search(query, start=1):
    resp = requests.get(
        "https://customsearch.googleapis.com/customsearch/v1",
        params={
            "key": os.environ["GOOGLE_API_KEY"],
            "cx": os.environ["GOOGLE_CSE_ID"],
            "q": query,
            "gl": "us",
            "hl": "en",
            "num": 10,
            "start": start,
        },
        timeout=30,
    )
    resp.raise_for_status()
    return resp.json().get("items", [])

for item in search("python asyncio timeout"):
    print(item["title"], item["link"], item["snippet"], sep="\n  ")

And the same function against the Google Search API. It returns items in the Custom Search shape, so the code that consumes them does not change:

import os
import time
from urllib.parse import urlparse

import requests

API_URL = "https://api.crawlerdata.com/v1/jobs"
HEADERS = {"Authorization": f"Bearer {os.environ['CRAWLERDATA_API_KEY']}"}


def google_search(query, country="us", language="en", page=1, retries=2):
    body = {
        "endpoint": "google-search",
        "params": {"query": query, "country": country, "language": language, "page": page},
        "queue": "live",
    }
    error = None
    for attempt in range(retries + 1):
        resp = requests.post(API_URL, json=body, headers=HEADERS, timeout=200)
        if resp.status_code in (400, 401, 402):
            raise RuntimeError(resp.json()["error"]["message"])  # retrying will not help
        if resp.status_code == 429 or resp.status_code >= 500:
            error = f"HTTP {resp.status_code}"
        else:
            data = resp.json()
            if data["job"]["status"] == "completed":
                return data["result"]
            error = data["job"]["error"]  # failed jobs cost 0 credits
        time.sleep(5 * 2 ** attempt)
    raise RuntimeError(f"search failed: {error}")


def search(query, start=1):
    """Drop-in for the old function: same arguments, Custom Search-shaped items."""
    page = (start - 1) // 10 + 1
    result = google_search(query, page=page)
    return [
        {
            "title": r["title"],
            "link": r["link"],
            "snippet": r.get("snippet") or "",
            "displayLink": urlparse(r["link"]).netloc,
            "formattedUrl": r["link"],
        }
        for r in result.get("organic_results", [])
    ]

Three things changed besides the URL:

  • The timeout is 200 seconds. A live request runs the whole fetch before it answers, so give the client a generous timeout. In our tests for this post, Google searches took 5 to 7 seconds. For batches, use the fast or regular queue and collect results by polling or webhook.
  • Failed jobs are free. If a fetch fails, the job comes back with status: "failed", an error message and 0 credits charged, and the function retries it.
  • displayLink is derived. If your UI showed the host name, urlparse(link).netloc gives you the same thing Custom Search did.

Things that work differently

Site restriction moves into the query. A Programmable Search Engine kept its list of sites in the cx settings. A SERP API searches Google as a user would, so you restrict results with site:example.com in the query. In our tests a single site: returned only pages from that site, while two site: operators joined with OR came back dominated by one of the two sites. For a list of sites, send one query per site or filter results by domain on your side.

You get the whole results page. A SERP API returns the results page itself, including ads, the AI Overview and People Also Ask when Google shows them. If you only want the ten blue links, read organic_results and ignore the rest.

Pagination is by page, not offset. Pages 1 to 10, one request each, 1 credit each. Custom Search stopped at 100 results, so ten pages covers the same depth.

No daily cap. Custom Search capped paid use at 10,000 queries a day. Our limits are per minute: 100 requests per minute and 20 per second per API key. For a big batch, submit jobs on the fast or regular queue and collect results by polling or webhook. All queues cost the same.

Cost: before and after

Custom Search cost $5 per 1,000 queries after the free 100 a day, per Google’s page. A Google Search request on CrawlerData is 1 credit. Packs run from $50 for 50,000 credits ($1.00 per 1,000) down to $3,750 for 12.5 million ($0.30 per 1,000). Credits are valid for 6 months, and failed jobs are free. Full details are on the pricing page.

A worked example: an app that used 5,000 Custom Search queries a day, every day.

  • Custom Search: (5,000 − 100 free) × 30 days = 147,000 paid queries, or $735 a month at $5 per 1,000.
  • CrawlerData: 150,000 credits a month. Over 6 months that is 900,000 credits. Two Standard packs (500,000 credits for $375 each) cover it for $750, or $125 a month.

If you paginated, count one request per page on both sides.

Migration checklist

  1. Find every call. Search your code for customsearch/v1, googleapis.com/customsearch and your cx ID. Client libraries hide the URL, so search for customsearch too.
  2. Map each call. Whole-web calls move straight to the Google Search API. Calls limited to your own sites move too, with site: in the query or a domain filter on your side.
  3. Wrap the new API in the old function signature, as above, so the rest of the code does not change.
  4. Compare outputs on 20 to 50 real queries before switching. Look at result counts, site: behaviour and snippets.
  5. Add retry handling for failed jobs (they cost 0 credits) and HTTP 429, and keep the client timeout generous.
  6. Ship before January 1, 2027. After that date, per Google, existing customers’ time to transition has run out.

Using it from an agent

If Custom Search was the web search tool for an LLM agent, the same google_search function works as a tool. Our post on giving an LLM agent fresh Google results shows how to trim the response before the model sees it. There is also an MCP server at https://api.crawlerdata.com/mcp and an OpenAPI spec at https://api.crawlerdata.com/openapi.json if you prefer to generate a client.

Try it

Sign up with a work email for 50 free credits, valid 30 days, and run your own Custom Search queries through the Google Search API. For a fuller walkthrough of the response, see getting Google search results as JSON with Python. If rank tracking was your use case, the SEO rank tracking page covers desktop and mobile positions.

Frequently asked questions

When does the Google Custom Search JSON API shut down?
Google's documentation says the API is closed to new customers and that existing customers have until January 1, 2027 to move to an alternative solution. That was the stated date as of October 2026.
What does Google recommend instead of the Custom Search JSON API?
Google's notice points to Vertex AI Search, which it describes as a favorable alternative for searching up to 50 domains. For full web search it asks you to contact Google through an interest form. Vertex AI Search is being renamed Agent Search, per Google Cloud's docs.
Can I still sign up for a Custom Search JSON API key?
No. As of October 2026 Google's overview page says the API is closed to new customers and not available for new sign-ups. Only existing customers can keep using it until the cutoff.
Is a SERP API a drop-in replacement for Custom Search?
Close. A SERP API returns what Google shows on a results page, with title, link and snippet for each organic result, which maps cleanly to Custom Search items. Instead of a cx engine ID you search Google directly, and you restrict results to a site with the site: operator in the query.
How much does a Custom Search replacement cost?
Custom Search charged $5 per 1,000 queries after 100 free a day, per Google. As of October 2026, Brave Search API lists $5 per 1,000, SerpApi starts at $25 for 1,000 searches, and Serper and CrawlerData packs run from $1.00 down to $0.30 per 1,000.
  • Google Custom Search API
  • Migration
  • Google Search API
  • SERP API
  • Python

Guides · 8 min read

Build a simple keyword rank tracker

Track where a domain ranks on Google for a keyword list, every day, by country and device. Python, SQLite and the CrawlerData API, with real cost math.

Guides · 9 min read

Give your LLM agent fresh Google results

Add a Google search tool to an LLM agent: the tool definition, trimming results to fit the context window, citing sources and caching, in Python.