# Google Trends Scraper: drop-in input, no browser (`steadydata/google-trends-scraper`) Actor

Google Trends per search term: interest over time, by subregion and city, and related queries. Takes the same input fields as Apify's Google Trends Scraper and returns the same row shape, so switching means changing only the actor ID. No browser, so no page timeouts. Pay per term.

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

## Pricing

from $1.63 / 1,000 search term delivereds

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: drop-in input, no browser

Google Trends per search term: interest over time, by subregion and city, and related queries. Takes the same input fields as Apify's Google Trends Scraper and returns the same row shape, so switching means changing only the actor ID. No browser, so no page timeouts. Pay per term.

### Why this scraper

- **Drop-in for existing tasks and integrations.** The input fields are `searchTerms`, `isMultiple`, `timeRange`, `customTimeRange`, `geo`, `category`, `viewedFrom`, `startUrls` and `maxItems`, and each row carries `interestOverTime_timelineData`, `interestBySubregion`, `interestByCity`, `relatedQueries_top`, `relatedQueries_rising`, `relatedTopics_top` and `relatedTopics_rising` in Google's own format. A schedule, a Make or Zapier step or a script that reads those fields keeps working when you point it at `steadydata/google-trends-scraper`.
- **No browser.** The data comes from the same JSON endpoints the Google Trends page itself calls, over a fresh proxy session per term. There is no page to load, so there is no page-load timeout to hit.
- **A failed block never fails the row.** If one block (say, cities) cannot be fetched, the row still arrives with the rest and `notes` says which block is missing and why, instead of leaving a silent empty list.
- **You only pay for delivered terms.** A term Google has no data for comes back as a free error row with a reason.

### Who this is for

- Teams whose Google Trends schedule, task or integration is built on the field names above and who want it to keep running.
- Marketers, SEO and content teams tracking interest in topics, brands or products over time and by place.
- Analysts and AI agents that need Google Trends as structured JSON without running a browser.

### Who this is not for

**Read this before you buy.** Google Trends values are relative: 100 is the peak within the chosen term, place and period, never a search volume. If you need absolute monthly search volumes, this is the wrong tool. **Related topics are not delivered:** Google only serves them to its own Trends page after a reCAPTCHA check, and to every other request it returns an empty list (measured on 24 popular terms on 03-10-2026 and traced on 05-10-2026). This actor does not get around that check, so `relatedTopics_top` and `relatedTopics_rising` stay empty with a note. Related queries do come in full. If your workflow depends on related topics, this actor does not cover it. The spreadsheet input of the other actor (`spreadsheetId`) is accepted but not read: paste the terms into `searchTerms`.

### Input fields

| Field | Type | Required or default | What it does |
|---|---|---|---|
| `searchTerms` | list of text |  | One row per search term. With 'Compare terms' switched on, a comma-separated entry such as 'tea, coffee' is compared in one chart. Max 200 per run. |
| `isMultiple` | true/false | false | Treat a comma-separated entry as up to five terms compared in one chart, like the comparison on the Google Trends site. |
| `timeRange` | text (, 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) |  | Period of the interest-over-time series. Empty means the past 12 months. |
| `customTimeRange` | text |  | Overrides the time range. Format 'YYYY-MM-DD YYYY-MM-DD', for example '2024-01-01 2024-12-31'. |
| `geo` | text |  | Two-letter country code such as US, NL or DE, or a region code such as US-CA. Empty for worldwide. Inside a country you also get interest by subregion and by city. |
| `category` | text |  | Google Trends category ID, for example 3 for Arts & Entertainment or 47 for Autos & Vehicles. Empty for all categories. |
| `viewedFrom` | text |  | Language code for Google's formatted labels, for example en-US or de. Empty for English. |
| `startUrls` | list of text |  | Paste explore URLs from trends.google.com; the term, country, period and category are read from the URL. |
| `maxItems` | number | 0 | Stop after this many search terms and URLs together. 0 means no limit (max 200 per run). |
| `spreadsheetId` | text |  | Accepted for compatibility and ignored: paste the terms into 'Search terms' instead. |
| `skipDebugScreen` | true/false |  | Accepted for compatibility; this actor uses no browser. |
| `maxConcurrency` | number |  | Accepted for compatibility; concurrency is managed by the actor. |
| `maxRequestRetries` | number |  | Accepted for compatibility; every term gets three proxy sessions. |
| `pageLoadTimeoutSecs` | number |  | Accepted for compatibility; this actor loads no pages. |

