# Google Trends Scraper: Interest Over Time, Regions & Related (`mdcurt/google-trends-scraper`) Actor

Google Trends data for any keyword without a browser: interest over time, interest by region, related queries and topics, plus what is trending now — via the same JSON endpoints the Trends site uses. First record in seconds, pay per result.

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

## Pricing

from $1.40 / 1,000 records

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: Interest Over Time, Regions & Related

Google Trends data for any keyword **without a browser**: interest over time, interest by region, related queries and
related topics, plus the country's "Trending now" feed. The Actor calls the same JSON endpoints the Trends website calls
(explore → widget tokens → widget data), so a keyword's full series arrives in about 2 seconds and a 70-keyword run
finishes in under 90 seconds on a 256 MB datacenter run. No login, no API key, no Puppeteer. Pay per result.

Built for people who were burned by browser-based Trends scrapers that time out or fail half their runs: the Actor paces
itself around Google's rate limit (a 429 is paused and retried, never a failure), rotates sessions, dedupes, and writes a
SUMMARY record with every counter you need to trust the data.

### What it does

For every keyword you pass it returns one record per selected dataset:

| Dataset | One record per keyword with… |
|---|---|
| `interestOverTime` | the complete 0–100 series (`points[]` with ISO dates and `isPartial`), plus `average`, `peak`, `latest`, `pointCount`, `resolution` (MINUTE/HOUR/DAY/WEEK/MONTH — chosen by Google from the time range) |
| `interestByRegion` | every country/region/city/DMA with data, sorted by value, plus `topRegion` and `regionCount` |
| `relatedQueries` | the **Top** list (25 queries with index 0–100) and the **Rising** list (25 queries with `+250%`-style growth or `Breakout`), each with a Trends link |
| `relatedTopics` | the same shape for topics (title, type, Google `mid`) — Google currently returns this list empty for many terms, in which case no record is charged |
| `trendingNow` | the country's "Trending now" feed (no keywords needed): ~10–20 trending searches with approximate traffic, start time, picture source and the headline news items behind them |

Values are Google's relative index (100 = the keyword's own peak in the chosen range and location), exactly as the Trends
site shows them. Each keyword is queried on its own, so series are not rescaled against each other.

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `keywords` | string\[] | `["chatgpt"]` | Search terms or Google topic ids (`/m/0k8z`). Up to a few hundred per run; ~1 request per keyword plus one per dataset. |
| `geo` | string | `""` (worldwide) | ISO country (`US`, `GB`, `DE`, `IN`), region (`US-CA`, `GB-ENG`) or US DMA (`US-CA-807`). Also picks the `trendingNow` country. |
| `timeRange` | string | `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`, or a custom `YYYY-MM-DD YYYY-MM-DD`. Aliases: `7d`, `30d`, `12m`, `5y`. |
| `datasets` | string\[] | interest over time, by region, related queries | Any of `interestOverTime`, `interestByRegion`, `relatedQueries`, `relatedTopics`, `trendingNow`. |
| `category` | integer | `0` | Trends category id (0 = all; 5 Computers & Electronics, 71 Food & Drink, 12 Business, 45 Health, 20 Sports — the `cat=` number in the Trends URL). |
| `maxItems` | integer | `100` | Total records cap (1–10 000). |
| `proxyConfiguration` | object | Apify datacenter proxy | Datacenter proxies pass; Google only rate-limits, which the Actor paces around. |

Agent-friendly: a single keyword with the default datasets is one record per dataset in ~2–3 seconds, for about $0.011.

### Output

`interestOverTime` (abridged):

```json
{
  "kind": "interestOverTime",
  "id": "interestOverTime:3f1c9e0b2a77",
  "url": "https://trends.google.com/trends/explore?q=ozempic&date=today+5-y",
  "keyword": "ozempic", "geo": "", "timeRange": "today 5-y", "category": 0, "property": "",
  "resolution": "WEEK", "hasData": true, "pointCount": 262,
  "average": 57.1,
  "peak":   { "date": "2024-05-26T00:00:00.000Z", "value": 100 },
  "latest": { "date": "2026-11-01T00:00:00.000Z", "value": 44, "isPartial": true },
  "firstDate": "2021-10-31T00:00:00.000Z", "lastDate": "2026-11-01T00:00:00.000Z",
  "points": [ { "date": "2021-10-31T00:00:00.000Z", "value": 3, "isPartial": false }, "…" ],
  "source": "trends.google.com/trends/api/widgetdata/multiline",
  "scrapedAt": "2026-11-06T17:48:40.000Z"
}
```

