# Google Trends Scraper: Interest Over Time, Regions, Queries (`hirethomas/google-trends-scraper`) Actor

Google Trends scraper at $1.50 per 1,000 search terms: interest over time, interest by region (incl. US metro areas), related queries and Trending Now searches, all in one result per term. HTTP-only, no browser, validated output that fails loudly instead of returning empty data.

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

## Pricing

from $1.50 / 1,000 search terms

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?

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 (Reliable, No Browser)

Get Google Trends data for any keyword: **interest over time**, **interest by region**, **related queries** (top and rising, plus optional related topics), plus today's **Trending Now** searches for any country. Export to JSON, CSV or Excel, call it from the API, or schedule it.

Built to be boring and dependable:

- **HTTP only, no headless browser.** Small memory (256 MB is plenty) and fast runs.
- **Validated output.** Every row is checked field by field before it is saved (dates, 0-100 scores, names, links). Bad rows are dropped and counted, never silently saved.
- **Fails loudly.** If Google refuses all requests, or the output fails validation, the run is marked as failed with a clear reason instead of "succeeding" with an empty dataset.
- **Handles rate limits.** On HTTP 429 the actor backs off and continues on a fresh proxy session. It never tries to solve CAPTCHAs.
- **No start fee.**

### What you get

One row per search term, with everything Google Trends shows on the explore page:

| Field | Description |
|---|---|
| `searchTerm` | The keyword (or topic ID like `/m/0dl567`) |
| `geo`, `timeRange`, `category`, `searchProperty` | The settings used |
| `hasData` | `false` when Google does not have enough search volume for the term |
| `interestOverTime` | Array of `{ date, formattedTime, value (0-100), hasData, isPartial }` |
| `averageInterest`, `peakDate`, `peakValue`, `pointsWithData` | Quick summary of the timeline |
| `interestByRegion` | Array of `{ geoCode, geoName, value (0-100), formattedValue }`, sorted by value |
| `relatedQueries` | `{ top: [...], rising: [...] }` with `query`, `value`, `formattedValue` (e.g. `+250%` or `Breakout`), `link` |
| `relatedTopics` | Optional. `{ top: [...], rising: [...] }` with `title`, `type`, `mid`, `value`, `formattedValue`, `link` |
| `comparedWith` | Other terms in the same comparison (when "Compare terms" is on) |
| `warnings` | Notes such as "not enough search volume" |
| `trendsUrl` | Link to the same view on trends.google.com |

If you add countries under **Trending now**, you also get one row per trending search (`recordType: "trendingSearch"`) with `trendingTitle`, `approxTraffic` (e.g. `2000+`), `approxTrafficNumber`, `publishedAt`, `pictureUrl` and `newsArticles` (title, url, source).

#### Example row

From a real run on 2026-10-08 (`chatgpt`, US, past 90 days). Arrays are shortened here; the real row had 93 timeline points, 51 regions and 34 related queries.

```json
{
  "recordType": "searchTerm",
  "searchTerm": "chatgpt",
  "geo": "US",
  "timeRange": "today 3-m",
  "hasData": true,
  "interestOverTimeCount": 93,
  "averageInterest": 65,
  "peakDate": "2026-09-03T00:00:00.000Z",
  "peakValue": 100,
  "topRegion": "California",
  "topRelatedQuery": "chatgpt ai",
  "interestOverTime": [
    { "date": "2026-10-07T00:00:00.000Z", "formattedTime": "Oct 7, 2026", "value": 79, "hasData": true, "isPartial": false },
    { "date": "2026-10-08T00:00:00.000Z", "formattedTime": "Oct 8, 2026", "value": 73, "hasData": true, "isPartial": true }
  ],
  "interestByRegion": [
    { "geoCode": "US-CA", "geoName": "California", "value": 100, "formattedValue": "100" },
    { "geoCode": "US-GA", "geoName": "Georgia", "value": 92, "formattedValue": "92" }
  ],
  "relatedQueries": {
    "top": [{ "query": "chatgpt ai", "value": 100, "formattedValue": "100", "link": "https://trends.google.com/trends/explore?q=chatgpt+ai&date=today+3-m&geo=US" }],
    "rising": [{ "query": "sam altman chatgpt water usage", "value": 8750, "formattedValue": "Breakout", "link": "https://trends.google.com/trends/explore?q=sam+altman+chatgpt+water+usage&date=today+3-m&geo=US" }]
  },
  "trendsUrl": "https://trends.google.com/trends/explore?q=chatgpt&geo=US&date=today%203-m&hl=en-US",
  "scrapedAt": "2026-10-08T01:33:18.023Z"
}
```

### Input

```json
{
  "searchTerms": ["chatgpt", "gemini"],
  "compareTerms": false,
  "geo": "US",
  "timeRange": "today 12-m",
  "dataTypes": ["interestOverTime", "interestByRegion", "relatedQueries"],
  "trendingGeos": ["US"]
}
```

