# Google Custom Search API Alternative (CSE JSON) (`automationnation/google-custom-search-api`) Actor

Drop-in replacement for Google's Custom Search JSON API, which shuts down on 1 January 2027: the same /customsearch/v1 parameters and JSON (items with title, link, snippet; image search too) from live Google results. No 10,000-a-day cap. $5 per 1,000 searches, Google's own price.

- **URL**: https://apify.com/automationnation/google-custom-search-api.md
- **Developed by:** [Nathan Carter](https://apify.com/automationnation) (community)
- **Categories:** Developer tools, SEO tools, AI
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 searches

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Google Custom Search API Alternative (CSE JSON)

**A drop-in replacement for Google's Custom Search JSON API, which Google has closed to new customers and retires on 1 January 2027.** Send the same `/customsearch/v1` requests and get the same JSON back (`items` with `title`, `link`, `snippet`, image search with `searchType=image`), served from live Google results. Existing code changes two things: the base URL and the key.

#### Example result

`q=best crm for startups&num=2`, a real response from 6 October 2026 (only the `url` template is left out):

```json
{
  "kind": "customsearch#search",
  "queries": {
    "request": [
      {
        "title": "Google Custom Search - best crm for startups",
        "searchTerms": "best crm for startups",
        "count": 2,
        "startIndex": 1,
        "inputEncoding": "utf8",
        "outputEncoding": "utf8",
        "safe": "off",
        "totalResults": "4"
      }
    ],
    "nextPage": [
      {
        "title": "Google Custom Search - best crm for startups",
        "searchTerms": "best crm for startups",
        "count": 2,
        "startIndex": 3,
        "inputEncoding": "utf8",
        "outputEncoding": "utf8",
        "safe": "off",
        "totalResults": "4"
      }
    ]
  },
  "context": {
    "title": "Google Search by AutomationNation"
  },
  "searchInformation": {
    "searchTime": 1.548,
    "formattedSearchTime": "1.55",
    "totalResults": "4",
    "formattedTotalResults": "4"
  },
  "items": [
    {
      "kind": "customsearch#result",
      "title": "What's the best CRM for an early stage, bootstrapped ...",
      "htmlTitle": "What&#39;s the <b>best</b> <b>CRM</b> <b>for</b> an early stage, bootstrapped ...",
      "link": "https://www.reddit.com/r/CRM/comments/1ncf59q/whats_the_best_crm_for_an_early_stage/",
      "displayLink": "www.reddit.com",
      "snippet": "We're just 2 people right now who are growing fast averaging 60 leads a month, and Salesforce or HubSpot feel way too heavy for where we are. But Google ...",
      "htmlSnippet": "We're just 2 people right now who are growing fast averaging 60 leads a month, and Salesforce or HubSpot feel way too heavy for where we are. But Google ...",
      "formattedUrl": "https://www.reddit.com/r/CRM/comments/1ncf59q/whats_the_best_crm_for_an_early_stage/",
      "htmlFormattedUrl": "https://www.reddit.com/r/CRM/comments/1ncf59q/whats_the_best_crm_for_an_early_stage/"
    },
    {
      "kind": "customsearch#result",
      "title": "Best CRM For Startups: The All-In-One Guide",
      "htmlTitle": "<b>Best</b> <b>CRM</b> <b>For</b> <b>Startups</b>: The All-In-One Guide",
      "link": "https://www.salesforce.com/crm/startup-crm/",
      "displayLink": "www.salesforce.com",
      "snippet": "Find out how the right CRM for startups can help boost revenue, reduce costs, and scale operations.",
      "htmlSnippet": "Find out how the right CRM for startups can help <b>boost revenue, reduce costs, and scale operations</b>.",
      "formattedUrl": "https://www.salesforce.com/crm/startup-crm/",
      "htmlFormattedUrl": "https://www.salesforce.com/crm/startup-crm/"
    }
  ]
}
```

#### Quick facts

- **Same requests, same JSON:** `q`, `num`, `start`, `gl`, `hl`, `lr`, `cr`, `safe`, `dateRestrict`, `siteSearch`, `exactTerms`, `excludeTerms`, `orTerms`, `fileType`, `searchType=image` and the image filters. `cx` and `key` are accepted and ignored.
- **Keeps working after 1 January 2027**, with no 10,000-queries-a-day cap.
- **Price:** $5 per 1,000 searches of up to 10 results, the same as Google charged, and less on paid Apify plans. Searches that return nothing are free.
- **Two ways to use it:** an HTTP endpoint for existing code (Standby mode), or normal runs from Apify Console, the API, schedules and integrations, with one dataset row per result.
- **Speed:** a request usually takes 4–10 seconds, occasionally up to about 20, because each one fetches live Google results (Google's API answered in under a second). Run requests in parallel for throughput.
- **Clean results:** web searches use Google's "Web" results view: ten plain results per page, without the AI Overview, ads or video and forum boxes, which is close to what the API returned.

### Switch your code in two lines

Replace the endpoint and send your [Apify API token](https://console.apify.com/settings/integrations) instead of the Google key. Everything else stays the same.

| | Before | After |
|---|---|---|
| Endpoint | `https://www.googleapis.com/customsearch/v1` | `https://automationnation--google-custom-search-api.apify.actor/customsearch/v1` |
| Auth | `key=YOUR_GOOGLE_KEY&cx=YOUR_ENGINE_ID` | `token=YOUR_APIFY_TOKEN` (or the header `Authorization: Bearer YOUR_APIFY_TOKEN`) |

**curl**

```bash
curl "https://automationnation--google-custom-search-api.apify.actor/customsearch/v1?q=best+crm+for+startups&num=10&token=$APIFY_TOKEN"
```

**Python**

```python
import os, requests

r = requests.get(
    "https://automationnation--google-custom-search-api.apify.actor/customsearch/v1",
    params={"q": "best crm for startups", "num": 10, "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://automationnation--google-custom-search-api.apify.actor/customsearch/v1');
url.search = new URLSearchParams({ q: 'best crm for startups', num: '10' });
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.APIFY_TOKEN}` } });
const { items = [] } = await res.json();
for (const item of items) console.log(item.title, item.link);
```

Set your HTTP timeout to at least 60 seconds. The first request after a quiet spell also starts the server, which adds a few seconds.

#### Google's Python client and LangChain

Code built on Google's own client (`google-api-python-client`) keeps working too: point it at this endpoint and add the token as a header. This snippet was tested on 6 October 2026:

```python
import os
import httplib2
from googleapiclient.discovery import build


