Dev.to AI 🤖 Ai 👁 0 📖 3 min read

How to replace Google's Custom Search JSON API before it shuts down (Jan 1, 2027)

Google's Custom Search JSON API (customsearch/v1) is closed to new customers and will stop answering on January 1, 2027. If your app, chatbot or AI agent calls it, you have until then to move. The official successor, Ve

Google's Custom Search JSON API (customsearch/v1) is closed to new customers and will stop answering on January 1, 2027. If your app, chatbot or AI agent calls it, you have until then to move.

The official successor, Vertex AI Search, is a different product: new setup, new response format, new pricing. If you just want your existing code to keep working, a drop-in replacement is less work.

This guide shows how to switch in about a minute, without changing how you read the results.

What "drop-in" means here

The replacement I'll use is an open actor on Apify that answers with the same JSON as Google's API: kind: customsearch#search, items[].title, items[].link, items[].snippet, htmlSnippet, searchInformation, and queries.nextPage. It accepts the same parameters: q, num, start, gl, hl, lr, cr, safe, dateRestrict, siteSearch, exactTerms, excludeTerms, orTerms and fileType. Errors come back in Google's shape too, so your error handling keeps working.

Disclosure: I built it, because I needed it myself.

Step 1: Get a token

Create a free Apify account and copy your API token from Settings → Integrations. The free plan includes $5 of monthly credit, which covers roughly 1,000 searches.

Step 2: Change one line

Before:

GET https://www.googleapis.com/customsearch/v1?key=GOOGLE_API_KEY&cx=ENGINE_ID&q=coffee
~~~

After:

~~~http
GET https://s3nafps--google-custom-search-api.apify.actor/customsearch/v1?token=APIFY_TOKEN&q=coffee
~~~

`key` becomes your Apify token (or send it as an `Authorization: Bearer` header). `cx` is accepted and ignored, so old URLs don't break.

Python:

~~~python
import os, requests

r = requests.get(
    "https://s3nafps--google-custom-search-api.apify.actor/customsearch/v1",
    params={"q": "best espresso machine", "num": 5, "gl": "us"},
    headers={"Authorization": f"Bearer {os.environ['APIFY_TOKEN']}"},
    timeout=60,
)
for item in r.json().get("items", []):
    print(item["title"], item["link"])
~~~

JavaScript:

~~~js
const url = new URL('https://s3nafps--google-custom-search-api.apify.actor/customsearch/v1');
url.search = new URLSearchParams({ q: 'best espresso machine', num: '5' });
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.APIFY_TOKEN}` } });
console.log((await res.json()).items?.map((i) => i.link));
~~~

## Step 3: Check the differences

A few things work differently, so test before you switch production traffic:

- Results come from google.com, not from a Programmable Search Engine you configured. To limit results to one site, use `siteSearch=example.com`.
- Speed: half of searches answer within about 7 seconds, most within 15. Google's API was faster. Set your client timeout to 60 seconds.
- Image search (`searchType=image`) isn't supported yet and returns a clear 400 error.
- `pagemap` only has `metatags`, and only when you ask for Markdown (below).

## Bonus for AI agents: page text in the same call

Add `markdown=true` and each result also carries the clean text of its page as Markdown, ready for an LLM or a RAG pipeline. That saves a second scraping step:

~~~python
params={"q": query, "num": 5, "markdown": "true", "markdownMaxChars": 4000}
~~~

Some sites block automated visitors, so expect text for about half the pages; the others return `markdownError` and aren't charged.

## Cost

Google charged $5 per 1,000 queries. This replacement charges $1.50 per 1,000 searches plus Apify's platform cost (mostly the Google search proxy, about $2.50 per 1,000), so about $4 per 1,000 in total. Searches that fail aren't charged.

## Lists of searches

For batch jobs, run the actor with a list instead of calling the web address:

~~~json
{ "queries": ["best coffee grinder 2026", "how to make cold brew"], "num": 10 }
~~~

Each search becomes one row in Google's format.

Actor page with all parameters: https://apify.com/s3nafps/google-custom-search-api

If you're migrating and something your code relies on is missing, open an issue on the actor page and I'll look at it.
📰 Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.