- **searchTerms**: keywords or Google topic IDs. Each term is one result row.
- **dataTypes**: interest over time, interest by region and related queries are on by default. Related topics is optional: in our test runs Google returned an empty related-topics list for every term, so it is off by default to save time. When the list is empty, the row says so in `warnings`.
- **compareTerms**: when on, terms are compared in groups of up to 5, exactly like typing them together on Google Trends, so values are relative across the group.
- **geo**: `US`, `GB`, `US-CA`, ... or empty for Worldwide.
- **timeRange** / **customTimeRange**: preset (past hour to 2004-present) or `2025-01-01 2025-06-30`.
- **category**, **searchProperty**: same filters as on the website (Web, Images, News, Shopping, YouTube).
- **regionResolution**: `AUTO`, `COUNTRY`, `REGION`, `DMA` (US metro areas) or `CITY`.
- **trendingGeos**: countries for the Trending Now feed.
- **proxyConfiguration**: Apify Proxy is on by default.

### Run status

Each run writes a `STATUS` record to its key-value store: number of rows, terms with data, invalid rows dropped, failed terms with the error, requests made and rate limits met. The run fails if no rows were produced, if more than 20% of rows failed validation, or if more than 20% of requested terms failed after retries. Partial results stay in the dataset either way.

### Tips

- Google Trends values are relative (0-100) within one request. Use **compareTerms** when you need terms on the same scale.
- Terms with very little search volume return `hasData: false` and a warning. This is Google's answer, not an error.
- For long keyword lists, schedule the actor and keep the default proxy.

### Limits

- Google Trends data is sampled and scaled by Google; it does not give absolute search volumes.
- Google may rate-limit heavy use. The actor retries with backoff and new proxy sessions, then reports the failure clearly.

### Is it legal?

The actor reads public Google Trends pages that anyone can open without logging in. It collects aggregated search interest, not personal data. Make sure your use complies with Google's terms and your local laws.

### Feedback

Found a bug or need a field? Open an issue on the Issues tab and we will look at it quickly.

### Pricing

Pay per result: $1.50 per 1,000 rows (one row per search term, plus one per trending search if you ask for them), plus $0.00005 per run start. No monthly rental.

#### FAQ

##### Is there an official Google Trends API?

Google offers only limited alpha access. This Actor is a practical Google Trends API alternative: send keywords, get interest over time, interest by region, related queries and Trending Now as JSON or CSV.

##### Why does pytrends keep returning 429 errors?

Google Trends rate limits unofficial clients hard. This Actor paces and retries requests and validates every row, so a run fails loudly instead of returning empty data.

##### Can I compare several keywords?

Yes. Turn on `compareTerms` to get up to 5 terms on the same 0 to 100 scale, like the Google Trends compare view.

##### Can I get Google Trends data for a country, state or US metro area?

Yes. Set `geo` (for example `US`, `US-CA` or `GB`) and interest by region returns sub-regions and US metro areas where Google provides them.

# Actor input Schema

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

Keywords to analyze (one result row per term). Leave empty if you only want trending searches.

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

If enabled, terms are compared in groups of up to 5 (like typing them together on trends.google.com), so values are relative across the group. If disabled, each term is scaled 0-100 on its own.

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

Country or region code as used by Google Trends, e.g. US, GB, DE, US-CA. Leave empty for Worldwide.

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

Preset time range. Ignored when Custom time range is set.

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

Optional. Format YYYY-MM-DD YYYY-MM-DD, e.g. 2025-01-01 2025-06-30.

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

Google Trends category ID. 0 = all categories (e.g. 71 = Food & Drink, 7 = Finance).

## `searchProperty` (type: `string`):

Which Google search to measure.

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

Which Google Trends widgets to collect for each term. Related topics is off by default: in our tests Google often returned an empty related-topics list (the row then carries a warning).

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

Granularity for Interest by region. AUTO = Google's default (countries for Worldwide, subregions for a country). CITY and DMA (US metro) are available for some countries.

## `trendingGeos` (type: `array`):

Optional. Country codes (e.g. US, GB, IN) for which to also fetch the current Trending Now searches with approximate traffic and news links. One row per trending search.

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

Interface language for names of regions and topics, e.g. en-US, de, fr.

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

Google rate-limits heavy traffic. Apify Proxy is recommended.

## `maxRetries` (type: `integer`):

On rate limits (HTTP 429) the actor backs off and switches to a fresh proxy session before retrying.

## Actor input object example

```json
{
  "searchTerms": [
    "chatgpt",
    "gemini"
  ],
  "compareTerms": false,
  "geo": "",
  "timeRange": "today 12-m",
  "category": 0,
  "searchProperty": "",
  "dataTypes": [
    "interestOverTime",
    "interestByRegion",
    "relatedQueries"
  ],
  "regionResolution": "AUTO",
  "language": "en-US",
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "maxRetries": 8
}
```

# Actor output Schema

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

One row per search term (and one per trending search, if requested).

## `overview` (type: `string`):

No description

## `status` (type: `string`):

Counts of rows, invalid rows dropped, failed terms and rate limits.

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

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

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

```

## MCP server setup

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