# Google Trends Scraper — Bulk Keyword Compare (`khalilbenali/google-trends-scraper`) Actor

Compare up to 200 Google Trends keywords on one scale, with trend analysis: rising or falling, peak month, share of search. Regions and related queries.

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

## Pricing

from $1.60 / 1,000 trend 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

### What is Google Trends Scraper?

Google Trends Scraper is an unofficial Google Trends API on Apify, not affiliated with Google. It returns Google Trends data as flat, export-ready JSON: interest over time with built-in trend analysis, interest by region, related queries and the current trending searches. It calls the same JSON endpoints the Google Trends website uses, so there is no browser to maintain and runs finish in minutes.

Google's own site compares at most five keywords at a time and rescales every comparison to its own peak. This Actor lets you compare keywords in bulk: up to 200 keywords land on one common 0-100 scale in a single run.

Key features:

- **Bulk compare:** up to 200 keywords on one common scale, or each keyword on its own scale.
- **Trend analysis built in:** every interest-over-time result with enough data comes with its trend direction, change in percent and peak. With a year or more of data it also has a peak month, and with two years a year-over-year change and a seasonality index. A Compare all run adds each keyword's share of search and rank within the comparison. It is part of the same result and costs nothing extra.
- **Interest by region:** countries, states, cities or US metro areas (DMA).
- **Related queries:** the top and the rising queries for every keyword, with breakout flags.
- **Trending now:** ranked trending searches for a country, with start time, search volume and growth.
- **HTTP-only reliability:** no browser. Sessions pace their requests, replace blocked sessions and stop cleanly when Google keeps blocking.
- **Pay only for successful results:** results with status `noData`, `blocked` or `error` are free.

### What Google Trends data can you extract?

Every result is one dataset item per keyword and data type (or one per trending search).

| Record type        | What it contains                                                         | Key fields                                                                                                                                                                              |
| ------------------ | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `interestOverTime` | Search interest of a keyword over the chosen period, with trend analysis | `points` (time, value 0-100, isPartial), `averageValue`, `resolution`, `scale`, and the analysis: `trendDirection`, `changePercent`, `peakMonth`, `shareOfSearchPercent`, `compareRank` |
| `interestByRegion` | Where a keyword is most searched                                         | `regions` (geoCode, geoName, value 0-100), `resolution`                                                                                                                                 |
| `relatedQueries`   | Queries searched together with the keyword                               | `top` (query, value), `rising` (query, value, formattedValue, isBreakout)                                                                                                               |
| `trendingNow`      | What people in a country are searching for right now                     | `rank`, `term`, `startedAt`, `endedAt`, `searchVolume`, `growthPercent`, `relatedTerms`                                                                                                 |

Every item also carries `keyword`, `geo`, `timeRange`, `category`, `searchProperty`, `status`, `errorMessage` and `scrapedAt`.

### Trend analysis: answers, not just numbers

Every interest-over-time item carries analysis fields next to the time series, so you can see whether a keyword is rising, when it peaks and who wins a comparison without post-processing. Each field is filled when there is enough data for it and is `null` otherwise (the rules are below). They are flat fields, so CSV and Excel exports stay usable. They are part of the same result: no extra charge, no extra input.

All fields are computed from the values you receive in `points` (after common-scale normalisation and rounding), and only from complete points, the ones with `isPartial` false. The running period is left out because its value can still change. Below, *n* is the number of complete points. When `status` is not `ok`, every analysis field is `null`.

