# Google Trends Scraper (`cirkit/google-trends-scraper`) Actor

Fast Google Trends scraper. Get interest over time, interest by subregion, and top and rising related queries and topics for any keyword, in any country, over any time range. Reads Google's own widget JSON API directly, no headless browser and no API key. Flat CSV-ready output.

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

## Pricing

from $0.70 / 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/platform/actors/running/actors-in-store#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

Get Google Trends data for any keyword — **interest over time**, **interest by
subregion**, and **top and rising related queries** — in any country, over any
time range.

Reads Google's own widget JSON API directly. No headless browser, no API key, no
login. A keyword over 12 months returns in about 3 seconds.

### Why this one

The established Google Trends actors drive a real browser, which is why they are
slow and why their runs fail as often as they do. This one is plain HTTP against
the same JSON endpoints the Trends frontend calls, and it handles the one thing
that actually breaks Google Trends scraping: **Google 429s any IP that has not
first been issued an `NID` cookie.** This actor bootstraps that cookie per proxy
session and rotates sessions when Google pushes back, which is why cheap
datacenter proxies are enough — residential is not required and does not help.

Output is **flat**. One row per data point, every row tagged with a `dataType`,
so the CSV export opens in a spreadsheet and pivots without unpacking nested
JSON first.

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `keywords` | array | — | **Required.** Search terms, one per line. |
| `geo` | string | `US` | `US`, `GB`, `DE`; `US-CA` for state level; empty for worldwide. |
| `timeframe` | 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`. |
| `customTimeRange` | string | — | `2024-01-01 2024-12-31`. Overrides `timeframe`. |
| `dataTypes` | array | interest over time, by subregion, related queries | Drop the ones you do not need to cut runtime and cost. |
| `maxItems` | integer | 1000 | Hard cap on rows written across all keywords. |
| `compareKeywords` | boolean | `false` | Chart all keywords together, normalised against each other (max 5), like adding comparison terms on the site. |
| `category` | integer | `0` | Google's numeric category id. `0` = all. |
| `property` | string | `""` (web) | `images`, `news`, `youtube`, `froogle`. |
| `proxyConfiguration` | object | Apify Proxy | Datacenter is sufficient. |

```json
{
  "keywords": ["air fryer", "pickleball"],
  "geo": "US",
  "timeframe": "today 12-m",
  "maxItems": 500
}
```

### Output

Every row carries `dataType`, `keyword`, `geo`, `timeframe`, `category`,
`property` and `scrapedAt`, plus the fields for its type.

**`interestOverTime`** — one row per time bucket.

```json
{
  "dataType": "interestOverTime",
  "keyword": "air fryer",
  "geo": "US",
  "timeframe": "today 12-m",
  "date": "2025-08-03T00:00:00Z",
  "formattedTime": "Aug 3 – 9, 2025",
  "value": 59,
  "hasData": true,
  "isPartial": false
}
```

`isPartial` marks the final bucket of a live range — it is still filling, and
charting it as a crash is the classic Google Trends misread.

**`interestBySubregion`** — one row per region (51 for the US: 50 states + DC).

```json
{
  "dataType": "interestBySubregion",
  "keyword": "air fryer",
  "regionCode": "US-WY",
  "regionName": "Wyoming",
  "value": 100,
  "formattedValue": "100"
}
```

**`relatedQueries`** — one row per related query, `metric` is `TOP` or `RISING`.

```json
{
  "dataType": "relatedQueries",
  "keyword": "air fryer",
  "metric": "RISING",
  "rank": 1,
  "query": "best air fryer 2026",
  "value": 12400,
  "formattedValue": "Breakout",
  "isBreakout": true,
  "link": "https://trends.google.com/trends/explore?q=best+air+fryer+2026&date=today+12-m&geo=US"
}
```

`isBreakout` is set for terms Google labels **Breakout** — growth too large to
put a number on. These are the terms worth acting on.

Roughly **150 rows per keyword** at `geo=US`, `today 12-m`, with the three
default data types on.

### A note on related topics

Google currently serves an **empty related-topics widget**. Verified against
broad search terms and against resolved entity ids (`/m/05p0rrx`), on both
residential and datacenter IPs — HTTP 200 with an empty list every time. It is a
gap on Google's side, not a scraping failure.

The option is still there in case Google restores it, but it is **off by
default** and the run logs say so plainly rather than leaving you to wonder.
Related *queries* are unaffected and work fine.

### Empty results

A search that legitimately charts nothing writes a single explanatory row with
`dataType: "noResults"` rather than an empty dataset. Terms below Google's volume
threshold are not charted at all — broaden the keyword, lengthen the timeframe,
or set `geo` to empty for worldwide.

Invalid input (`maxItems: 0`, a malformed `customTimeRange`, an unsupported
`property`) fails the run loudly instead of finishing "successfully" with nothing
in the dataset.

### Notes

- Google rate-limits per IP. Leave Apify Proxy on for anything past a smoke test.
- Values are Google's own 0–100 relative index, not absolute search volume —
  that is how Google Trends works, and no scraper can change it.
- With `compareKeywords` on, values are normalised across the set, so the terms
  are directly comparable but no longer on their own 0–100 scale.

# Actor input Schema

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

Search terms to analyse, one per line. Each keyword is scraped independently unless 'Compare keywords' is on.

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

Two-letter country code such as US, GB or DE. Add a subregion for state or province level, e.g. US-CA. Clear the field entirely for worldwide, which returns interest broken down by country.

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

Preset window to chart. Ignored when 'Custom time range' is filled in. Shorter ranges return finer buckets: 'now 7-d' is hourly, 'today 12-m' is weekly.

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

Explicit window as 'YYYY-MM-DD YYYY-MM-DD', for example '2024-01-01 2024-12-31'. Overrides the preset time range when set.

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

Which datasets to pull for each keyword. Deselecting the ones you do not need makes runs faster and cheaper. Related topics is off by default because Google itself currently serves an empty topics widget - see the note in its label.

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

Hard cap on rows written to the dataset across all keywords. One keyword over 12 months in the US yields roughly 150 rows with every data type enabled.

## `compareKeywords` (type: `boolean`):

Chart all keywords together so their values are normalised against each other, exactly like adding comparison terms on trends.google.com. Maximum 5 keywords. In this mode the subregion rows show each keyword's share of interest in that region rather than its own 0-100 index. Leave off to scrape each keyword independently.

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

Google Trends numeric category id to restrict the query, for example 71 (Food & Drink) or 7 (Finance). 0 means all categories.

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

Which Google surface to measure. Web search is the default.

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

Google Trends rate-limits per IP, so a proxy is required for anything beyond a couple of keywords. Apify datacenter proxy is enough - residential costs far more and measurably does not help here.

## Actor input object example

```json
{
  "keywords": [
    "air fryer",
    "pickleball"
  ],
  "geo": "US",
  "timeframe": "today 12-m",
  "dataTypes": [
    "interestOverTime",
    "interestBySubregion",
    "relatedQueries"
  ],
  "maxItems": 500,
  "compareKeywords": false,
  "category": 0,
  "property": "",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset of Google Trends rows.

## `datasetCsv` (type: `string`):

Same dataset rendered as 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 = {
    "keywords": [
        "air fryer",
        "pickleball"
    ],
    "geo": "US",
    "maxItems": 500,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("cirkit/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": [
        "air fryer",
        "pickleball",
    ],
    "geo": "US",
    "maxItems": 500,
    "proxyConfiguration": { "useApifyProxy": True },
}

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

```

## MCP server setup

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