# Google Trends Scraper & API (`curiousanand/google-trends-scraper`) Actor

Google Trends interest over time, by region, related queries and topics as JSON, CSV or Excel. Pay only for keywords that return data. No browser, never hangs, unlimited keywords on one scale, daily data over years, works with AI agents (MCP).

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

## Pricing

from $0.60 / 1,000 keyword results

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 & API

Interest over time, interest by region, related queries and related topics from Google Trends, for one keyword or ten thousand. **$1.50 per 1,000 keywords (down to $0.60 on paid Apify plans), compute included, and keywords that fail are free.**

I built this after watching browser-based Trends scrapers run for twenty minutes and come back empty. This one talks to the same data endpoints the Trends website uses, so a keyword with all four sections usually takes 2 to 5 seconds and the run never hangs.

- **Pay for results, not attempts.** Every keyword gets a status row (`ok`, `partial` or `failed`). Only `ok` keywords are charged.
- **Compare more than 5 keywords on one scale.** Google caps comparisons at 5. Normalize mode puts any number of keywords on a single 0–100 scale.
- **Several countries in one run.** List them in `geos` and every keyword runs in each one.
- **Daily data over years.** Google switches to weekly data after about 9 months. Daily mode stitches overlapping windows into one daily series.
- **Bring your existing input.** It accepts the input format of the official Apify Google Trends scraper, Trends URLs, and plain English ("United Kingdom", "past 90 days").
- **Works from AI agents** like Claude, ChatGPT and Cursor through Apify's MCP server.

### How it compares

| | Typical browser-based Trends scraper | This actor |
|---|---|---|
| How it gets data | Loads trends.google.com in a headless browser | Calls Trends' data endpoints directly |
| Typical time per keyword | 30 s to several minutes, sometimes never | 2–5 s |
| Memory per run | 4 GB | 256 MB |
| Charged when a keyword fails | Often | Never |
| Keywords on one comparable scale | 5 | Unlimited (normalize mode) |
| Countries per run | 1 | Up to 50 |
| Daily data for ranges over 9 months | No | Yes (daily mode) |
| Compute cost | Added on top | Included in the price |

### What it costs

| You run | You pay |
|---|---|
| 1 keyword, all sections | $0.0015, plus $0.001 if related topics come back |
| 100 keywords | $0.15 |
| 1,000 keywords | $1.50 |
| 10,000 keywords | $15 |
| 10 keywords in 5 countries | $0.075 (each keyword × country counts once) |
| A keyword that fails | $0 |

A few details, so nothing surprises you:

- **Paid Apify plans pay less**: $1.20 per 1,000 keywords on Bronze, $0.90 on Silver, and $0.60 on Gold, Platinum and Diamond. The table above uses the Free plan price.
- **Related topics** cost an extra $1 per 1,000 keywords, and only when Google actually returned topics. Fetching them needs a heavier request. If you don't need them, untick "Related topics" and you pay only the keyword price.
- **Rows output** (one row per date or region, for spreadsheets) adds $0.01 per 1,000 rows. The default nested output has no row charge.
- **Max cost per run.** Set one and the actor only starts keywords that fit inside it, then stops cleanly and tells you how many it skipped.
- Apify adds a tiny standard start fee, well under $0.001 per run.

### Quick start

The simplest input:

```json
{ "searchTerms": ["web scraping", "ai agents"], "geo": "US", "timeRange": "today 12-m" }
```

Compare streaming services on one scale (add as many as you like):

```json
{ "searchTerms": ["netflix", "hulu", "disney plus", "max", "peacock", "paramount plus"], "mode": "normalize", "geo": "US", "sections": ["timeline"] }
```

The same keywords in three markets:

```json
{ "searchTerms": ["electric bike", "cargo bike"], "geos": ["US", "GB", "Germany"], "timeRange": "today 12-m" }
```

Three years of daily data:

```json
{ "searchTerms": ["black friday"], "customTimeRange": "2023-09-01 2026-09-30", "dailyResolution": true, "geo": "US" }
```

Paste Google Trends URLs:

```json
{ "startUrls": [{ "url": "https://trends.google.com/trends/explore?q=tea,coffee&geo=GB&date=today%203-m" }] }
```

Plain English works too: `"geo": "Germany"`, `"timeRange": "past 7 days"`, `"sections": ["timeline", "region"]`.

### What you get

| Section | Contents |
|---|---|
| Interest over time | A 0–100 value per hour, day, week or month |
| Interest by region | Countries, states, US metro areas (DMA) or cities |
| Related queries | Top and rising, including Breakout terms |
| Related topics | Top and rising Knowledge Graph topics |
| Status | `ok`, `partial` or `failed` for every keyword, with the reason |

#### Sample item (default nested output)

Real output, trimmed to one entry per list:

