# Google Trends Compare · 5+ Keywords, Regions & Related (`thequietstack/google-trends-compare`) Actor

Google Trends scraper for keyword research and market research: compare more than the five keywords Google allows, on one 0-100 scale through anchor normalization. Interest over time, interest by region and related queries per keyword. Empty runs cost nothing.

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

## Pricing

from $1.75 / 1,000 time series

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 Compare · 5+ Keywords, Regions & Related

**Compare more than 5 keywords in Google Trends on one common 0-100 scale** - across countries, US states or German federal states, with interest by region and related queries. You pay only for results that contain data. An empty run costs nothing.

On trends.google.com you can compare up to 5 terms at a time. Each comparison is scaled to its own maximum, so you cannot simply put two comparisons next to each other. This Actor splits your list into Google requests of 5 terms. It puts the same **anchor keyword** into every request and rescales all requests through that anchor. The result is one table where `chatgpt`, `gemini`, `claude`, `perplexity`, `copilot`, `deepseek` and `grok` sit on the same scale.

No login, no Google account, no proxy needed.

### What you get

| | This Actor | Typical Google Trends scrapers |
|---|---|---|
| More than 5 keywords | one common 0-100 scale through an anchor keyword, with a precision flag per row | 5 per run, or separate scales that are not comparable |
| Locations | several countries / regions / US metros compared on one scale; `splitGeoIntoRegions` turns `DE` into the 16 federal states, `US` into 51 states | one location per run |
| Summary per keyword | average, peak and date, latest value, change in % (last vs first quarter of the range), rank | raw timeline only |
| Interest by region | optional, per keyword (countries, regions/states, US metros) | often |
| Related queries | optional: top and rising, rising with growth % or Breakout | often |
| Empty results | free status row (`no_data`), never charged | often charged |
| Hangs | hard stop after `maxRunMinutes`, everything collected so far is delivered | "ran 20 minutes, no results" |
| Start fee | none | often $0.02 per run |

### Use cases

- **Market and brand comparison:** 10-50 brands, products or competitors in one ranked table, instead of stitching 5-term screenshots together.
- **Regional demand:** one product across all German federal states or US states over time, e.g. for ad budgets, store openings or sales territories.
- **Content and SEO research:** related rising queries (Breakout terms) for your seed keywords, every week on a schedule.
- **Seasonality:** 5 years of weekly data for a product category, ready for Sheets, Looker Studio, Make, n8n or Zapier.
- **YouTube, News, Images, Shopping:** the same comparison for other Google properties (`searchType`).

### Input example

```json
{
    "keywords": ["chatgpt", "gemini", "claude", "perplexity", "copilot", "deepseek", "grok"],
    "geos": ["US"],
    "timeRange": "today 12-m",
    "includeRelatedQueries": true
}
```

- `keywords` - any number of terms. Up to 200 keyword x location pairs per run.
- `geos` - empty = worldwide; `US`, `DE`, `DE-BY`, `US-CA`, `US-CA-807` (metro). Several locations compare every keyword in every location.
- `splitGeoIntoRegions` - `DE` becomes the 16 federal states, `US` the 51 states (up to 60 regions per country).
- `timeRange` - `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`, or `2024-01-01 2024-12-31`.
- `anchorKeyword`, `anchorGeo` - the term that links the requests. By default the first keyword is used. Choose a term that is neither the biggest nor the smallest in your list (see "Honest numbers").
- `includeRegions` + `regionResolution` (`auto`, `COUNTRY`, `REGION`, `DMA`), `includeRelatedQueries`.
- `searchType` (`web`, `images`, `news`, `shopping`, `youtube`), `category` (Google Trends category ID, 0 = all).
- `includeTimeline` (default on), `requestDelaySecs` (default 1.5), `maxRunMinutes` (default 20).

### Output example

Real row from a test run on 04 Oct 2026 (the input above, timeline shortened). `grok` was in the second Google request and is scaled through the anchor `chatgpt`:

```json
{
    "type": "timeseries",
    "keyword": "grok",
    "geo": "US",
    "timeRange": "today 12-m",
    "searchType": "web",
    "status": "ok",
    "rankByAverage": 5,
    "pairsCompared": 8,
    "averageValue": 4.91,
    "peakValue": 10,
    "peakAt": "2026-03-01T00:00:00.000Z",
    "latestValue": 4,
    "latestAt": "2026-09-27T00:00:00.000Z",
    "lastPointIsPartial": true,
    "changePercent": 8,
    "resolution": "WEEK",
    "points": 54,
    "scaling": {
        "method": "anchor",
        "factor": 0.999759,
        "anchorAverageInBatch": 77.09,
        "rawAverageInBatch": 4.91,
        "precision": "low",
        "anchorKeyword": "chatgpt",
        "anchorGeo": "US",
        "request": 2,
        "requests": 2
    },
    "timeline": [
        { "date": "2025-09-28T00:00:00.000Z", "value": 3, "rawValue": 3, "isPartial": false },
        { "date": "2026-09-27T00:00:00.000Z", "value": 4, "rawValue": 4, "isPartial": false },
        { "date": "2026-10-04T00:00:00.000Z", "value": 4, "rawValue": 4, "isPartial": true }
    ]
}
```

