# Google Trends Scraper — related queries, by region, CSV/JSON (`tallyrake/google-trends-scraper`) Actor

Google Trends interest over time, interest by region and related queries as flat CSV/JSON rows, one row per data point with a stable id. $0.25 per 1,000 rows; session rotation on rate limits.

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

## Pricing

from $0.25 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Google Trends Scraper — related queries, by region, CSV/JSON

Google Trends as Excel-ready rows: interest over time, interest by region, related queries. One flat row per data point, each with a stable `id`. $0.25 per 1,000 rows.

| | This actor | Official Google Trends actor |
|---|---|---|
| Price | $0.25 per 1,000 rows | $0.30 per 1,000 rows |
| Output shape | Flat rows, one per data point, stable `id` | Nested timeline arrays |
| On a Google 429 | Session rotates and the run continues (observed in our soak runs, see Reliability) | Not documented |
| Failed or timed-out runs, last 30 days (public store stats, 2026-09-09) | Not enough public runs yet; listing is new | 27% (5,996 of 21,833) |
| Empty related topics | Zero rows, zero charge, run succeeds | Not documented |

### Try it for free

```json
{
  "searchTerms": ["coffee"],
  "outputs": ["interestOverTime", "relatedQueries"],
  "geo": "US",
  "timeRange": "today 12-m"
}
```

Measured on 2026-09-09 (run ef6NeMf4qBi5flDSI): 53 interest-over-time rows and 50 related-query rows, 103 rows, $0.026 at $0.25 per 1,000. Row counts vary by term and range.

#### Example output rows

```json
{
  "type": "interestOverTime",
  "term": "coffee",
  "geo": "US",
  "timeRange": "today 12-m",
  "time": "2025-09-07T00:00:00.000Z",
  "formattedTime": "Sep 7 – 13, 2025",
  "value": 58,
  "isPartial": false,
  "fetchedAt": "2026-09-09T06:39:34.060Z",
  "id": "b3790555d1acb5d3"
}
```

```json
{
  "type": "relatedQueries",
  "term": "coffee",
  "list": "top",
  "rank": 1,
  "query": "coffee shop",
  "value": 88,
  "formattedValue": "88",
  "link": "/trends/explore?q=coffee+shop&date=today+12-m&geo=US",
  "fetchedAt": "2026-09-09T06:39:34.060Z",
  "id": "172b002ab25dde86"
}
```

### What you get