```json
{
  "keyword": "pixel phone", "geo": "GB", "timeRange": "today 3-m", "status": "ok", "resolution": "DAY",
  "interestOverTime_averages": [58.66],
  "interestOverTime_timelineData": [{ "time": "1784332800", "date": "2026-07-18", "value": [53], "formattedValue": ["53"], "hasData": [true] }],
  "interestBy": [{ "geoCode": "GB-ENG", "geoName": "England", "value": [100], "formattedValue": ["100"], "hasData": [true] }],
  "relatedQueries_top": [{ "query": "google phone", "value": 100, "formattedValue": "100", "link": "https://trends.google.com/trends/explore?q=google+phone&date=today+3-m&geo=GB" }],
  "relatedQueries_rising": [{ "query": "google pixel phone price increase", "value": 12850, "formattedValue": "Breakout", "link": "https://trends.google.com/trends/explore?q=google+pixel+phone+price+increase&date=today+3-m&geo=GB" }],
  "relatedTopics_top": [], "relatedTopics_rising": [],
  "errors": [], "notes": [], "durationMs": 3032
}
```

A Breakout query shows up as `"formattedValue": "Breakout"`. Rows output adds an `isBreakout` column and an `isPartial` column, which flags the current, still-incomplete day or week.

Pick **rows** output if you're going straight into Excel, Google Sheets or a BI tool. You get one row per date, region or related item, with a `type` column to filter on.

Every run also saves a `SUMMARY` record with the success rate, requests, retries, proxy used and keywords charged.

### Measured, not promised

| Test (Oct 2026, on Apify) | Result |
|---|---|
| 500 keywords, all sections | 500 of 500 returned data, about 0.6–0.9 s per keyword with 10 in parallel |
| Google throttling during that run | 35–39 rate limits out of about 3,200 requests, all retried automatically. It switched to residential proxies on its own when needed |
| Memory | Peak about 180 MB, even for 5 years of daily data |
| Platform restarts | Finished keywords are skipped on restart, unfinished ones resume, nothing is charged twice |

### Switching from the official Apify scraper

Paste your existing input. These fields work the same: `searchTerms`, `isMultiple`, `timeRange`, `customTimeRange`, `geo`, `category`, `startUrls`, `maxItems`, `viewedFrom`, `maxConcurrency`, `maxRequestRetries`. `skipDebugScreen` and `pageLoadTimeoutSecs` are ignored because there's no browser. `spreadsheetId` isn't supported yet, so paste the terms instead.

Three output differences to check before you switch a pipeline:

- Region data is always in `interestBy` (the official scraper splits it into `interestBySubregion`, `interestByCity` or `interestByMetro`).
- Timeline points carry `date` (YYYY-MM-DD or an ISO time) instead of `formattedTime`.
- Related-item `link` values are full URLs.

### Use it from code, AI agents and other tools

**API.** Start a run and get the results in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/curiousanand~google-trends-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"searchTerms": ["tea", "coffee"], "geo": "GB", "timeRange": "past 90 days"}'
```

**Python:**

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("curiousanand/google-trends-scraper").call(run_input={"searchTerms": ["tea", "coffee"], "geo": "GB"})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["keyword"], item["interestOverTime_averages"])
```

**Claude, ChatGPT, Cursor and other agents (MCP).** Add Apify's MCP server with just this tool:

```json
{ "mcpServers": { "apify": { "url": "https://mcp.apify.com?tools=curiousanand/google-trends-scraper" } } }
```

Then ask something like *"Compare interest in Notion, Obsidian and Evernote in Germany over the past 5 years."*

**No code.** Apify's integrations can send results to Google Sheets, Slack, Zapier, Make, n8n or a webhook when a run finishes. Add a Schedule for weekly tracking.

**Want what's trending right now instead?** [Google Trends Trending Now Scraper with News](https://apify.com/curiousanand/google-trends-trending-now) returns the full Trending Now list for any country, with the news behind each trend.

### FAQ

**Is there an official Google Trends API?** Google has an alpha API with limited access. Most people use the Trends website or a scraper like this one, which reads the same data the website shows.

**How do I export Google Trends data to CSV or Excel?** Run the actor, open the dataset and click Export. Choose rows output for one row per date or region, which opens cleanly in Excel and Google Sheets.

**Why are related topics sometimes empty?** Since September 2026 Google withholds related topics from automated requests. The actor fetches them through Google's embed widget instead, which has a per-IP quota. In my tests, residential proxies got topics for 10 of 10 keywords and the default datacenter proxies got them for 0 of 30. When topics are missing, the keyword's notes say why and the topics charge isn't applied. If topics matter to you, set the proxy to Residential.

**Do I need a proxy or a Google account?** You don't need a Google account. On Apify the default proxy is included in the price, and the actor switches to residential proxies by itself if Google starts blocking. If you run it somewhere without a proxy, Google will rate-limit you after a handful of keywords.

**Can I compare countries?** Yes. Put them in `geos` and each keyword runs in every country, with country in the `geo` field. Each country has its own 0–100 scale, as on the Trends website, so compare shapes and timing across countries rather than raw numbers. In normalize mode every country gets its own anchor unless you set `anchorTerm`.