`precision: "low"` is shown because grok averages below 5 of 100 next to chatgpt. Google rounds to whole numbers, so small values carry a large rounding error (see "Honest numbers").

Region row (`includeRegions`, Germany, year 2025, list shortened):

```json
{
    "type": "regions",
    "keyword": "bier",
    "geo": "DE",
    "resolution": "REGION",
    "regionCount": 16,
    "topRegion": "Thuringia",
    "regions": [
        { "geoCode": "DE-TH", "geoName": "Thuringia", "value": 100 },
        { "geoCode": "DE-SN", "geoName": "Saxony", "value": 99 },
        { "geoCode": "DE-ST", "geoName": "Saxony-Anhalt", "value": 93 }
    ]
}
```

Related queries row (`includeRelatedQueries`, lists shortened):

```json
{
    "type": "related-queries",
    "keyword": "deepseek",
    "geo": "US",
    "topCount": 25,
    "risingCount": 25,
    "top": [{ "query": "ai", "value": 100 }, { "query": "deepseek ai", "value": 92 }],
    "rising": [{ "query": "deepseek v4 flash", "growthPercent": null, "breakout": true }]
}
```

The run summary (key-value store record `SUMMARY`) has the full ranking, the anchor, every Google request with its status, the HTTP statistics (including waits on rate limits) and the billing.

### Honest numbers

- **The anchor method works, and here is the check.** In our test on 04 Oct 2026 we compared 7 AI assistants (2 requests through the anchor). Then we compared 5 of them directly in one Google request. Ratios to gemini, anchored vs direct: claude 0.673 vs 0.672 · copilot 0.231 vs 0.229 · grok 0.179 vs 0.178 · deepseek 0.077 vs 0.073.
- **Small terms are imprecise.** Google gives whole numbers from 0 to 100. A term that averages 2 next to a giant like chatgpt can be off by 5-10 % (deepseek above). Every row therefore carries `scaling.precision`:
  - `exact` - all your terms fit into one Google request, so the numbers are Google's own.
  - `good` - the anchor and the term both average at least 5 in their request.
  - `low` - otherwise.
    For small terms, run them in a separate list with a smaller anchor.
- **The anchor must show up.** If the anchor rounds to 0 next to the other terms in a request, those terms cannot be scaled. They come back as free rows with `status: "anchor_without_data"`. A more popular `anchorKeyword` fixes this.
- **Google samples its data.** The same query can move by 1-2 points between two runs. This applies to every Google Trends tool.
- **Comparing locations shows search share, not volume.** Google divides by all searches in each location. "bier" scores higher in Saxony than in Bavaria because a larger share of Saxony's searches is about beer, not because there are more searches in total.
- **Region values are per keyword.** 100 is the region where that keyword has its highest share. Cities are not offered: in our test for Germany, Google returned 200 towns and none of them had data.

### How much does it cost?

Pay per event, no start fee:

| Event | When it is charged | Price |
|---|---|---|
| `timeseries` | one keyword/location pair with data on the common scale | $0.0025 |
| `region-breakdown` | one region row with at least one region with data (`includeRegions`) | $0.002 |
| `related-queries` | one row with at least one top or rising query (`includeRelatedQueries`) | $0.002 |

You are **never charged** for:

- pairs without search volume (`no_data`)
- pairs that cannot be scaled (`anchor_without_data`)
- failed, rate-limited or blocked requests
- the anchor, when it is not one of your keywords
- status rows
- empty runs

Example: 7 keywords with related queries = 7 x $0.0025 + 7 x $0.002 = $0.0315.

Apify's "Max cost per run" setting is respected: the Actor stops writing at your limit.

### Reliability and Google's limits

- The Actor makes the same requests the trends.google.com page makes for a visitor who is not signed in. It sends one request at a time, with a pause between requests (`requestDelaySecs`).
- **Rate limits (HTTP 429):** the Actor waits and retries up to 3 times (20 s, 60 s, 120 s, honouring Retry-After). If Google keeps refusing, the run stops cleanly. All finished rows are delivered, and the missing pairs appear as free `failed` rows.
- **Bot protection is never bypassed.** A CAPTCHA, an "unusual traffic" page or a redirect to Google's /sorry/ page stops the run immediately. It is never retried and never worked around. No login, no account cookies, no proxy rotation, no browser disguise. The only cookie sent is the anonymous one Google itself sets on the start page.
- **No silent hangs:** the run ends after `maxRunMinutes` (default 20) at the latest and delivers what it has.
- A typical run: 7 keywords with related queries = 12 requests in about 30 s.

