# Google Trends Scraper — Compare Unlimited Keywords (`sondalabs/google-trends-scraper`) Actor

Google Trends as spreadsheet-ready rows: interest over time, regions, related queries, trending now. Compare more than 5 keywords on one scale. $0.50/1K rows.

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

## Pricing

from $0.40 / 1,000 row delivereds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
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 Trends Scraper — Compare Unlimited Keywords

Get Google Trends data as clean, spreadsheet-ready rows: interest over time, interest by region, related queries, related topics and today's trending searches, for Web, YouTube, News, Images and Shopping searches.

One thing the Google Trends website can't do:

- **Compare more than 5 keywords on one scale.** Google limits comparisons to 5 terms. This actor links batches through a shared anchor keyword, so 50 keywords come back on the same 0–100 scale.

**$0.50 per 1,000 rows ($0.40 on paid Apify plans). Failed and rate-limited requests are never charged.**

### Why this scraper

- **All five data types in one run**, for any country, region or worldwide.
- **Unlimited keyword comparisons** on a single scale (anchor-based normalization).
- **One flat row per data point.** Exports straight to Excel, Google Sheets or BI tools without nested JSON.
- **Built for Google's rate limits.** Requests that hit a 429 are retried on a new connection and never charged.
- **Daily history for long ranges** (opt-in with `dailyHistory`): consistent daily values beyond Google's ~9-month limit.
- **Every row links back** to the exact view on Google Trends.

### Use cases

- **SEO and content:** find rising queries and plan around seasonality.
- **Market research:** compare demand for brands, products or categories across countries.
- **E-commerce:** spot seasonal spikes in Google Shopping searches before stocking up.
- **Newsrooms and social media:** see what is trending right now in any country.
- **Finance and data science:** consistent attention series for models.
- **AI agents:** live trend data through the Apify MCP server.

### Quick start

Compare keywords over the last year in the US:

```json
{
  "keywords": ["ChatGPT", "Gemini", "Claude", "Copilot", "Perplexity", "Grok", "DeepSeek"],
  "geo": "US",
  "timeframe": "today 12-m",
  "dataTypes": ["interest_over_time", "related_queries"]
}
```

Seven keywords: more than Google allows in one comparison, all returned on the same scale.

Today's trending searches in Mexico:

```json
{
  "dataTypes": ["trending_now"],
  "trendingGeo": "MX"
}
```

### Ready-made examples

Open any example to run it with one click, or copy its input.