Every dataset row carries `type`, `term`, `fetchedAt` (ISO timestamp), and a stable `id` (a hash of the row's type, term, and time/location/query key, so the same logical data point always gets the same id across runs).

#### `interestOverTime`

| Field | Description |
|---|---|
| `term` | The search term this row belongs to |
| `geo` | Geo filter used for the request (`""` = worldwide) |
| `timeRange` | The time range or custom range used for the request |
| `time` | ISO 8601 timestamp of the data point |
| `formattedTime` | Google's human-readable label for the point (e.g. "Sep 7 – 13, 2025") |
| `value` | Relative search interest, 0-100 |
| `isPartial` | True when Google flags this point as incomplete (usually the most recent point) |

#### `interestByRegion`

| Field | Description |
|---|---|
| `term` | The search term this row belongs to |
| `geo` | Geo filter used for the request |
| `resolution` | `COUNTRY`, `REGION`, `CITY`, or `DMA` |
| `geoCode` | Google's code for the region (e.g. `US`, `US-CA`) |
| `geoName` | Human-readable region name |
| `value` | Relative search interest in that region, 0-100 |

#### `relatedQueries`

| Field | Description |
|---|---|
| `term` | The search term this row belongs to |
| `list` | `top` or `rising` |
| `rank` | 0-based position within its list |
| `query` | The related search query |
| `value` | For `top`: 0-100 relative popularity. For `rising`: percentage growth, capped at 5000 to represent "Breakout" |
| `formattedValue` | Google's display string (e.g. `"100"` or `"Breakout"`) |
| `link` | Relative Google Trends explore URL for that query |

#### `relatedTopics` (opt-in, best effort)

Same row shape as `relatedQueries`, with `topicTitle`, `topicType`, and `topicMid` (Google's topic identifier) in place of `query`.

As of September 2026, Google returns an empty related-topics list to most automated sessions even for mainstream terms, while related queries keep working. The actor requests topics only when you select this output in `outputs`, reports zero rows without failing the run when Google returns none, and does not charge for rows it did not return.

### Time ranges and geo codes

`timeRange` accepts Google Trends' own presets: `now 1-H`, `now 4-H`, `now 1-d`, `now 7-d`, `today 1-m`, `today 3-m`, `today 12-m` (default), `today 5-y`, or `all` (2004-present). Set `customTimeRange` to a specific window instead, formatted `"YYYY-MM-DD YYYY-MM-DD"` — this overrides `timeRange` when set.

`geo` takes a two-letter country code (`US`, `GB`, `DE`, ...), a country-region code (`US-CA`, `US-NY`, ...), or an empty string for worldwide. Region codes follow Google's own Trends explorer, which follows ISO 3166.

### How results are counted for pricing

Every pushed dataset row (one interest-over-time point, one region, one related query, one related topic) is one result. A single run over N terms and M output types produces roughly N × (points-per-timeseries + regions-per-geo-map + related-queries-found + related-topics-found), which varies by term and how much data Google has for it. Related queries/topics commonly return 0-50 rows per list; interest-by-region at `COUNTRY` resolution returns around 250 rows (one per country), and narrower resolutions return more.

### Recipes

#### Compare three terms on one scale

Put three products or brands on the same 0-100 axis instead of three separate scales.

```json
{
  "searchTerms": ["coffee", "tea", "matcha"],
  "compareTerms": true,
  "outputs": ["interestOverTime"],
  "geo": "US",
  "timeRange": "today 12-m"
}
```

Row count and cost: estimate, roughly 150-160 rows (about 52 weekly points per term over 12 months), well under $0.05. No real run at this exact input yet.

#### US interest plus rising queries as CSV

Pull one term's trend line and what people are searching alongside it, then hand the dataset straight to a spreadsheet.

```json
{
  "searchTerms": ["coffee"],
  "outputs": ["interestOverTime", "relatedQueries"],
  "geo": "US",
  "timeRange": "today 12-m"
}
```

Measured on 2026-09-09 (run ef6NeMf4qBi5flDSI): 53 interest-over-time rows and 50 related-query rows, 103 rows, $0.026. On the run's Dataset tab, use the Export button and choose CSV. To pull it by URL instead: `https://api.apify.com/v2/datasets/<datasetId>/items?format=csv`, where `<datasetId>` is the run's dataset ID from the Console or the API response.

#### My last Trends tool returned 429 — try this input

A shorter window, one term, and paced requests so a rate limit does not end the run.

```json
{
  "searchTerms": ["coffee"],
  "outputs": ["interestOverTime", "relatedQueries"],
  "geo": "US",
  "timeRange": "today 3-m",
  "pacingMs": 500
}
```

Row count and cost: estimate, in the range of the 103-row run above, under $0.05. This works because each search term gets its own session that rotates on a real 429: in our own test runs, a fresh session per term saw 0 real 429s in 30 requests across two runs, down from 7 real 429s in 28 requests on the prior version.

No Apify Console feature prefills an actor's input from a URL for a stranger to click through (checked docs.apify.com, September 2026); copy the input above into the Input editor by hand.

### Advanced options

- `searchTerms` accepts 1 to 5 terms per Google Trends comparison; more than 5 are automatically batched into separate comparison calls of up to 5.
- `compareTerms` (default off): when enabled, all search terms in a comparison are sent together so their values are relative to each other (one term is the 0-100 anchor). Off by default, each term is scored independently on its own 0-100 scale.
- `maxConcurrency` (default 2, max 3): how many search terms are processed in parallel. Higher values finish faster but raise the chance of Google 429s.
- `requestsPerSession` (default 8): reuse a Trends session for this many successful requests, then rotate. A session still rotates immediately on a real 429, regardless of this setting.
- `proxyConfiguration` (default: Apify Proxy on): Google Trends rate-limits by IP. Using Apify Proxy is strongly recommended for any run beyond a couple of terms.
- `category`, `searchType`, and `regionResolution` narrow the request to a Google Trends category, search vertical (web/images/news/YouTube/Shopping), and region granularity.

### Coming from pytrends or google-trends-api?

Two symptoms bring people here.

**Related queries come back empty.** google-trends-api's own issue tracker reports an empty `rankedList` for related queries ([pat310/google-trends-api#174](https://github.com/pat310/google-trends-api/issues/174), open since 2025-02-19), and pytrends has been archived since August 2024, so neither library will be fixed upstream. The current widget protocol (an explore call, then a per-widget token, then the `relatedsearches` call) still returns data. This actor uses the current protocol; the `relatedQueries` rows in the example above came from a real run on 2026-09-09. Related topics are different: Google returns an empty list to automated sessions for that widget, so it is opt-in and never charged when empty.

**HTTP 429 (too many requests).** Two 429s get mixed up. The first request to `trends.google.com/trends/explore` always answers 429 while it sets the `NID` cookie; that one is harmless if the cookie is kept. The real rate limit hits the `/trends/api/` calls when one IP or session makes too many requests in a short window. This actor keeps a session, rotates it on a real 429, retries with backoff, and continues with the other terms; a run fails only if every term fails. In our test runs on 2026-09-09 every term completed from both a home IP and Apify datacenter proxies. On datacenter, version 0.1.2 saw 7 real 429s in 28 requests, all recovered by session rotation; version 0.1.11 (fresh session per term, paced requests) saw 0 real 429s in 30 requests across two runs of 15 on the same input. Expect occasional retries rather than failures.

### Reliability

Sessions rotate automatically on a Google 429 response and retry with exponential backoff (1s, 2s, 4s, capped, up to 5 attempts). If a search term still fails after all retries, that term's failure is logged and the run continues with the remaining terms; the run fails outright only if every term fails.

### Limitations

- Google Trends values are relative, not absolute: 100 marks the peak popularity for the selected term, time range, and geo — not a fixed volume of searches.
- With `compareTerms` enabled, all terms in that comparison share one 0-100 scale relative to whichever term peaks highest; with it disabled (default), each term is scored independently and values are not comparable across terms.
- Google does not guarantee availability or consistency of historical data, and can change or withdraw related queries/topics for a given term with no notice.
- Very low-volume terms may return empty or partial results, particularly for `interestByRegion`.
- `relatedTopics` is frequently empty for automated sessions (see above); rely on `relatedQueries` for keyword expansion.

### Support

Questions or issues: ops@tallyrake.com

# Actor input Schema

## `searchTerms` (type: `array`):

1 to 5 search terms per Google Trends comparison. More than 5 terms are automatically batched into separate comparison calls of up to 5.

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

Preset Google Trends time window. Ignored if Custom time range is set.

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

Overrides Time range. Format: "YYYY-MM-DD YYYY-MM-DD" (e.g. "2023-01-01 2023-06-30").

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

Two-letter country code (e.g. "US"), or country-region code (e.g. "US-CA"). Leave empty for worldwide.

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

Google Trends category ID. 0 means all categories.

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

Which Google property to pull trends from.

## `outputs` (type: `array`):

Which data to fetch. Each selected output becomes its own row type in the dataset.

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

Granularity used for Interest by region.

## `compareTerms` (type: `boolean`):

When enabled, all search terms are sent as a single Google Trends comparison so their values are relative to each other (one term is the 0-100 anchor). When disabled (default), each term is fetched on its own 0-100 scale.

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

Google Trends aggressively rate-limits by IP. Using Apify Proxy is strongly recommended for any run beyond a couple of terms.

## `maxConcurrency` (type: `integer`):

Maximum number of search terms processed in parallel. Keep at 3 or below to avoid Google rate limits.

## `requestsPerSession` (type: `integer`):

Reuse a Google Trends session for this many successful requests, then rotate to a fresh one. A session also rotates immediately on a rate-limit response.

## `pacingMs` (type: `integer`):

Base jittered delay in milliseconds between Google Trends requests; 0 disables pacing.

## Actor input object example

```json
{
  "searchTerms": [
    "coffee"
  ],
  "timeRange": "today 12-m",
  "geo": "US",
  "category": 0,
  "searchType": "",
  "outputs": [
    "interestOverTime",
    "relatedQueries"
  ],
  "regionResolution": "COUNTRY",
  "compareTerms": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxConcurrency": 2,
  "requestsPerSession": 8,
  "pacingMs": 500
}
```

# Actor output Schema

## `interestOverTime` (type: `string`):

Rows of type interestOverTime (one per term per time point).

## `interestByRegion` (type: `string`):

Rows of type interestByRegion (one per term per region).

## `relatedQueries` (type: `string`):

Top and rising related queries per term.

## `allRows` (type: `string`):

Every row of every selected output type, flat JSON/CSV.

# 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 = {
    "searchTerms": [
        "coffee"
    ],
    "timeRange": "today 12-m",
    "geo": "US"
};

// Run the Actor and wait for it to finish
const run = await client.actor("tallyrake/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 = {
    "searchTerms": ["coffee"],
    "timeRange": "today 12-m",
    "geo": "US",
}

# Run the Actor and wait for it to finish
run = client.actor("tallyrake/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 '{
  "searchTerms": [
    "coffee"
  ],
  "timeRange": "today 12-m",
  "geo": "US"
}' |
apify call tallyrake/google-trends-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tallyrake/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/17lIopgoFolsIjnzd/builds/ah6ZM3Z38mfRi5mxI/openapi.json
