# Google Trends Scraper (Batch, Reliable) (`appreciative_duct/google-trends-batch-scraper`) Actor

Private probe that reads Google Trends interest over time and related queries for a small batch of keywords.

- **URL**: https://apify.com/appreciative_duct/google-trends-batch-scraper.md
- **Developed by:** [Ross AI](https://apify.com/appreciative_duct) (community)
- **Categories:** SEO tools, Marketing
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## 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 Trends Scraper (Batch, Reliable)

This trends scraper collects Google Trends for a list of keywords in one run. Google does not offer a public Google Trends API for this data, so the actor calls the same JSON endpoints the Trends site uses. There is no API key to paste in.

It is built for keyword research: interest over time, interest by region, and related queries and topics (top and rising). Download the dataset as a CSV when you want the batch in a spreadsheet.

Google compares at most five keywords in one chart. Send a longer list and the actor chunks it into groups of five. If you need the 0–100 scores to be comparable across the whole list, switch to anchor mode and pin every group to one keyword.

A keyword that Google blocks is saved as its own error row. The rest of the batch still finishes.

### Input

Five terms, past 12 months, United States, web search:

```json
{
  "keywords": ["coffee", "tea", "matcha", "espresso", "cold brew"],
  "geo": "US",
  "timeframe": "today 12-m",
  "category": 0,
  "gprop": "web",
  "comparisonMode": "chunk"
}
```

Same list, scored against one anchor so a 40 in the second group means the same thing as a 40 in the first:

```json
{
  "keywords": ["tea", "matcha", "espresso", "cold brew", "oolong", "chai"],
  "geo": "US",
  "timeframe": "today 12-m",
  "comparisonMode": "anchor",
  "anchorKeyword": "coffee"
}
```

| Field | Default | What it does |
| --- | --- | --- |
| `keywords` | required | 1 to 100 search terms. Exact duplicates are dropped. |
| `geo` | empty | Country or region code such as `US`, `GB`, or `US-CA`. Empty is worldwide. |
| `timeframe` | `today 12-m` | Also `today 3-m`, `today 5-y`, `now 7-d`, `now 1-d`, or `2024-01-01 2024-12-31`. |
| `category` | `0` | Google category id. `0` is all categories. `5` Computers & Electronics, `7` Finance, `18` Shopping, `45` Health, `71` Food & Drink. |
| `gprop` | `web` | `web`, `news`, `youtube`, `images`, or `froogle` (Shopping). |
| `comparisonMode` | `chunk` | `chunk` splits the list into groups of five. `anchor` keeps one keyword in every group. |
| `anchorKeyword` | empty | Required in anchor mode. Saved once, as the reference series. |

The form prefills coffee, tea, matcha, espresso, and cold brew so a first run stays small.

### What the numbers mean

Interest values are Google's 0–100 index, not search volume. Inside one request, 100 is the peak of the most popular term in that request.

In chunk mode, each group of five has its own scale. A 100 in group two is not "twice" a 50 in group one.

In anchor mode the anchor is the first term in every request. Every other score is relative to that same term, including across chunks. The anchor is written once, with `isAnchor: true`.

Interest by region uses the map Google returns for that geo. A country code such as `US` comes back as states. An empty geo comes back as countries.

### Output

One dataset row per keyword. Open the run dataset and choose **Export → CSV**. Nested lists are JSON in a single cell, which is the whole series rather than one spreadsheet row per day.

Trimmed from a real US web-search run on 20 Oct 2026 (`today 12-m`, chunk mode). Coffee was in a group with tea, matcha, espresso, and cold brew, so the interest score is chunk-relative. Lists are cut to a few rows.

```json
{
  "keyword": "coffee",
  "geo": "US",
  "timeframe": "today 12-m",
  "category": 0,
  "gprop": "web",
  "comparison": "chunk",
  "chunkIndex": 0,
  "anchorKeyword": null,
  "isAnchor": false,
  "scale": "chunk-relative",
  "status": "ok",
  "error": null,
  "interestPoints": 53,
  "interestOverTime": [
    { "timestamp": 1760832000, "date": "Oct 19–25, 2025", "value": 65, "partial": false }
  ],
  "interestByRegion": [
    { "geoCode": "US-WY", "geoName": "Wyoming", "value": 100 },
    { "geoCode": "US-CA", "geoName": "California", "value": 36 }
  ],
  "regionCount": 51,
  "relatedQueries": {
    "top": [
      { "query": "coffee near me", "value": "100", "extractedValue": 100 },
      { "query": "coffee shop", "value": "87", "extractedValue": 87 }
    ],
    "rising": [
      { "query": "sports scores today", "value": "Breakout", "extractedValue": 5900 }
    ]
  },
  "relatedQueryTopCount": 25,
  "relatedQueryRisingCount": 25,
  "relatedTopics": { "top": [], "rising": [] },
  "relatedTopicTopCount": 0,
  "relatedTopicRisingCount": 0
}
```

`status` is `ok` when interest over time, interest by region, and related queries were all parsed. Empty lists are still `ok` when Google returned an empty list, which is common for a term with little data. `partial` means at least the time series (or one of the other widgets) came back and another widget did not. `blocked` means HTTP 429 or a challenge page after retries and a new proxy session. `error` means the request failed for another reason. `blocked` and `error` rows have empty lists and a short `error` string.

The key-value record `SUMMARY` counts those statuses, the number of chunks, HTTP 429s, and how many proxy sessions were used.

Related topic objects look like `{ "title": "Coffee", "type": "Drink", "mid": "/m/02mjmr", "value": "100", "extractedValue": 100 }`. Rising values use Google's label, such as `+250%` or `Breakout`.

### Retries and proxy

Each Google call is tried up to three times with exponential backoff. If a chunk is still blocked, the actor opens a new datacenter proxy session and retries the chunk, up to three sessions. It uses Apify's included datacenter group only. It does not select residential, SERP, or unblocker proxies.

Requests are paced by about a second per widget so a 25-keyword run stays on one or two sessions. That is a reliability choice, not a way to hide from Google. If Google starts returning 429s, the failed keywords are rows and the run still completes.

### FAQ

#### Is this an official Google Trends API?

No. There is no public Google Trends API for interest over time or related queries. This actor reads the endpoints the Trends website uses after you open an explore chart. You do not create a Google Cloud key.

#### Why do two groups both contain a value of 100?

Chunk mode scales each group of five on its own. Use `comparisonMode: "anchor"` and set `anchorKeyword` when you need one scale for the whole list.

#### Related topics are empty. Did the keyword fail?

Not by itself. Google often omits the related-topics widget for scripted clients, and still returns related queries. On a 25-keyword US run on 20 Oct 2026, every keyword was `ok` and every topics list was empty because that widget was not in the response. Use related queries for keyword research when topics are blank.

#### One keyword says blocked and the others are fine.

That is intentional. The actor retries, rotates the proxy session, and then writes a `blocked` row for the keywords in that chunk. It does not fail the run. Rerun those terms later, or send a shorter list. A 25-keyword US run on 20 Oct 2026 finished 25/25 `ok` in 223 seconds, with 61 requests, one datacenter session, and zero HTTP 429s. Residential proxies were not required, and this actor does not use them.

#### How do I export a CSV?

Open the run dataset, then **Export**, then **CSV**. You get one row per keyword. `interestOverTime`, `interestByRegion`, `relatedQueries`, and `relatedTopics` are JSON text in their cells.

#### What does a run cost?

The actor does not add a per-result fee. Apify bills the compute for the run. The default memory is 256 MB. A batch of about 25 keywords has been a fraction of a cent of compute. There is no start fee.

#### Which timeframe and property strings are accepted?

Timeframes follow Google's own tokens: `now 1-H`, `now 4-H`, `now 1-d`, `now 7-d`, `today 1-m`, `today 3-m`, `today 12-m`, `today 5-y`, or two dates `YYYY-MM-DD YYYY-MM-DD`. `gprop` is `web`, `news`, `youtube`, `images`, or `froogle`.

# Actor input Schema

## `keywords` (type: `array`):

Search terms, up to 100. Duplicates are removed. Google compares at most five terms in one chart, so longer lists are chunked.

## `geo` (type: `string`):

Country or region code, such as US, GB, or US-CA. Leave empty for worldwide.

## `timeframe` (type: `string`):

Google Trends range. Examples: today 12-m, today 3-m, today 5-y, now 7-d, or a custom range like 2024-01-01 2024-12-31.

## `category` (type: `integer`):

Google Trends category id. 0 is all categories. A few top-level ids: 5 Computers & Electronics, 7 Finance, 18 Shopping, 45 Health, 71 Food & Drink.

## `gprop` (type: `string`):

Which Google search property to measure. froogle is Google Shopping.

## `comparisonMode` (type: `string`):

Chunk gives each group of five its own 0–100 scale. Anchor inserts one fixed keyword into every group so scores can be compared across the whole list.

## `anchorKeyword` (type: `string`):

Required when comparison mode is Fixed anchor. This term is added to every group and saved once, as the reference series.

## Actor input object example

```json
{
  "keywords": [
    "coffee",
    "tea",
    "matcha",
    "espresso",
    "cold brew"
  ],
  "geo": "US",
  "timeframe": "today 12-m",
  "category": 0,
  "gprop": "web",
  "comparisonMode": "chunk",
  "anchorKeyword": "coffee"
}
```

# Actor output Schema

## `keywords` (type: `string`):

Interest over time, interest by region, related queries, and related topics.

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

Chunk count, HTTP 429s, proxy mode, and elapsed time.

# 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 = {
    "keywords": [
        "coffee",
        "tea",
        "matcha",
        "espresso",
        "cold brew"
    ],
    "geo": "US",
    "timeframe": "today 12-m",
    "category": 0,
    "gprop": "web",
    "comparisonMode": "chunk",
    "anchorKeyword": "coffee"
};

// Run the Actor and wait for it to finish
const run = await client.actor("appreciative_duct/google-trends-batch-scraper").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 = {
    "keywords": [
        "coffee",
        "tea",
        "matcha",
        "espresso",
        "cold brew",
    ],
    "geo": "US",
    "timeframe": "today 12-m",
    "category": 0,
    "gprop": "web",
    "comparisonMode": "chunk",
    "anchorKeyword": "coffee",
}

# Run the Actor and wait for it to finish
run = client.actor("appreciative_duct/google-trends-batch-scraper").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 '{
  "keywords": [
    "coffee",
    "tea",
    "matcha",
    "espresso",
    "cold brew"
  ],
  "geo": "US",
  "timeframe": "today 12-m",
  "category": 0,
  "gprop": "web",
  "comparisonMode": "chunk",
  "anchorKeyword": "coffee"
}' |
apify call appreciative_duct/google-trends-batch-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,appreciative_duct/google-trends-batch-scraper"
        }
    }
}
```

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/dNK1yzyI34bTIY05x/builds/GB999NlE0nZpdqaay/openapi.json