| Example | What you get |
|---|---|
| [Compare AI chatbots (US, 12 months)](https://apify.com/sondalabs/google-trends-scraper/examples/compare-ai-chatbots-us) | ChatGPT, Gemini, Claude, Copilot, Perplexity, Grok and DeepSeek on one scale |
| [Black Friday & holiday shopping](https://apify.com/sondalabs/google-trends-scraper/examples/black-friday-holiday-shopping-trends) | Google Shopping interest for Black Friday, Cyber Monday and Christmas gifts, 5 years |
| [iPhone vs Samsung vs Pixel](https://apify.com/sondalabs/google-trends-scraper/examples/iphone-vs-samsung-vs-pixel) | Brand interest over time and by US state |
| [Nvidia vs Tesla vs Apple stock](https://apify.com/sondalabs/google-trends-scraper/examples/stock-search-interest-nvidia-tesla-apple) | Daily attention series for retail-investor sentiment |
| [Bitcoin vs Ethereum vs Solana](https://apify.com/sondalabs/google-trends-scraper/examples/bitcoin-ethereum-solana-trends) | Worldwide interest over time and by country, 5 years |
| [SEO keyword ideas](https://apify.com/sondalabs/google-trends-scraper/examples/seo-keyword-ideas-related-queries) | Top and rising related queries and topics |
| [YouTube search trends](https://apify.com/sondalabs/google-trends-scraper/examples/youtube-search-trends-games) | Minecraft vs Fortnite vs Roblox on YouTube search |
| [Trending now: US](https://apify.com/sondalabs/google-trends-scraper/examples/trending-searches-us-today), [UK](https://apify.com/sondalabs/google-trends-scraper/examples/trending-searches-uk-today), [India](https://apify.com/sondalabs/google-trends-scraper/examples/trending-searches-india-today) | Today's trending searches with volume and news |

More inputs you can paste into the Input tab:

```json
{ "dataTypes": ["trending_now"], "trendingGeo": "DE", "trendingHours": "24" }
```

```json
{ "dataTypes": ["trending_now"], "trendingGeo": "BR", "trendingHours": "24" }
```

```json
{
  "keywords": ["air fryer", "solar panels", "heat pump"],
  "geo": "US",
  "timeframe": "today 12-m",
  "regionResolution": "REGION",
  "dataTypes": ["interest_by_region", "related_queries"]
}
```

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `keywords` | string\[] | `["chatgpt"]` | Search terms or topic IDs (e.g. `/m/0dl567`). Any number; more than 5 are linked through an anchor keyword. |
| `anchorKeyword` | string | auto | Keyword used to link batches when comparing more than 5. Auto picks the strongest keyword of the first batch. |
| `dataTypes` | enum\[] | `["interest_over_time"]` | `interest_over_time`, `interest_by_region`, `related_queries`, `related_topics`, `trending_now`. |
| `geo` | string | `""` (worldwide) | Country (`US`) or region (`US-CA`). |
| `timeframe` | enum | `today 12-m` | `now 1-H`, `now 4-H`, `now 1-d`, `now 7-d`, `today 1-m`, `today 3-m`, `today 12-m`, `today 5-y`, `all`. |
| `customTimeRange` | string | — | Exact range such as `2024-01-01 2025-06-30`. Overrides `timeframe`. |
| `property` | enum | `web` | `web`, `youtube`, `news`, `images`, `froogle` (Google Shopping). |
| `category` | integer | `0` | Google Trends category ID. `0` = all categories. |
| `regionResolution` | enum | `auto` | `COUNTRY`, `REGION`, `CITY`, `DMA` (US metros) or `auto`. |
| `trendingGeo` | string | `US` | Country for `trending_now`. |
| `trendingHours` | enum | `24` | `4`, `24`, `48` or `168` hours. |
| `dailyHistory` | boolean | `false` | Daily values for ranges longer than ~260 days (see [Daily history](#daily-history)). Only applies to `interest_over_time`. |
| `maxRows` | integer | `5000` | Maximum billable rows for the whole run. The run stops cleanly when it is reached. |
| `skipEmptyRows` | boolean | `true` | Leave rows without data (`value: null`) out of the dataset. They are never charged either way. |

### Output

Every row has a `type`, the request context and a `sourceUrl` to the same view on Google Trends.

Interest over time:

```json
{
  "type": "interest_over_time",
  "keyword": "Claude",
  "geo": "US",
  "timeframe": "today 12-m",
  "property": "web",
  "date": "2026-10-05",
  "dateEnd": "2026-10-11",
  "granularity": "week",
  "value": 34,
  "isPartial": false,
  "comparisonGroup": "a1f3c9",
  "isRescaled": true,
  "sourceUrl": "https://trends.google.com/trends/explore?date=today%2012-m&geo=US&q=Claude",
  "scrapedAt": "2026-10-18T04:10:00Z"
}
```

Related query:

```json
{
  "type": "related_query",
  "keyword": "Claude",
  "geo": "US",
  "timeframe": "today 12-m",
  "list": "rising",
  "query": "claude code",
  "value": 4250,
  "formattedValue": "+4,250%",
  "isBreakout": false,
  "rank": 1
}
```

Trending now:

```json
{
  "type": "trending_now",
  "geo": "MX",
  "title": "liga mx",
  "approxTraffic": 200000,
  "growthPct": 1000,
  "startedAt": "2026-10-18T01:00:00Z",
  "endedAt": null,
  "isActive": true,
  "hours": 24,
  "categoryId": 17,
  "category": "Sports",
  "relatedQueries": ["liga mx resultados", "tabla liga mx"],
  "articles": [{ "title": "…", "source": "…", "url": "https://…" }]
}
```

#### How to read the numbers

Google Trends never shows search counts. Values are relative, 0–100, where 100 is the peak within one request. Rows with the same `comparisonGroup` share one scale and can be compared directly. `isRescaled: true` means the value was adjusted by the anchor keyword to keep that shared scale. Google itself samples its data: two identical queries made minutes apart can differ by a few points (up to ~8 at the peak in our tests, 0.7 on average), so expect small differences between runs.

#### Daily history

Google returns daily values only for ranges up to about 260 days; longer ranges come back weekly or monthly. With `dailyHistory: true` the actor requests overlapping 250-day windows (50 days of overlap), rescales each window using the days it shares with the previous one and stitches them into one daily series, for example 20 years with `timeframe: "all"`.

- Rows have `granularity: "day"`, `isRescaled: true` and one `comparisonGroup`: values are on a shared 0–100 scale for the whole range, with 100 at the highest day.
- Accuracy against Google's own weekly series for the same range: about 0.5 points on average and under 5 at the worst week for multi-year ranges. Over 20 years the error accumulates (about 0.9 on average, up to ~7 at the peak of a very large keyword). Very small keywords (under ~1% of the peak) are rounded to whole numbers by Google and can look noisy.
- It uses about one request per 200 days per keyword batch (roughly 40 for `all`) and returns one row per keyword per day: one keyword over `all` is about 8,300 rows. Raise `maxRows` for long ranges; rows are delivered keyword by keyword.
- If a window cannot be fetched, history is delivered from the most recent window back to the failed one and the final message says so. Failed requests are not charged.

#### Rows without data

Google sometimes has no data for a point, for example small cities in `interest_by_region` (a `CITY` query for Texas returns about 200 cities, most of them empty). Those rows have `value: null`. **They are never charged.** With `skipEmptyRows: true` (default) they are not added to the dataset; with `false` they are included with `value: null`.

Every run ends with one `run_summary` row (also never charged) and a status message that tells you how many rows were billed and how many had no data, for example: `Delivered 3 billable rows. 206 rows had no data from Google and were skipped (not charged).`

```json
{
  "type": "run_summary",
  "queries": 3,
  "queriesOk": 3,
  "queriesEmpty": 0,
  "queriesFailed": 0,
  "rows": 3,
  "rowsWithoutData": 206,
  "retried429": 0,
  "lost429": 0,
  "residentialMB": 0.04,
  "message": "Delivered 3 billable rows. 206 rows had no data from Google and were skipped (not charged)."
}
```

### Pricing

| Event | Free plan | Paid plans |
|---|---|---|
| Row delivered | $0.0005 | $0.0004 |

| Example | Rows | Cost (free plan) |
|---|---|---|
| 1 keyword, 12 months weekly | ~54 | $0.03 |
| 10 keywords, 12 months weekly + related queries | ~1,000 | $0.50 |
| Trending now, one country | ~50 | $0.03 |

Not charged: failed requests, rate-limited requests (429), retries, empty results, rows without data (`value: null`) and the `run_summary` row.

### For AI agents

```
https://mcp.apify.com?tools=sondalabs/google-trends-scraper
```

### FAQ

**Why are related topics always empty?**
At the time of writing, Google returns an empty list for the related-topics endpoint. Nothing is charged when that happens. Related queries are not affected.

**Why are related queries missing for my keyword?**
Google only publishes them when there is enough search volume for that keyword, country and period. Broader keywords and longer periods return them more often.

**Can I compare values from two different runs?**
Only if both runs share the same anchor keyword setup. Within one run, rows with the same `comparisonGroup` are comparable.

**Is this the official Google Trends API?**
No. Google's official Trends API is in a closed alpha. This is an independent tool, not affiliated with Google, that collects the data Google Trends shows publicly.

### Support

Open an issue in the **Issues** tab. Issues are answered within 48 hours. Changes to output fields are announced in the changelog and never break existing fields.

### Roadmap

- Region detail `DMA` (US metro areas) and category filters.
- Related topics: Google currently returns an empty list; we will re-check periodically.
- Public example tasks.

# Changelog

This Actor's version history is a separate document: https://apify.com/sondalabs/google-trends-scraper/changelog.md

# Actor input Schema

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

Search terms or topic IDs (e.g. /m/0dl567). Any number: more than 5 are compared on one scale through an anchor keyword.

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

Keyword used to link batches when comparing more than 5. Leave empty to pick the strongest keyword of the first batch automatically.

## `dataTypes` (type: `array`):

What to extract.

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

Country (US) or region (US-CA). Leave empty for worldwide.

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

Period to analyze. Short periods return finer granularity (hourly, daily); longer ones weekly or monthly.

## `customTimeRange` (type: `string`):

Exact range, e.g. 2024-01-01 2025-06-30. Overrides Time range.

## `dailyHistory` (type: `boolean`):

Return daily values for ranges longer than Google allows (about 260 days) by stitching overlapping windows into one consistent series. Uses roughly one request per 200 days per keyword batch, and returns about one row per keyword per day: set maxRows accordingly.

## `property` (type: `string`):

Which Google search product to measure.

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

Google Trends category ID. 0 = all categories.

## `regionResolution` (type: `string`):

Level of detail for interest by region. Automatic picks countries for worldwide and regions/states for a single country.

## `trendingGeo` (type: `string`):

Two-letter country code for Trending now, e.g. US or MX.

## `trendingHours` (type: `string`):

How far back Trending now looks.

## `maxRows` (type: `integer`):

Hard cap on billable rows for the whole run. The run stops cleanly when reached.

## `skipEmptyRows` (type: `boolean`):

Google sometimes has no data for a point (for example small cities). Those rows are never charged. When enabled they are left out of the dataset; disable to keep them with value null.

## `proxyConfiguration` (type: `object`):

Keep residential proxies: Google Trends rate-limits datacenter IPs almost immediately.

## Actor input object example

```json
{
  "keywords": [
    "chatgpt"
  ],
  "dataTypes": [
    "interest_over_time"
  ],
  "geo": "",
  "timeframe": "today 12-m",
  "dailyHistory": false,
  "property": "web",
  "category": 0,
  "regionResolution": "auto",
  "trendingGeo": "US",
  "trendingHours": "24",
  "maxRows": 5000,
  "skipEmptyRows": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# 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": [
        "chatgpt"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("sondalabs/google-trends-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": ["chatgpt"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("sondalabs/google-trends-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": [
    "chatgpt"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call sondalabs/google-trends-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,sondalabs/google-trends-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/AJqEWUJekmgIffBvT/builds/75pSOvSLcPRiyvABM/openapi.json