### Input example

```json
{
  "searchTerms": ["web scraping", "electric bike"],
  "timeRange": "today 3-m",
  "geo": "US"
}
```

Comparing terms in one chart, or starting from a Google Trends URL:

```json
{
  "searchTerms": ["tea, coffee"],
  "isMultiple": true,
  "startUrls": [{"url": "https://trends.google.com/trends/explore?q=bike&geo=NL&date=today%201-m"}]
}
```

### Output example

| Field | Type | What it holds | Example |
|---|---|---|---|
| `inputUrlOrTerm` | text | The search term or Google Trends URL exactly as it was given in the input. | `web scraping` |
| `searchTerm` | text | The term that was measured; with 'Compare terms' the comma-separated list. | `web scraping` |
| `geo` | text | Country or region code the interest was measured in, or 'worldwide'. | `US` |
| `timeRange` | text | The period in Google's own notation, for example 'today 3-m' or '2024-01-01 2024-12-31'. | `today 3-m` |
| `category` | number | Google Trends category ID; 0 means all categories. | `0` |
| `interestOverTime_timelineData` | list | The graph as data, in Google's own format: time (Unix seconds), formattedTime, value (0 to 100, one per compared term), hasData. | `[{"time": "1783036800", "formattedTime": "Jul 3, 2026", "...` |
| `interestOverTime_averages` | list | Average per compared term; Google only returns it when terms are compared. |  |
| `interestBy` | list | Worldwide: score per country, highest is 100. |  |
| `interestBySubregion` | list | Inside a country: score per state or province. | `[{"geoCode": "US-MD", "geoName": "Maryland", "value": [10...` |
| `interestByCity` | list | Inside a country or region: score per city. |  |
| `relatedTopics_top` | list | Topics most searched together with the term. |  |
| `relatedTopics_rising` | list | Topics whose search together with the term grew fastest. |  |
| `relatedQueries_top` | list | Searches most made together with the term. | `[{"query": "web scraping api", "value": 100, "formattedVa...` |
| `relatedQueries_rising` | list | Searches that grew fastest, with their growth. |  |
| `notes` | list | Why a block is empty, when it is: Google returned nothing for it, or the block could not be fetched. |  |

One row per term (lists shortened; a real row for this term held 93 time points, 51 states, 200 cities, 25 top and 14 rising related queries):

```json
{
  "inputUrlOrTerm": "web scraping",
  "searchTerm": "web scraping",
  "status": "ok",
  "geo": "US",
  "timeRange": "today 3-m",
  "category": 0,
  "interestOverTime_timelineData": [
    {"time": "1783036800", "formattedTime": "Jul 3, 2026", "formattedAxisTime": "Jul 3",
     "value": [77], "hasData": [true], "formattedValue": ["77"]}
  ],
  "interestOverTime_averages": [],
  "interestBy": [],
  "interestBySubregion": [
    {"geoCode": "US-MD", "geoName": "Maryland", "value": [100], "formattedValue": ["100"],
     "maxValueIndex": 0, "hasData": [true]}
  ],
  "interestByCity": [],
  "relatedTopics_top": [],
  "relatedTopics_rising": [],
  "relatedQueries_top": [
    {"query": "web scraping api", "value": 100, "formattedValue": "100", "hasData": true,
     "link": "/trends/explore?q=web+scraping+api&date=today+3-m&geo=US"}
  ],
  "relatedQueries_rising": [],
  "notes": ["relatedTopics: Google returned an empty list for this term"]
}
```