**How does normalize mode work?** Your keywords go to Google in batches of 4, plus one anchor keyword that appears in every batch. The anchor's value in each batch puts all batches on one scale. Google rounds to whole numbers, so a keyword about 50 times smaller than the biggest one can't be measured precisely; those rows are marked `precisionWarning: low-precision` rather than showing false precision. Pick a medium-popular `anchorTerm` for the best results.

**Is the data the same as on the Trends website?** Yes, for the same query on the same day. Google samples its data, so values can move a little from one day to the next.

**Is scraping Google Trends legal?** The actor collects public, aggregated, anonymized data that anyone can see on trends.google.com. It doesn't touch personal data or log in anywhere. How you use the results is up to you.

**Something isn't working?** Open an issue on the Issues tab with your run link and I'll take a look.

# Actor input Schema

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

Keywords to look up. With 'Comma = compare' on, "tea, coffee" charts both terms together.

## `startUrls` (type: `array`):

Paste trends.google.com/trends/explore URLs. Their own terms, region, dates, category and property are used.

## `mode` (type: `string`):

separate: each term on its own 0–100 scale. compare: up to 5 terms on one chart. normalize: any number of terms on ONE shared scale (anchor method).

## `anchorTerm` (type: `string`):

Optional. A term of medium popularity included in every batch. Leave empty to pick one automatically.

## `isMultiple` (type: `boolean`):

Treat commas inside a search term as a comparison of up to 5 terms (same as apify/google-trends-scraper).

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

Preset range, or plain English like "past 7 days" or "last 3 months". Ignored if a custom range is set.

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

"YYYY-MM-DD YYYY-MM-DD", e.g. "2024-01-01 2024-12-31". Overrides the preset.

## `dailyResolution` (type: `boolean`):

Google only gives daily points for ranges up to ~9 months. Turn this on to get daily data for any range (stitched from overlapping windows). Uses more requests.

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

Country or region code (US, GB, US-CA) or a country name ("Germany"). Empty = worldwide.

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

Run every keyword in each of these countries or regions, e.g. \["US", "GB", "Germany"]. Each keyword × country is billed as one keyword. Leave empty to use "Region" above.

## `category` (type: `string`):

Google Trends category id, e.g. 71 for Food & Drink (the cat= number in a Trends URL). Empty or 0 = all categories.

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

Which Google search to measure: web, image, news, YouTube or Google Shopping searches.

## `sections` (type: `array`):

Fewer sections = faster and fewer requests. Related topics add a small `related-topics` charge, applied only to keywords that actually returned topics.

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

How detailed the "interest by region" data is. Automatic uses Google's default for the chosen region.

## `includeLowVolumeRegions` (type: `boolean`):

Also return regions with too little search volume for Google to score (they appear with no data).

## `useTopics` (type: `boolean`):

Looks up each term's Knowledge Graph topic (merges spellings and languages), like picking the 'Topic' suggestion on Google Trends.

## `outputFormat` (type: `string`):

nested (default): one item per keyword using the main field names of apify/google-trends-scraper — cheapest. rows: one row per date / region / related item, ideal for CSV, Excel and Sheets; billed per 1,000 rows because it stores ~100+ items per keyword.

## `language` (type: `string`):

Language for region names and related items, e.g. en-US, de, fr.

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

Process at most this many inputs (0 = all).

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

How many keywords are fetched in parallel. The scraper also slows itself down automatically if Google throttles.

## `maxRequestRetries` (type: `integer`):

How many times a failed request is retried (on a fresh IP, with backoff) before the keyword is marked failed.

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

Starts on Apify datacenter proxies and switches to residential automatically if Google blocks them.

## `residentialFallback` (type: `boolean`):

If Google blocks the datacenter IPs, switch to Apify residential proxies automatically for the rest of the run.

## `viewedFrom` (type: `string`):

Optional country for proxy IPs (e.g. US).

## Actor input object example

```json
{
  "searchTerms": [
    "web scraping"
  ],
  "mode": "separate",
  "isMultiple": false,
  "timeRange": "today 12-m",
  "dailyResolution": false,
  "geo": "",
  "category": "",
  "property": "web",
  "sections": [
    "timeline",
    "regions",
    "relatedQueries",
    "relatedTopics"
  ],
  "regionResolution": "AUTO",
  "includeLowVolumeRegions": false,
  "useTopics": false,
  "outputFormat": "nested",
  "language": "en-US",
  "maxItems": 0,
  "maxConcurrency": 10,
  "maxRequestRetries": 5,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "residentialFallback": true
}
```

# Actor output Schema

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

One item per keyword (nested format) or one row per keyword, date and region (rows format), each with a status and any errors.

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

Success rate, keywords charged, requests, retries and proxy usage for this run.

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

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

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

```

## MCP server setup

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