### FAQ

**Can I compare 50 keywords?** Yes. 50 keywords in one location = 13 Google requests through the anchor. Pick an anchor of medium popularity.

**Why does a keyword show `no_data`?** Google reports too little search volume for that term, location and time range. These rows are free.

**Is this data official?** It is Google Trends' public, relative, sampled index (0-100). It does not give absolute search volumes.

**Can I schedule it?** Yes. Use Apify Schedules and connect the dataset to Google Sheets, Slack, Make, n8n or Zapier.

# Actor input Schema

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

Search terms to compare. Any number up to 200 keyword/location pairs: more than 5 are split into several Google requests and put on one common scale through an anchor keyword.

## `geos` (type: `array`):

Leave empty for worldwide. Country codes (US, DE), regions (DE-BY, US-CA) or US metros (US-CA-807). Several locations compare every keyword in every location on the same scale.

## `splitGeoIntoRegions` (type: `boolean`):

Replaces each country by all its regions before comparing, e.g. DE -> the 16 German federal states, US -> 51 states. Every keyword then gets one time series per region, all on one scale.

## `timeRange` (type: `string`):

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 - or a custom range "YYYY-MM-DD YYYY-MM-DD" (from 2004 on).

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

Used in every Google request to link them to one scale. Default: your first keyword in the first location. Best: a term of medium popularity compared with the others - a tiny anchor makes the scaling imprecise (shown in scaling.precision).

## `anchorGeo` (type: `string`):

Location of the anchor keyword. Default: your first location.

## `includeRegions` (type: `boolean`):

One extra row per keyword/location with Google's interest by sub-region (e.g. federal states or cities). Charged as region-breakdown only when Google returns regions.

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

auto = Google's default for the location (countries for worldwide, regions/states for a country). DMA gives US metro areas (US locations only).

## `includeRelatedQueries` (type: `boolean`):

One extra row per keyword/location with Google's top and rising related queries (rising with growth % or Breakout). Charged as related-queries only when Google returns at least one.

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

Which Google search to measure.

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

Google Trends category (0 = all categories). Example: 71 Food & Drink, 5 Computers & Electronics.

## `includeTimeline` (type: `boolean`):

Adds every data point (date, value on the common scale, Google's raw value, partial flag). Off = only the summary numbers per keyword.

## `requestDelaySecs` (type: `number`):

Minimum pause between two requests to Google. Minimum 1.

## `maxRunMinutes` (type: `integer`):

The run stops cleanly after this time and delivers everything collected so far. No silent 20-minute hangs.

## Actor input object example

```json
{
  "keywords": [
    "chatgpt",
    "gemini",
    "claude",
    "perplexity",
    "copilot",
    "deepseek",
    "grok"
  ],
  "geos": [
    "US"
  ],
  "splitGeoIntoRegions": false,
  "timeRange": "today 12-m",
  "includeRegions": false,
  "regionResolution": "auto",
  "includeRelatedQueries": false,
  "searchType": "web",
  "category": 0,
  "includeTimeline": true,
  "requestDelaySecs": 1.5,
  "maxRunMinutes": 20
}
```

# Actor output Schema

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

Rows of type timeseries (common 0-100 scale, average, peak, latest, change, scaling precision, timeline), regions and related-queries. Pairs without data appear as free status rows.

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

Ranking of all pairs by average interest, anchor used, every Google request with its status, HTTP statistics including waits on rate limits, and billing.

# 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",
        "gemini",
        "claude",
        "perplexity",
        "copilot",
        "deepseek",
        "grok"
    ],
    "geos": [
        "US"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("thequietstack/google-trends-compare").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",
        "gemini",
        "claude",
        "perplexity",
        "copilot",
        "deepseek",
        "grok",
    ],
    "geos": ["US"],
}

# Run the Actor and wait for it to finish
run = client.actor("thequietstack/google-trends-compare").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",
    "gemini",
    "claude",
    "perplexity",
    "copilot",
    "deepseek",
    "grok"
  ],
  "geos": [
    "US"
  ]
}' |
apify call thequietstack/google-trends-compare --silent --output-dataset

```

## MCP server setup

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

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/EmbCM93qyagbazYMB/builds/SpMRZDcGPyMn75E3w/openapi.json