class ApifyAuth(httplib2.Http):
    """Sends your Apify token with every request."""
    def request(self, uri, method="GET", body=None, headers=None, *args, **kwargs):
        headers = {**(headers or {}), "Authorization": f"Bearer {os.environ['APIFY_TOKEN']}"}
        return super().request(uri, method, body, headers, *args, **kwargs)


service = build(
    "customsearch", "v1",
    developerKey="unused",  # the Apify token in the header replaces the key
    http=ApifyAuth(timeout=60),
    client_options={"api_endpoint": "https://automationnation--google-custom-search-api.apify.actor"},
    static_discovery=True,  # uses the API description bundled with the library; nothing goes to Google
)
res = service.cse().list(q="best crm for startups", cx="unused", num=10).execute()
```

**LangChain** (`GoogleSearchAPIWrapper` from `langchain-google-community`) uses that client, so give it the service above:

```python
from langchain_google_community import GoogleSearchAPIWrapper

search = GoogleSearchAPIWrapper(google_api_key="unused", google_cse_id="unused", k=5)
search.search_engine = service
print(search.run("how to learn rust"))
```

### Supported parameters

| Parameter | What it does here |
|---|---|
| `q` | The search. Google operators work: `site:`, `filetype:`, `"exact phrase"`, `-exclude`, `OR`. |
| `num` | Results per request, 1–10 (default 10). |
| `start` | Index of the first result, 1–100. As with Google's API, results stop at 100. |
| `gl` / `hl` | Country and interface language of the Google results (default `us` / `en`). |
| `lr` / `cr` | Language (`lang_de`) and country (`countryDE`) restrictions. |
| `safe` | `active` turns on SafeSearch. |
| `dateRestrict` | `d[number]`, `w[number]`, `m[number]` or `y[number]`, e.g. `m6` for the past six months. |
| `siteSearch` + `siteSearchFilter` | Only results from a site (`i`, the default) or none from it (`e`). |
| `exactTerms`, `excludeTerms`, `orTerms`, `fileType` | Added to the query the way Google's engine does it. |
| `filter` | `0` turns off Google's duplicate filter. |
| `searchType=image` | Google Images, with `imgSize`, `imgType`, `imgColorType`, `imgDominantColor` and `rights`. Items include `image.contextLink`, `width`, `height`, `byteSize` and the thumbnail. |
| `cx`, `key`, `fields`, `alt` | Accepted so existing code doesn't break. `cx` is echoed back; the others are ignored. |

Errors use the API's own format, for example a missing `q` returns HTTP 400 with `{"error": {"code": 400, "message": "Required parameter: q", …}}`.

### Differences from Google's API

Most code won't notice these, but check them before you switch:

- **It searches the whole web,** like a Programmable Search Engine set to "Search the entire web". A `cx` limited to your own sites isn't read; pass those sites with `siteSearch`, or in `q` as `site:example.com OR site:example.org`. Off-site results that Google mixes into later pages are removed.
- **`totalResults` is a lower bound.** Google no longer shows result counts, so it's the results so far plus one more page while there are more. Clients that page until they run out still work.
- **No `pagemap`** (thumbnails and metatags per result).
- **`sort`, `linkSite`, `lowRange`, `highRange`, `hq` and `c2coff` are ignored.**
- **Slower:** usually 4–10 seconds per request instead of under one, since each request fetches live Google results. If your client has a short timeout (10 seconds is common), raise it to 60.

### Use it as a normal Actor run

In Apify Console, through the Apify API, on a schedule or from Make, n8n or Zapier, give it a list of searches and get one dataset row per result, in the API's item format.

#### Input example

```json
{
  "queries": ["best project management software", "mcp server site:github.com"],
  "maxResultsPerQuery": 20,
  "country": "us",
  "language": "en"
}
```

Options: `searchType` (`web` or `image`), `maxResultsPerQuery` (up to 100), `country`, `language`, `siteSearch` with `excludeSite`, `dateRestrict`, `fileType` and `safeSearch`.

#### Output example

A real row from 6 October 2026 (`htmlTitle`, `htmlSnippet` and `htmlFormattedUrl` left out):

```json
{
  "query": "mcp server site:github.com",
  "position": 1,
  "searchType": "web",
  "kind": "customsearch#result",
  "title": "modelcontextprotocol/servers: Model Context Protocol ...",
  "link": "https://github.com/modelcontextprotocol/servers",
  "displayLink": "github.com",
  "snippet": "The servers in this repository are intended as reference implementations to demonstrate MCP features and SDK usage. They are meant to serve as educational ...",
  "formattedUrl": "https://github.com/modelcontextprotocol/servers",
  "country": "us",
  "language": "en",
  "scrapedAt": "2026-10-06T11:52:43.406Z"
}
```

Image searches add `mime`, `fileFormat` and `image` (`contextLink`, `width`, `height`, `byteSize`, `thumbnailLink`). A run summary per search is saved as `OUTPUT` in the key-value store.

### How much does it cost?

You pay per search of up to 10 results: $5 per 1,000, the price Google charged for the Custom Search JSON API. Searches that return nothing, and requests Google doesn't answer, are free. A normal run counts each page of up to 10 results it saves as one search.

| Searches | Free & Bronze plans | Silver | Gold and above |
|---|---|---|---|
| 1,000 | $5.00 | $4.50 | $4.00 |
| 10,000 | $50 | $45 | $40 |
| 100,000 | $500 | $450 | $400 |

Google's API also gave 100 free queries a day. Here, the Apify free plan's $5 monthly credit covers about 1,000 searches a month. There's no daily cap, and for normal runs you can set a maximum cost per run.

### Use it with AI agents (MCP)

Add `https://mcp.apify.com?tools=automationnation/google-custom-search-api` to Claude, ChatGPT, Cursor or another MCP client and sign in with Apify. The agent can then run Google searches and read the results as JSON.