| Field                       | The question it answers             | Exact definition                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| --------------------------- | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `peakValue`, `peakTime`     | How high did interest go, and when? | The highest value among the complete points, and the start time (ISO 8601) of its first occurrence. `null` when every complete point is 0, because then there is no peak.                                                                                                                                                                                                                                                                                                                                                                                                               |
| `recentAverage`             | Where is interest now?              | Average of the last quarter of the complete points: the last floor(*n* / 4) points, rounded to 2 decimals. `null` with fewer than 8 complete points.                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `changePercent`             | How much did interest change?       | (recent average − first-quarter average) ÷ first-quarter average × 100, rounded to 1 decimal. The first quarter is the first floor(*n* / 4) complete points. `null` with fewer than 8 complete points or when the first-quarter average is 0.                                                                                                                                                                                                                                                                                                                                           |
| `trendDirection`            | Is it rising, falling or flat?      | `rising` if `changePercent` is above +15, `falling` if it is below −15, otherwise `stable` (exactly +15 and −15 are `stable`). If the first-quarter average is 0: `rising` when `recentAverage` is above 0, otherwise `stable`. `null` with fewer than 8 complete points.                                                                                                                                                                                                                                                                                                               |
| `yearOverYearChangePercent` | Is it higher than a year ago?       | Average of the complete points in the last 52 weeks (364 days) against the average of the 52 weeks before, counted back from the last complete point: recent ÷ earlier × 100 − 100, rounded to 1 decimal. Weekly data puts 52 points in each window, monthly data 12. Needs complete points that span at least two years (728 days), so use `today 5-y` or `all`. `null` otherwise, or when the earlier average is 0.                                                                                                                                                                   |
| `peakMonth`                 | In which month is interest highest? | The English month name (`January` to `December`) whose complete points have the highest average value, grouped by UTC calendar month. Needs the complete points to cover at least 12 distinct calendar months (every month from January to December, in any year, so the default 12 months of weekly data are enough) and resolution `DAY`, `WEEK` or `MONTH`, otherwise `null`. A tie goes to the earliest month of the year. `null` as well when every month has the same average (a flat series, for example a keyword stuck at 1, or all zeros), because then no month is the peak. |
| `seasonalityIndex`          | How seasonal is it?                 | (highest monthly average − lowest monthly average) ÷ overall average, rounded to 2 decimals. 0 = flat all year; higher = stronger seasonal swing. Needs a span of at least two years (728 days) and resolution `DAY`, `WEEK` or `MONTH`. `null` otherwise, or when the overall average is 0.                                                                                                                                                                                                                                                                                            |
| `shareOfSearchPercent`      | Who has the biggest share?          | The keyword's sum of complete-point values ÷ the sum over all successful keywords of the comparison × 100, rounded to 1 decimal. The shares of a comparison add up to about 100. Only with **Compare all** (`scale` is `common`), otherwise `null`. Also `null` when the comparison did not finish, when any keyword of it ended `blocked` or `error`, or when the total is 0 (see Good to know).                                                                                                                                                                                       |
| `compareRank`               | Who is number one?                  | 1 = the biggest `shareOfSearchPercent` (the highest sum of complete-point values) among the successful keywords of the comparison, so the ranks always follow the shares. Keywords with exactly the same sum share a rank (1, 1, 3). Only with **Compare all**, otherwise `null`, and `null` in the same cases as `shareOfSearchPercent`. It is not the Trending now `rank`.                                                                                                                                                                                                            |

Good to know:

- Only keywords with status `ok` take part in shares and ranks, and keywords that return `noData`, `blocked` or `error` have `null` for both. A keyword with `noData` is simply left out of the comparison. But if any keyword of the comparison ends `blocked` or `error`, `shareOfSearchPercent` and `compareRank` are `null` for every keyword of that comparison: shares re-based over the survivors would look like a complete ranking when it is not. The trend analysis of each successful keyword is still filled. Run the comparison again later to get shares and ranks.
- Share and rank are computed once every keyword of the comparison is finished. A run that was migrated and resumed returns the same numbers as an uninterrupted run. If you stop a Compare all run early, `shareOfSearchPercent` and `compareRank` stay `null`, because the comparison is incomplete. If instead your maximum cost per run stops the saving of results, the shares still refer to the full comparison, so the saved ones add up to less than 100.
- The default time range (12 months of weekly data) covers every calendar month, so it has a `peakMonth`. It spans only about 51 weeks, which is too short for `yearOverYearChangePercent` and `seasonalityIndex`, which need two years. Use `today 5-y` or `all` for those.

#### Example: which drink is rising, and who wins?

Compare five drinks on one scale over five years in the United States:

```json
{
    "keywords": ["coffee", "tea", "matcha", "espresso", "cold brew"],
    "compareMode": "compareAll",
    "dataTypes": ["interestOverTime"],
    "geo": "US",
    "timeRange": "today 5-y"
}
```

Real data from a run on 10 October 2026, analysed with this version: the item for `matcha`, with `points` trimmed to two of the 261 weekly points. Google Trends values move over time, so a new run shows slightly different numbers.