Which regional block is filled depends on `geo`: worldwide gives `interestBy` (per country); inside a country you get `interestBySubregion` and `interestByCity`; inside a region such as `US-CA` you get `interestByCity`.

### Related actors from steadydata

- [google-trends-compare](https://apify.com/steadydata/google-trends-compare): up to five keywords on one scale
- [google-trends-regions](https://apify.com/steadydata/google-trends-regions): one keyword's map by country or region, ranked
- [google-trending-searches](https://apify.com/steadydata/google-trending-searches): what is trending right now per country

### Pricing

Pay per event: one `trend-fetched` event per delivered term, a flat price that includes every block of the row. No charge for terms Google has no data for, and no separate platform-usage surcharge.

**Free Apify plan:** this actor delivers up to 25 rows per run for accounts on the Apify free plan, and then stops with a message. That limit is set by us, not by Apify. Any paid Apify plan runs it at full size, billed per delivered row, with failed rows never charged.

**Reviews:** if this actor saves you time, a short review on this page is the one thing that helps most.

### FAQ

**Do I have to change my input to switch?** No. The same field names are accepted, including the ones that only made sense for a browser (`maxConcurrency`, `maxRequestRetries`, `pageLoadTimeoutSecs`, `skipDebugScreen`); those are ignored.

**Is the output really the same?** The blocks carry the same names and Google's own format inside them. Each row also has `status`, `geo`, `timeRange`, `category` and `notes`, which you can ignore.

**How do I compare terms?** Switch on `isMultiple` and put up to five terms comma-separated in one entry. Related topics and queries are per term, so run the terms separately when you need those.

**Why is a block empty?** Read `notes` on the row. Related queries are missing for terms with little volume, related topics are currently empty for every term (see above), and averages only come when terms are compared.

# Changelog

This Actor's version history is a separate document: https://apify.com/steadydata/google-trends-scraper/changelog.md

# Actor input Schema

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

One row per search term. With 'Compare terms' switched on, a comma-separated entry such as 'tea, coffee' is compared in one chart. Max 200 per run.

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

Treat a comma-separated entry as up to five terms compared in one chart, like the comparison on the Google Trends site.

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

Period of the interest-over-time series. Empty means the past 12 months.

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

Overrides the time range. Format 'YYYY-MM-DD YYYY-MM-DD', for example '2024-01-01 2024-12-31'.

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

Two-letter country code such as US, NL or DE, or a region code such as US-CA. Empty for worldwide. Inside a country you also get interest by subregion and by city.

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

Google Trends category ID, for example 3 for Arts & Entertainment or 47 for Autos & Vehicles. Empty for all categories.

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

Language code for Google's formatted labels, for example en-US or de. Empty for English.

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

Paste explore URLs from trends.google.com; the term, country, period and category are read from the URL.

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

Stop after this many search terms and URLs together. 0 means no limit (max 200 per run).

## `spreadsheetId` (type: `string`):

Accepted for compatibility and ignored: paste the terms into 'Search terms' instead.

## `skipDebugScreen` (type: `boolean`):

Accepted for compatibility; this actor uses no browser.

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

Accepted for compatibility; concurrency is managed by the actor.

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

Accepted for compatibility; every term gets three proxy sessions.

## `pageLoadTimeoutSecs` (type: `integer`):

Accepted for compatibility; this actor loads no pages.

## Actor input object example

```json
{
  "searchTerms": [
    "web scraping"
  ],
  "isMultiple": false,
  "timeRange": "",
  "geo": "",
  "category": "",
  "viewedFrom": "",
  "maxItems": 0
}
```

# Actor output Schema

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

No description

# 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"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("steadydata/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"] }

# Run the Actor and wait for it to finish
run = client.actor("steadydata/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"
  ]
}' |
apify call steadydata/google-trends-scraper --silent --output-dataset

```

## MCP server setup

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