Custom Search JSON API shutdown · January 1, 2027

Google Custom Search JSON API shutdown: migrate in 5 minutes

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 code calls it, Searlo's drop-in endpoint takes the same request and answers in the same JSON and error format: change the host and the key, and keep the rest. Searlo returns Google results from the whole web, at 1 credit a call, $0.30 per 1,000 calls on the Scale pack.

When does the Google Custom Search JSON API stop working?

On January 1, 2027. Google's overview page says existing customers "have until January 1, 2027 to transition to an alternative solution" and calls that date "the service discontinuation". New customers cannot sign up at all.

Google gives no time of day and does not say what a request will return after that date, so plan to finish well before it. The separate Site Restricted JSON API (the /siterestrict endpoint) already stopped serving traffic on January 8, 2025.

New customers
Closed: “The Custom Search JSON API is closed to new customers.”— developers.google.com
Existing customers
“have until January 1, 2027 to transition to an alternative solution”— developers.google.com
The service itself
“the service discontinuation on January 1, 2027”— developers.google.com
“Search the entire web” engines
Existing engines can keep the option until January 1, 2027; new engines since January 20, 2026 must use “Sites to search” (up to 50 domains)— Programmable Search Engine blog
Site Restricted JSON API (/siterestrict)
“will cease to serve traffic on January 8, 2025”— developers.google.com
Google's suggested replacement
Vertex AI Search for up to 50 domains; for full web search, a form to register interest— developers.google.com

Third-party figures on this page last verified against the sources linked above. Prices change; if you find one of these stale, tell us and we will correct it.

Migration guides by stack

The change: the host and the key