```json
{
    "recordType": "interestOverTime",
    "keyword": "matcha",
    "geo": "US",
    "timeRange": "today 5-y",
    "category": 0,
    "searchProperty": "web",
    "status": "ok",
    "errorMessage": null,
    "scale": "common",
    "scrapedAt": "2026-10-10T14:13:10.395Z",
    "resolution": "WEEK",
    "points": [
        {
            "time": "2021-10-10T00:00:00.000Z",
            "timestamp": 1633824000,
            "formattedTime": "Oct 10 – 16, 2021",
            "value": 1,
            "isPartial": false
        },
        {
            "time": "2021-10-17T00:00:00.000Z",
            "timestamp": 1634428800,
            "formattedTime": "Oct 17 – 23, 2021",
            "value": 1,
            "isPartial": false
        }
    ],
    "averageValue": 3.58,
    "peakValue": 8,
    "peakTime": "2026-04-05T00:00:00.000Z",
    "recentAverage": 6.14,
    "changePercent": 238.1,
    "trendDirection": "rising",
    "yearOverYearChangePercent": 24.4,
    "peakMonth": "June",
    "seasonalityIndex": 0.51,
    "shareOfSearchPercent": 3.5,
    "compareRank": 4
}
```

The results of the whole run, side by side:

| keyword   | averageValue | trendDirection | changePercent | yearOverYearChangePercent | shareOfSearchPercent | compareRank | peakMonth | seasonalityIndex |
| --------- | ------------ | -------------- | ------------- | ------------------------- | -------------------- | ----------- | --------- | ---------------- |
| coffee    | 58.58        | rising         | 50.4          | 30.1                      | 57.4                 | 1           | May       | 0.14             |
| tea       | 32.13        | rising         | 20.9          | 12.1                      | 31.5                 | 2           | December  | 0.14             |
| espresso  | 6.23         | rising         | 99.3          | 36.6                      | 6.1                  | 3           | December  | 0.45             |
| matcha    | 3.58         | rising         | 238.1         | 24.4                      | 3.5                  | 4           | June      | 0.51             |
| cold brew | 1.47         | rising         | 50.6          | 49.3                      | 1.4                  | 5           | June      | 0.80             |

How to read it: coffee leads with 57.4% of the search interest of the five drinks, and tea follows with 31.5%. Matcha has only a 3.5% share, but it grew the most: its average over the last quarter of the five years is 238% above the first quarter. Cold brew is the most seasonal (index 0.80, peaking in June), while coffee and tea are steady all year (0.14). The shares add up to about 100 (rounding), and the ranks follow the shares. Over long ranges Google sometimes changes how it collects data, which it marks on its own charts, so compare keywords with each other rather than reading a single change in isolation.

### How to scrape Google Trends

1. Open the Actor in Apify Console and go to the **Input** tab.
2. Add your keywords, one per line. Terms and Google topic IDs (for example `/m/0dl5d`) both work.
3. Under **What to collect**, choose interest over time, interest by region and/or related queries. Set **Compare mode** to compare all keywords on one scale.
4. Under **Location, time and filters**, pick a region, a time range, a category and a search property (web, YouTube, news, images or Google Shopping).
5. Click **Start**. When the run finishes, open the **Output** tab to view the results or export them as JSON, CSV or Excel.

To list trending searches instead, set **Mode** to Trending now.

### How much does it cost to scrape Google Trends?

The Actor uses pay-per-event pricing. At current prices:

- **Run start:** $0.003 per run. Apify charges the run start once per GB of memory, minimum one; the default 256 MB counts as one, and the Actor never needs more.
- **Trend result:** $0.002 for every successful keyword and data type result.
- **Trending search:** $0.0005 for every trending search saved.

Prices are lower on higher Apify plans. They may change, and the Pricing tab of this page is always the authoritative source.

Worked examples (plus the $0.003 run start):

| Run                                             | Billable results | Approximate cost |
| ----------------------------------------------- | ---------------- | ---------------- |
| 100 keywords, interest over time                | 100              | $0.20            |
| 50 keywords, all three data types (150 results) | 150              | $0.30            |
| Trending now, top 100 searches                  | 100              | $0.05            |

Results with status `noData`, `blocked` or `error` are saved with an explanation and are never charged. If you set a maximum cost per run, the Actor stops cleanly when it is reached and keeps what it saved.

### Input

The input form has five groups. Everything has a default, so you can start a run without changing anything: the default compares coffee and tea worldwide over the last 12 months.