### FAQ

**Is the Custom Search JSON API really going away?**
Yes. Google's documentation says it's closed to new customers and that existing customers have until 1 January 2027 to move. For searching up to 50 domains Google suggests Vertex AI Search, a different product with a different API; for whole-web search it asks you to contact Google.

**Do I need to change my parsing code?**
No. The response has the same shape: `items[].title`, `link`, `displayLink`, `snippet`, `htmlSnippet`, `formattedUrl`, `queries.nextPage` and `searchInformation`. Check the differences above for `totalResults` and `pagemap`.

**Can I use my Programmable Search Engine's site list?**
Not by its `cx`. Put the sites in `siteSearch` (one site) or in `q` (`site:a.com OR site:b.com`).

**How fast is it, and how many requests can I send?**
Usually 4–10 seconds per request, occasionally up to about 20. Requests run in parallel, so send several at once for throughput; there's no daily cap.

**Is it legal?**
It reads public Google results, like a person searching. Use the data in line with the laws and terms that apply to you.

**Guides:** [Custom Search JSON API shutting down: a drop-in replacement](https://retracn.github.io/automationnation-actors/guides/google-custom-search-json-api-alternative/) · [LangChain GoogleSearchAPIWrapper after the shutdown](https://retracn.github.io/automationnation-actors/guides/langchain-google-search-custom-search-api-shutdown/) · [Image search after the Custom Search API](https://retracn.github.io/automationnation-actors/guides/google-custom-search-api-image-search-alternative/) · [Code examples (Python, JavaScript, curl)](https://github.com/retracn/google-custom-search-api-alternative)

### More Google data from AutomationNation

- **[Google Images Scraper](https://apify.com/automationnation/google-images-scraper)**: up to 100 full-size images per search, with sizes and source pages.
- **[Google News Scraper](https://apify.com/automationnation/google-news-scraper)**: headlines, sources, dates and article URLs.
- **[Google Shopping Scraper](https://apify.com/automationnation/google-shopping-scraper)**: prices, stores and reviews for any product search.
- **[Google Videos Scraper](https://apify.com/automationnation/google-videos-scraper)**: videos from YouTube, TikTok and more, with channel and duration.
- **[Google AI Overview Tracker](https://apify.com/automationnation/aeo-auditor)**: whether Google's AI Overviews cite your site.
- **[Google Trends Scraper](https://apify.com/automationnation/google-trends-scraper)**: interest over time, related queries and trending searches.

Questions or a missing parameter? Open an issue on the **Issues** tab; fixes usually ship within a day.

# Changelog

This Actor's version history is a separate document: https://apify.com/automationnation/google-custom-search-api/changelog.md

# Actor input Schema

## `queries` (type: `array`):

What to search for on Google, one per line. Google operators work (site:, filetype:, "exact phrase", -exclude).

## `searchType` (type: `string`):

Web results (title, link, snippet) or Google Images (image URL, size, thumbnail and the page it's on), like the API's searchType=image.

## `maxResultsPerQuery` (type: `integer`):

Up to 100, the API's own limit. Each 10 results count as one search ($0.005).

## `country` (type: `string`):

Two-letter country code for the Google results (the API's gl), e.g. us, gb, de, fr, in, br, au.

## `language` (type: `string`):

Google interface language (the API's hl), e.g. en, de, es, fr, pt, ja.

## `siteSearch` (type: `string`):

Restrict results to one site or path, e.g. reddit.com or docs.python.org/3 (the API's siteSearch).

## `excludeSite` (type: `boolean`):

Leave out results from the site above instead of keeping only them (the API's siteSearchFilter=e).

## `dateRestrict` (type: `string`):

Only results from this period (the API's dateRestrict).

## `fileType` (type: `string`):

Only files of this type, e.g. pdf, docx, xlsx, pptx (the API's fileType).

## `safeSearch` (type: `boolean`):

Filter explicit results (the API's safe=active).

## Actor input object example

```json
{
  "queries": [
    "best project management software"
  ],
  "searchType": "web",
  "maxResultsPerQuery": 10,
  "country": "us",
  "language": "en",
  "excludeSite": false,
  "dateRestrict": "any",
  "safeSearch": false
}
```

# Actor output Schema

## `results` (type: `string`):

One row per result, in the API's item format.

## `allData` (type: `string`):

No description

## `summary` (type: `string`):

Per search: status and results.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "queries": [
        "best project management software"
    ],
    "maxResultsPerQuery": 10,
    "country": "us",
    "language": "en"
};

// Run the Actor and wait for it to finish
const run = await client.actor("automationnation/google-custom-search-api").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "queries": ["best project management software"],
    "maxResultsPerQuery": 10,
    "country": "us",
    "language": "en",
}

# Run the Actor and wait for it to finish
run = client.actor("automationnation/google-custom-search-api").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "queries": [
    "best project management software"
  ],
  "maxResultsPerQuery": 10,
  "country": "us",
  "language": "en"
}' |
apify call automationnation/google-custom-search-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automationnation/google-custom-search-api"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/7XeasG8sIKjxnuC0p/builds/ZmJ42pxSyGcVhqZBB/openapi.json