Point the request at api.searlo.tech instead of www.googleapis.com (or customsearch.googleapis.com, the host Google's client libraries use) and put your Searlo API key where the Google key was. The path, the parameter names, the response JSON and the error format stay as they are. With a client library, it is one option.

- https://www.googleapis.com/customsearch/v1?key=GOOGLE_API_KEY&cx=YOUR_CX&q=lectures
+ https://api.searlo.tech/customsearch/v1?key=SEARLO_API_KEY&cx=YOUR_CX&q=lectures
- service = build("customsearch", "v1", developerKey=GOOGLE_API_KEY)
+ service = build("customsearch", "v1", developerKey=SEARLO_API_KEY,
+                 client_options={"api_endpoint": "https://api.searlo.tech"})
- const customsearch = google.customsearch({ version: "v1", auth: GOOGLE_API_KEY });
+ const customsearch = google.customsearch({ version: "v1", auth: SEARLO_API_KEY,
+                                            rootUrl: "https://api.searlo.tech/" });
- $client->setDeveloperKey($googleApiKey);
- $service = new Google\Service\CustomSearchAPI($client);
+ $client->setDeveloperKey($searloApiKey);
+ $service = new Google\Service\CustomSearchAPI($client, 'https://api.searlo.tech/');

Migrate in five steps

  1. 01Get a Searlo API keySign up at dashboard.searlo.tech and create a key. New accounts get 3,000 free credits, enough for 3,000 calls; no card, no Google Cloud project, no search engine to configure.
  2. 02Change the hostReplace https://www.googleapis.com (or https://customsearch.googleapis.com) with https://api.searlo.tech. The path stays /customsearch/v1, and /customsearch/v1/siterestrict works too.
  3. 03Replace the keyPut your Searlo key (it starts with sk_) in the key parameter. If you can set headers, send it as x-api-key instead and keep it out of URLs and logs.
  4. 04Keep results on your sites, if your engine didcx is accepted and has no effect, because an engine's site list lives in your Google console. If your engine searched a list of sites, pass siteSearch=example.com, or site:a.com OR site:b.com in q.
  5. 05Run your testsYour parser, paging (queries.nextPage) and error handling should pass unchanged. Parameters Searlo accepts with no effect are named in the X-Searlo-Ignored-Params response header, and a parameter it cannot honour returns a 400 that names it, instead of being dropped silently.

What breaks on January 1, 2027

Any code that calls https://www.googleapis.com/customsearch/v1, directly or through Google's client libraries: google-api-python-client, googleapis for Node.js, google/apiclient for PHP and the others built from the same discovery document. Google's overview page speaks of "the service discontinuation", with no exception for engines that search only your own sites.

So does every tool that wraps that API: LangChain's GoogleSearchAPIWrapper and GoogleCustomSearch, Open WebUI's google_pse web search engine, n8n workflows that call it with an HTTP Request node, and WordPress plugins that ask for a Custom Search API key. Each one needs a key that still works after the cut-off, and the guides above show where each keeps its URL and key.

The Programmable Search Element, the search box you embed on your own site with Google's script, is a different product. Google's January 2026 post says it remains the solution for up to 50 domains in "Sites to search", while engines set to "Search the entire web" can keep that option only until January 1, 2027. The drop-in replaces the JSON API, not the embedded box.

For Google's whole timeline, quoted and dated, and for moving to Searlo's native web search API instead of the drop-in, read the step-by-step shutdown migration guide on our blog, linked at the end of this page.

Parameter compatibility

What GET https://api.searlo.tech/customsearch/v1 does with each parameter Google documents for cse.list, and with Google's standard query parameters, generated from the parser that serves it (checked October 25, 2026). Of these 39, 26 are supported, 4 are accepted with no effect, 4 are accepted at Google's default value only and 5 return 400.
ParameterOn SearloNotes
keySupportedYour Searlo API key (sk_…). The x-api-key header and Authorization: Bearer also work, and keep it out of URLs
qSupportedRequired. Up to 500 characters, and 2,048 once the filter parameters below are added as operators
numSupported1 to 10, default 10
startSupported1-based. As on Google, the last result can be at most the 100th: start=91&num=10 is the last full page
glSupportedTwo-letter country code
crSupportedOne country as countryXX, read as gl. A boolean expression, or a gl naming another country, returns 400
hlSupportedInterface language
lrSupportedOne language as lang_xx, used as the request language rather than a strict filter on the document's language. A boolean expression, or an hl in another language, returns 400
safeSupportedactive or off (the legacy high and medium mean active)
dateRestrictSupportedd[n], w[n], m[n] or y[n]. Returns 400 with searchType=image, or with the operator parameters (siteSearch, fileType, orTerms…)
siteSearchSupportedA domain or URL prefix, applied as site:
siteSearchFilterSupportedi (include, the default) or e (exclude, applied as -site:)
exactTermsSupportedApplied as a quoted phrase
excludeTermsSupportedApplied as -word, or -"phrase" for a phrase
orTermsSupportedApplied as (a OR b)
fileTypeSupportedApplied as filetype:; several types become an OR
hqSupportedAppended to the query, as Google documents
lowRangeSupportedSent with highRange, appended as low..high
highRangeSupportedSent with lowRange, appended as low..high
searchTypeSupportedimage, for image search
imgSizeSupportedImage search: icon, small, medium, large, xlarge, xxlarge, huge
imgTypeSupportedImage search: clipart, face, lineart, stock, photo, animated
imgColorTypeSupportedImage search: color, gray, mono, trans
imgDominantColorSupportedImage search: black, blue, brown, gray, green, orange, pink, purple, red, teal, white, yellow
cxAccepted, no effectSearlo searches the whole web: an engine's site list lives in your Google console. Restrict results with siteSearch, or site: in q
googlehostAccepted, no effectDeprecated by Google
filterDefault value onlyfilter=1 is accepted; any other value returns 400. Results always come with Google's duplicate-content filter on (filter=1).
c2coffDefault value onlyc2coff=0 is accepted; any other value returns 400. Simplified/Traditional Chinese search cannot be switched off (c2coff=0 only).
sortDefault value onlyAn empty sort= is accepted; any other value returns 400. Sorting by structured data (sort=date and friends) needs a Google-hosted engine.
enableAlternateSearchHandlerDefault value onlyenableAlternateSearchHandler=false is accepted; any other value returns 400. There is no alternate search handler.
linkSiteReturns 400Google retired the link: operator this parameter relies on.
relatedSiteReturns 400Google retired the related: operator this parameter relies on.
rightsReturns 400Licence (Creative Commons) filtering is not available.
snippetLengthReturns 400Not taken: an unknown parameter returns Google's own 400 ("Unknown name")
altSupportedjson only
fieldsSupportedGoogle's partial-response syntax, for example items(title,link)
prettyPrintSupportedtrue or false
callbackReturns 400JSONP is not supported. Call the API from a server and keep the key there.
quotaUserAccepted, no effectGoogle's quota plumbing
userIpAccepted, no effectGoogle's quota plumbing
location, uule, near, city and other city or point locationsReturns 400Location is country level only, through gl or cr

The response

The Custom Search response shape (customsearch#search), field by field. Results come from Searlo's web search, so ranking, snippets and the totalResults estimate can differ from your engine.
FieldOn Searlo
kindcustomsearch#search
url.templateGoogle's template, pointing at api.searlo.tech
queries.request[0]title, totalResults (a string), searchTerms, count, startIndex, inputEncoding, outputEncoding, safe, cx, and the parameters you sent, under Google's names
queries.nextPage[0]Present only when more results exist within the first 100
queries.previousPage[0]Present when start is past 1
context.titleSearlo
searchInformationsearchTime, formattedSearchTime, totalResults (a string), formattedTotalResults
items[]kind, title, htmlTitle, link, displayLink, snippet, htmlSnippet, formattedUrl (the full link), htmlFormattedUrl. Left out when nothing matched, as on Google
items[].pagemapcse_thumbnail only, when the result has a thumbnail
items[] for searchType=imagemime, fileFormat, image.contextLink, plus image width, height, thumbnailLink, thumbnailWidth and thumbnailHeight when reported
Not returnedcacheId, labels, promotions, spelling, queries.request[0].startPage, image.byteSize, and pagemap entries other than cse_thumbnail

Errors

Errors use Google's envelope ({"error": {code, message, errors[{domain, reason}], status, details}}), so code that reads error.code or error.errors[0].reason keeps working. None of these is charged.
WhenHTTP statuserrors[0].reason
A parameter is missing or invalid400badRequest, invalid, required, unsupportedParameter, cityLocationUnavailable
The key is not a Searlo key (a Google AIza… key included)400keyInvalid
No key403forbidden
Account suspended, or email not confirmed403forbidden
Out of credits: clears when you top up, not at midnight403dailyLimitExceeded
Rate limit, or too many searches in flight429rateLimitExceeded, with Retry-After
Search temporarily unavailable503backendError, with Retry-After
Internal error500backendError
Unknown path under /customsearch404notFound

Check it in one minute

Two calls with your own key: the first shows Custom Search JSON coming back, the second shows which of your parameters had no effect.

# 1. Your key works and the answer is Custom Search JSON
curl -s "https://api.searlo.tech/customsearch/v1?key=$SEARLO_API_KEY&cx=YOUR_CX&q=lectures&num=3" \
  | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d.get("kind"), [i["link"] for i in d.get("items", [])])'

# 2. Parameters Searlo accepts with no effect (cx and friends) are named in a response header
curl -s -o /dev/null -D - "https://api.searlo.tech/customsearch/v1?key=$SEARLO_API_KEY&cx=YOUR_CX&q=lectures&num=1" \
  | grep -i x-searlo-ignored-params

What it costs

1 credit per call, whatever num (1 to 10) and start ask for; image search is 1 credit too. A call that returns an error is not charged. Pricing may change during November–December 2026.
PackPriceCreditsCustom Search callsPer 1,000 calls
Free$03,0003,000Free
Micro$3.995,0005,000$0.80
Starter$9.9920,00020,000$0.50
Builder$29.9975,00075,000$0.40
Scale$74.99250,000250,000$0.30
Pro$199.99900,000900,000$0.22
Enterprise$7994,000,0004,000,000$0.20
Google Custom Search JSON API (until January 1, 2027)Per use—100 a day free, then up to 10,000 a day$5.00

What is different from Google

Searlo is a separate service that returns Google results; it is not Google's API on another address. These differences are deliberate, and each one is in the tables above:

  • cx has no effect: results come from the whole web. Restrict with siteSearch or site:
  • Ranking, snippets and totalResults can differ from your engine
  • Location is country level (gl, cr); city locations return 400
  • Boolean cr and lr expressions return 400; one country and one language per call
  • q is limited to 500 characters
  • Out of credits is 403 dailyLimitExceeded until you top up, not until midnight
  • Call it from a server: browsers on other sites are blocked by CORS, and JSONP is refused
  • Responses carry X-Request-ID; quote it to support

FAQ

Frequently asked questions

When does the Google Custom Search JSON API shut down?

Google's overview page says existing customers have until January 1, 2027 to transition, and calls that date "the service discontinuation". It is already closed to new customers, and Google has not said what a request will return after the cut-off. Facts checked on October 25, 2026.

Will my existing code work if I only change the URL?

If it calls /customsearch/v1 and reads the standard fields (items, title, link, snippet, searchInformation, queries.nextPage, error.code), yes: put your Searlo key where the Google key was and the request, response and error shapes match. Check three things: an engine that searched a site list needs siteSearch, a few parameters (linkSite, rights, sort=date, city locations) return 400, and fields such as cacheId, labels and spelling are not returned.

Do I still need a search engine ID (cx)?

No. cx is accepted so existing code does not have to change, and it has no effect: Searlo searches the whole web. It is echoed back in queries.request[0].cx and named in the X-Searlo-Ignored-Params header.

Does it work with Google's client libraries?

Yes, with one option, because the drop-in serves Google's own paths. In Python, pass client_options={"api_endpoint": "https://api.searlo.tech"} to build(); in Node.js, pass rootUrl: "https://api.searlo.tech/" to google.customsearch(); in PHP, pass 'https://api.searlo.tech/' as the second argument to Google\Service\CustomSearchAPI. We ran each of them before publishing; the Python, Node.js and PHP guides have the full code.

What about the /siterestrict endpoint?

Google's Site Restricted JSON API stopped serving traffic on January 8, 2025, according to its own page. Searlo answers /customsearch/v1/siterestrict with the same search as /customsearch/v1, so code still pointed at it works again once you change the host; restrict results with siteSearch, since cx has no effect.

Can I use it for search on my own website?

Yes, by adding siteSearch=yourdomain.com to each call (or site: in q). The WordPress guide has a must-use plugin that does this for plugins that call the API through WordPress. The embedded Programmable Search Element is a different product and is not replaced by the drop-in.

How much does it cost?

1 credit per call, the same as a Searlo web search, for up to 10 results. That is $0.30 per 1,000 calls on the Scale pack, with 3,000 free credits at sign-up and no 10,000-a-day cap. Google's rate for existing customers is $5 per 1,000 after 100 free queries a day, up to 10,000 a day.

Is Searlo affiliated with Google?

No. Searlo is an independent service that returns Google results through its own API. The drop-in uses Custom Search's request and response format so that existing code keeps working; Google is a trademark of Google LLC.

Move before the cut-off

Create a key, change the host, run your tests. 3,000 free credits, no card.