- **Keywords:** `mode` (`keywords` or `trendingNow`) and `keywords`, up to 200 per run. Duplicates and empty lines are ignored.
- **What to collect:** `dataTypes`, `regionResolution` (`COUNTRY` for worldwide, `REGION`, `CITY` or `DMA` for a country), `compareMode` (`separate` or `compareAll`) and `anchorKeyword`.
- **Location, time and filters:** `geo` (`US`, `FR`, `US-CA`, or empty for worldwide), `timeRange` (past hour to 5 years, `all` or `custom`), `customTimeRange` (`2025-01-01 2025-06-30`), `category` (0 = all, 20 = Sports, 174 = Science) and `searchProperty`.
- **Trending now:** `trendingGeo`, `trendingHours` (`"4"`, `"24"`, `"48"` or `"168"`) and `trendingMaxItems`.
- **Advanced:** `language`, `timezoneOffsetMinutes` and `maxConcurrency` (1 to 5 parallel sessions, default 2).

If Google rejects a region detail for a country, the Actor uses Google's default breakdown and logs a warning.

#### Example: keywords with regions and related queries

```json
{
    "mode": "keywords",
    "keywords": ["coffee", "tea"],
    "dataTypes": ["interestOverTime", "interestByRegion", "relatedQueries"],
    "compareMode": "separate",
    "geo": "US",
    "timeRange": "today 12-m"
}
```

#### Example: compare seven keywords on one scale

```json
{
    "keywords": ["coffee", "tea", "espresso", "latte", "cappuccino", "matcha", "cold brew"],
    "compareMode": "compareAll",
    "anchorKeyword": "coffee",
    "dataTypes": ["interestOverTime"]
}
```

#### Example: trending searches

```json
{ "mode": "trendingNow", "trendingGeo": "US", "trendingHours": "24", "trendingMaxItems": 100 }
```

### Output

Results are available in the dataset as JSON, CSV, Excel, XML and more. The dataset has views for an overview, interest over time, interest by region, related queries and trending searches. Example interest-over-time item for one keyword on its own scale over 12 months (values are illustrative):

```json
{
    "recordType": "interestOverTime",
    "keyword": "coffee",
    "geo": "US",
    "timeRange": "today 12-m",
    "category": 0,
    "searchProperty": "web",
    "status": "ok",
    "errorMessage": null,
    "scale": "perKeyword",
    "scrapedAt": "2026-10-10T12:00:00.000Z",
    "resolution": "WEEK",
    "points": [
        {
            "time": "2025-10-05T00:00:00.000Z",
            "timestamp": 1759622400,
            "formattedTime": "Oct 5 – 11, 2025",
            "value": 78,
            "isPartial": false
        }
    ],
    "averageValue": 81.4,
    "peakValue": 100,
    "peakTime": "2025-12-14T00:00:00.000Z",
    "recentAverage": 86.1,
    "changePercent": 7.4,
    "trendDirection": "stable",
    "yearOverYearChangePercent": null,
    "peakMonth": "December",
    "seasonalityIndex": null,
    "shareOfSearchPercent": null,
    "compareRank": null
}
```

In this example `yearOverYearChangePercent` and `seasonalityIndex` are `null` because 12 months of data are too short for them (they need two years), and `shareOfSearchPercent` and `compareRank` are `null` because the keyword is not part of a Compare all comparison. See the trend analysis section above for every field.

| Field                          | Meaning                                                                                                                                                                                                                |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `status`                       | `ok`, `noData` (too little search volume), `blocked` (Google blocked the run, not scraped) or `error`. Only `ok` is charged.                                                                                           |
| `errorMessage`                 | Explains any status other than `ok`; `null` otherwise.                                                                                                                                                                 |
| `scale`                        | `perKeyword`: values are relative to the keyword's own peak. `common`: one scale shared by all keywords of the run.                                                                                                    |
| `value` (points, regions, top) | Google's relative index from 0 to 100, never an absolute search count. Decimals appear when more than five keywords are normalised across batches.                                                                     |
| `isPartial`                    | The period is not finished yet, so its value can still change.                                                                                                                                                         |
| analysis fields                | `peakValue` to `compareRank`, interest over time only. `null` means there is not enough data, no peak, or no finished comparison, never zero. The trend analysis section has the exact definitions and the null rules. |
| `rising.value`                 | Growth in percent. `isBreakout` is true when the growth exceeds 5000%.                                                                                                                                                 |
| `searchVolume`                 | Trending now only: Google's rounded approximate number of searches.                                                                                                                                                    |
| `endedAt`, `isActive`          | Trending now only: `endedAt` is `null` and `isActive` is true while the search is still trending.                                                                                                                      |