`relatedQueries` carries `top[]` and `rising[]` (`{ query, value, formattedValue, isBreakout, url }`), `interestByRegion` carries
`regions[]` (`{ geoCode, name, value }`) and `topRegion`, `trendingNow` carries `title`, `rank`, `approxTraffic` (`"20K+"` → 20000),
`approxTrafficText`, `publishedAt`, `picture`, `pictureSource` and `news[]` (`{ title, url, source }`, headline snippets only).

The key-value store's `SUMMARY` record lists every counter: keywords explored, records per dataset, `emptyResults` (datasets Google
returned empty for — not charged), `noDataKeywords`, `rateLimited`, `blocked`, `requestsFailed`, time to first record, p95 latency,
peak concurrency and compute seconds. Dataset views: **Overview**, **Interest over time**, **Trending now**.

### Pricing

Pay per event: **$0.005 per run** + **$0.002 per record** (Store discounts: −10 % Starter, −20 % Scale, −30 % Business).
A record is a whole series or table, not a data point. Examples: one keyword with the three default datasets ≈ $0.011; 100 keywords
× 3 datasets = $0.605; the trending feed for one country ≈ $0.03. A 256 MB run of 70 keywords took 85 s of compute (≈ $0.007 at the
Starter tier). Compare: the official browser-based Actor charges $0.006 per record and fails about half of its public runs; the
current PPE leader charges $0.025 per start + $0.002 per record.

### Monitoring (scheduled runs)