Region and related-query values are always relative to the keyword's own peak (`scale` is `perKeyword`), even in Compare all mode.

### Use this unofficial Google Trends API from your code

Every Actor run is available through the Apify API. Replace `<YOUR_APIFY_TOKEN>` with your own API token.

#### JavaScript

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('Khalilbenali/google-trends-scraper').call({
    keywords: ['coffee', 'tea'],
    dataTypes: ['interestOverTime'],
    geo: 'US',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("Khalilbenali/google-trends-scraper").call(
    run_input={"keywords": ["coffee", "tea"], "dataTypes": ["interestOverTime"], "geo": "US"}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

#### cURL

```bash
curl -X POST "https://api.apify.com/v2/acts/Khalilbenali~google-trends-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"keywords": ["coffee", "tea"], "dataTypes": ["interestOverTime"], "geo": "US"}'
```

The synchronous endpoint returns the dataset items directly and suits short runs. For larger runs start the Actor asynchronously and read the dataset when it finishes.

#### Integrations

Connect the Actor to Make, Zapier, n8n or Google Sheets, or call a webhook when a run finishes, using the Apify integrations. AI agents can run it through the [Apify MCP server](https://mcp.apify.com): the flat output and the `status` field are easy for a model to read.

### Use cases

- **SEO and keyword research:** compare keywords on one scale, rank them by share of search and find rising queries before you write.
- **Content calendars:** with a year or more of data, see in which month (`peakMonth`) interest in a topic peaks and plan around it.
- **Trend monitoring:** schedule a run and use `trendDirection` and `changePercent` to spot keywords that are rising or falling, without post-processing.
- **Market and brand research:** compare brands, products or topics by country, state or city, and by search property such as YouTube or Google Shopping.
- **Product and seasonality planning:** use five years of weekly data or the full history since 2004 to time launches and stock.
- **AI agents and automation:** feed Google Trends data and trending searches into reports, alerts and agent workflows.

### How the bulk comparison works

Google rescales every comparison so that its own highest point is 100, so two separate comparisons cannot be put side by side. With **Compare all** the Actor solves this for up to 200 keywords:

1. Up to five keywords are compared by Google in a single request. They are already on one scale.
2. With more than five keywords the Actor builds batches of one **anchor keyword** plus up to four new keywords. Every batch uses the same region, time range and filters.
3. The anchor appears in every batch. The reference batch is the first batch where the anchor has a usable timeline with search volume (normally the first). Every other batch is multiplied by the sum of the anchor's values in the reference batch divided by the sum of the anchor's values in that batch.
4. Finally everything is rescaled so the highest value across your keywords is 100, and values are rounded to two decimals. That is why values can have decimals when you compare more than five keywords.

Choose an anchor with steady, medium-to-high interest. Without `anchorKeyword` the first keyword is used. An anchor that is not in your keyword list is used for scaling only: it gets no result and is not charged. If the anchor has no measurable volume in a batch, that batch's keywords get status `noData` with a message suggesting a stronger anchor. If one batch fails, only its keywords are affected.

In our offline test, a keyword measured through an anchor matched a direct five-keyword comparison within about 0.25 index points on average. Keywords far below the strongest keyword register only as 0 or 1 on a common scale.

### FAQ

#### How many keywords can I compare?

Up to 200 per run. Google compares five at a time, so larger lists are linked through the anchor keyword as described above. A run with 100 keywords and interest over time takes roughly 5 to 6 minutes with the default two sessions, and Google rate limiting can add time.

#### How is this different from the official Google Trends website?

The numbers come from the same endpoints the website uses. The Actor adds what the website lacks: bulk comparison of up to 200 keywords on one scale, flat JSON, CSV and Excel output, an API, scheduling, and Trending now as a dataset. The website is interactive and compares five terms at a time. Values on a common scale across more than five keywords are estimates built with the anchor method. This Actor is not affiliated with or endorsed by Google.

#### Do the analysis fields cost extra?

No. The analysis fields are part of the same interest-over-time result, so there is no extra event, no extra input and no change in price. Results with status `noData`, `blocked` or `error` are still free, and their analysis fields are `null`.

#### Why are some analysis fields null?

`null` means the data to compute a field is not there, never zero. `trendDirection`, `changePercent` and `recentAverage` need at least 8 complete points. `peakValue` and `peakTime` are `null` when every complete point is 0. `peakMonth` needs data that covers all 12 calendar months, which the default 12 months of weekly data do, but a shorter range or an hourly range does not, and it is `null` for a flat series where every month has the same average. `yearOverYearChangePercent` and `seasonalityIndex` need two years (728 days), so use `today 5-y` or `all` for them. `shareOfSearchPercent` and `compareRank` need **Compare all** and a comparison that finished with no keyword `blocked` or `error` and some search volume. Every analysis field is `null` when `status` is not `ok`.

#### Can I schedule it?

Yes. Use Apify Schedules to run it hourly, daily or weekly, for example to track Trending now for a country or a fixed list of keywords. Each scheduled run is charged like any other run.

#### What does status "blocked" mean?

Google rate-limited or blocked the sessions of this run, so the keyword was not scraped. The result is free. Run it again later, or lower the number of parallel sessions. The Actor never attempts to solve CAPTCHAs or evade checks.

#### What does status "noData" mean?

Google has no data for the keyword with your filters because its search volume is too low. It also appears for keywords that are too small to register next to the others on a common scale.

#### Is it legal to scrape Google Trends?

The Actor reads public, aggregated, anonymous search-interest data. It collects no personal data, uses no login or cookies from user accounts, and does not fetch the Google Trends web pages that robots.txt excludes. You remain responsible for using the data in line with Google's terms and the laws that apply to you.

#### What happens if the platform migrates or restarts my run?

The run saves its progress after every finished keyword batch. After a migration it resumes where it stopped: finished results are not fetched, saved or charged again. When you compare more than five keywords, the finished batches are kept so the common scale is completed without repeating them. The trend analysis, share of search and rank are calculated from the final values once the comparison is complete, so a resumed run returns the same numbers as an uninterrupted one.

#### Can I get related topics?

Not in this version. Google currently returns empty related-topic lists, so only related queries are offered.

#### What are the limits?

- Values are Google's rounded 0-100 index, not search counts, and recent periods are marked `isPartial`.
- Trending now results link no news articles except in the RSS fallback, which lists about 10 items.
- The analysis fields describe Google's relative index, not search counts. Percent changes are only as precise as that index, and keywords with low interest can swing a lot.
- Data starts in 2004, and Google decides the time resolution for the chosen range.
- Google can change its internal endpoints at any time. Report problems through the Issues tab.

### Changelog

- **1.1 (2026-10-10):** trend analysis fields on every interest-over-time result: peak value and time, recent average, change in percent, trend direction, year-over-year change, peak month and seasonality, plus share of search and compare rank when you compare keywords. Free, with no change in price or input.
- **1.0 (2026-10-10):** first release with interest over time, regions, related queries, Trending now, bulk compare of up to 200 keywords with anchor normalisation, migration-safe resume and pay-per-result pricing.

# Actor input Schema

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

Keywords collects data for the keywords below. Trending now lists what people are searching for right now in one country (set it in the Trending now section). Example: choose Trending now to get today's top searches in the US.

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

Search terms or Google topic IDs, one per line. Up to 200 per run. Whitespace is trimmed, and duplicates and empty lines are ignored. Used in Keywords mode. Example: coffee, iced tea, /m/0dl5d (a topic ID).

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

Interest over time returns the timeline, interest by region the breakdown by country, state or city, and related queries the top and rising searches. Each keyword and data type is one result. Example: select all three to get 3 results per keyword.

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

Level of detail for Interest by region. Country is for worldwide searches. Region (states), City and DMA (US metro areas) work for a country such as US. If Google rejects a combination, the Actor uses Google's default breakdown for that region instead and logs a warning. Example: set Region to US and this to City to get the top US cities.

## `compareMode` (type: `string`):

Separate: every keyword gets its own 0-100 scale (its own peak is 100). Compare all: every keyword is placed on one common scale. Up to 5 keywords use a single Google comparison; more than 5 are linked through an anchor keyword. Example: with coffee and tea on Compare all, the more searched keyword peaks at 100 and the other shows its lower values on the same scale.

## `anchorKeyword` (type: `string`):

Only used with Compare all and more than 5 keywords. This keyword is included in every batch to link the batches onto one scale. Pick a keyword with steady, mid-to-high interest. Leave empty to use the first keyword. Example: coffee.

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

Region code: US, GB, FR, DE... or a sub-region such as US-CA. Leave empty for worldwide. Example: FR for France, US-CA for California.

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

The period to analyse. Shorter ranges give finer resolution (minutes or hours up to 7 days, days up to 3 months, weeks up to 5 years). Choose Custom range to set exact dates. Example: Past 30 days for a recent trend, 2004 - present for the long view.

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

Used only when Time range is Custom range. Format: start and end date separated by a space, YYYY-MM-DD YYYY-MM-DD, for example 2025-01-01 2025-06-30. Data starts in 2004 and the end date cannot be in the future.

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

Google Trends category ID. 0 means all categories. Examples: 0 = all categories, 3 = Arts and entertainment, 7 = Finance, 20 = Sports, 71 = Food and drink, 174 = Science.

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

Which Google search to analyse. Example: choose YouTube search to see what people look up on YouTube instead of Google web search.

## `trendingGeo` (type: `string`):

Country code for Trending now mode. Example: US, GB or FR.

## `trendingHours` (type: `string`):

How far back Trending now looks: 4, 24, 48 or 168 hours (7 days). Example: 24 for the last day's trending searches.

## `trendingMaxItems` (type: `integer`):

Maximum number of trending searches to save, highest ranked first. Example: 100 saves the top 100.

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

Interface language code, for example en-US, fr or de. It affects labels and related query wording, not the underlying numbers.

## `timezoneOffsetMinutes` (type: `integer`):

Offset from UTC in minutes, as returned by JavaScript's getTimezoneOffset (UTC-5 is 300, UTC+1 is -60). It only matters for hourly and minute data.

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

How many sessions run in parallel, each with its own cookies and (on the Apify platform) its own proxy session. Every session waits at least two seconds between requests. 1 to 5. Example: 2 (the default) is a good balance of speed and politeness.

## Actor input object example

```json
{
  "mode": "keywords",
  "keywords": [
    "coffee",
    "tea"
  ],
  "dataTypes": [
    "interestOverTime"
  ],
  "regionResolution": "COUNTRY",
  "compareMode": "separate",
  "anchorKeyword": "",
  "geo": "",
  "timeRange": "today 12-m",
  "customTimeRange": "2025-01-01 2025-06-30",
  "category": 0,
  "searchProperty": "web",
  "trendingGeo": "US",
  "trendingHours": "24",
  "trendingMaxItems": 100,
  "language": "en-US",
  "timezoneOffsetMinutes": 0,
  "maxConcurrency": 2
}
```

# Actor output Schema

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

All results, one item per keyword and data type (or per trending search).

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

Timelines per keyword.

## `trendingNow` (type: `string`):

Ranked trending searches (Trending now mode).

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

One row per keyword and region.

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

Rising related queries per keyword.

# 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": [
        "coffee",
        "tea"
    ],
    "dataTypes": [
        "interestOverTime"
    ],
    "anchorKeyword": "",
    "customTimeRange": "2025-01-01 2025-06-30",
    "category": 0,
    "trendingGeo": "US",
    "trendingMaxItems": 100,
    "language": "en-US",
    "timezoneOffsetMinutes": 0,
    "maxConcurrency": 2
};

// Run the Actor and wait for it to finish
const run = await client.actor("khalilbenali/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": [
        "coffee",
        "tea",
    ],
    "dataTypes": ["interestOverTime"],
    "anchorKeyword": "",
    "customTimeRange": "2025-01-01 2025-06-30",
    "category": 0,
    "trendingGeo": "US",
    "trendingMaxItems": 100,
    "language": "en-US",
    "timezoneOffsetMinutes": 0,
    "maxConcurrency": 2,
}

# Run the Actor and wait for it to finish
run = client.actor("khalilbenali/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": [
    "coffee",
    "tea"
  ],
  "dataTypes": [
    "interestOverTime"
  ],
  "anchorKeyword": "",
  "customTimeRange": "2025-01-01 2025-06-30",
  "category": 0,
  "trendingGeo": "US",
  "trendingMaxItems": 100,
  "language": "en-US",
  "timezoneOffsetMinutes": 0,
  "maxConcurrency": 2
}' |
apify call khalilbenali/google-trends-scraper --silent --output-dataset

```

## MCP server setup

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