Schedule the Actor with your keyword list and `timeRange: "now 7-d"` (hourly points) or `today 3-m` (daily points) and feed the
dataset into [mdcurt/dataset-diff-monitor](https://apify.com/mdcurt/dataset-diff-monitor) to get alerted when `latest.value` jumps, a
new query appears in `rising[]` with `isBreakout: true`, or a term enters the `trendingNow` feed. Record ids are stable per
keyword × geo × range × category, so diffs line up run to run.

### Speed (live tests, 2026-11-06, datacenter egress)

| Run | Result |
|---|---|
| 1 keyword, `interestOverTime` only | 1 record, first record 2.2 s, 2 requests |
| 3 keywords worldwide, 5 years, all four keyword datasets | 9 records (related topics empty → not charged), first record 2.6 s, 15 requests |
| `trendingNow` for GB | 10 records in 0.5 s, 1 request |
| 2 keywords, `US-CA`, custom range `2025-01-01 2025-06-30` | 4 records (daily resolution), first record 2.5 s |
| **70 keywords × 3 datasets** | **210 records, 280/280 requests OK, 0 rate limits, 0 blocks, first record 2.2 s, 85 s compute (148 records/min)** |
| 200 keywords × 3 datasets (sustained) | see the Limitations: Google throttles a single IP after roughly 150–300 calls; the Actor slows to ~1 request/s and finishes with zero failed requests |

### Tutorials

- **[How to track competitors on Google Trends automatically (no browser, $0.035 a run)](https://dev.to/mdcurt/how-to-track-competitors-on-google-trends-automatically-no-browser-0035-a-run-3jjb)** — also in
  `examples/competitor-search-interest-monitor/` in the Actor source: a real 15-record sample dataset (5 running-shoe brands, 2026-11-08), how to read it, and the dataset-diff-monitor
  recipe that turns it into a weekly Slack digest. The ready-made input is the example task *Monitor competitor brands' Google search
  interest by US state* on this Actor's **Example tasks** tab.

### For AI agents

Pass one thing: `{"keywords": ["<term>"]}` (optionally `"geo": "US"`). Back come three records in about 2–3 seconds — `interestOverTime`
(`average`, `peak.date`, `latest.value`, the full `points[]`), `interestByRegion` (`topRegion`, `regions[]`) and `relatedQueries`
(`top[]`, `rising[]` with `isBreakout`). One lookup costs about $0.011 ($0.005 start + 3 × $0.002). The Actor runs with limited
permissions and no login, so it is usable through Apify's MCP server (`https://mcp.apify.com/?tools=mdcurt/google-trends-scraper`)
and through agentic payments without an Apify account. Pass `maxItems: 1` with `datasets: ["interestOverTime"]` for the cheapest
single-number answer.

### Limitations

- Google Trends is sampled, relative data; Google may answer "not enough data" (an all-zero series, `hasData: false`) for rare terms.
- `relatedTopics` comes back empty for many terms since Google changed the Trends backend; empty datasets are not charged.
- Keywords are explored one at a time (no 5-term comparison rescaling yet) and only web search (`property` youtube/news/images/shopping is on the roadmap).
- One IP sustains roughly 1–3 requests per second before Google answers HTTP 429. The Actor pauses, lowers concurrency, retries on
  another session and never counts a 429 as a failure, but very large runs (500+ keywords) take several minutes. Residential proxies
  are not needed.
- The Actor never requests the robots-disallowed `/trends/explore` HTML page; it reads the JSON API behind it. Trends data is
  Google's; use it within Google's terms.

### Changelog

- **1.0.0** (2026-11-06) — first release: interest over time, interest by region, related queries/topics, trending-now feed; cookie
  bootstrap per session, 429 pacing, six-tier Store discounts.

# Actor input Schema

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

Search terms to look up, one per entry (e.g. "chatgpt", "air fryer"), or Google topic ids ("/m/0k8z"). Each keyword yields one record per selected dataset; values are Google's 0–100 relative index per keyword. The first record arrives in about 2 seconds.

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

Empty = worldwide. Otherwise an ISO country code (US, GB, DE, IN), a region (US-CA, GB-ENG) or a US DMA (US-CA-807). Also selects the country of the trendingNow feed.

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

One of: 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, all — or a custom range "YYYY-MM-DD YYYY-MM-DD". Short aliases work too (7d, 30d, 12m, 5y). Google picks the resolution (minutes/hours/days/weeks/months) from the range.

## `datasets` (type: `array`):

Which Trends panels to return, one record per keyword each: interestOverTime (the full series with average, peak and latest), interestByRegion (every region with data, sorted), relatedQueries and relatedTopics (top + rising with Breakout flags). trendingNow returns the country's "Trending now" feed (~10–20 records, no keywords needed).

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

Google Trends category number to restrict the keywords to (0 = all categories; e.g. 5 Computers & Electronics, 71 Food & Drink, 12 Business & Industrial, 45 Health, 20 Sports). Find ids in the Trends category picker URL (cat=…).

## `maxItems` (type: `integer`):

Maximum number of records to return in total (1–10000). Each keyword produces at most one record per selected dataset; trendingNow adds one record per trending search.

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

Apify Proxy settings. Datacenter proxies work (tested at 200+ keywords, zero blocks; Google only rate-limits, which the Actor paces around). Switch to a RESIDENTIAL group only if the SUMMARY record reports blocked pages.

## Actor input object example

```json
{
  "keywords": [
    "chatgpt",
    "air fryer"
  ],
  "geo": "US",
  "timeRange": "today 12-m",
  "datasets": [
    "interestOverTime",
    "interestByRegion",
    "relatedQueries"
  ],
  "category": 0,
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `records` (type: `string`):

One record per keyword per dataset (interestOverTime series, interestByRegion table, relatedQueries, relatedTopics) and one per trending search; each carries kind, keyword, geo, timeRange, url and scrapedAt.

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

SUMMARY record: counts, duplicates and known ids skipped, blocked pages, inferred rate limit, p95 latency, time to first record and compute seconds.

# 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",
        "air fryer"
    ],
    "geo": "US",
    "timeRange": "today 12-m",
    "datasets": [
        "interestOverTime",
        "interestByRegion",
        "relatedQueries"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("mdcurt/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",
        "air fryer",
    ],
    "geo": "US",
    "timeRange": "today 12-m",
    "datasets": [
        "interestOverTime",
        "interestByRegion",
        "relatedQueries",
    ],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("mdcurt/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",
    "air fryer"
  ],
  "geo": "US",
  "timeRange": "today 12-m",
  "datasets": [
    "interestOverTime",
    "interestByRegion",
    "relatedQueries"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call mdcurt/google-trends-scraper --silent --output-dataset

```

## MCP server setup

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