# Google Trends Scraper — Fast, No Browser (`tienlq/google-trends-scraper`) Actor

Google Trends API without a browser. Get interest over time, by country, region or city, related queries, and what's trending now. Compare any number of keywords on one scale. Same input as the official Google Trends Scraper, and failed terms are free.

- **URL**: https://apify.com/tienlq/google-trends-scraper.md
- **Developed by:** [Luong Quyet Tien](https://apify.com/tienlq) (community)
- **Security:** Limited permissions
- **Stats:** 3 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 search term with data

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

Get Google Trends data for any list of search terms: interest over time, interest by country, region or city, and related queries (top and rising). You can also pull what's trending right now in any country, with search volume and % increase. You get clean JSON or CSV, ready to drop into a spreadsheet, a dashboard or an AI agent.

This scraper doesn't open a browser. It calls the same JSON endpoints the Google Trends website uses, so it's fast (60 terms in about a minute with 20 parallel requests) and it doesn't hang on page loads.

### Why another Google Trends scraper?

We built this after reading the issue tracker of the most popular Google Trends actor. The same few complaints kept coming up, so we fixed them:

- **"Runs forever and returns nothing."** No browser here, so no page-load timeouts. If Google blocks a request, we retry with a fresh IP and wait a bit longer each time. After a set number of attempts we give up on that term and move on. A run always ends.
- **"One bad term killed the whole run."** Every term is handled on its own. If one fails, you get a row that says why, and the rest of the run carries on. **You're not charged for failed terms.**
- **"Interest by city is all zeros."** Google returns 0 both when interest is really low and when it has no data at all. We drop the "no data" rows, so the numbers you see are real.
- **"I can't compare more than 5 terms."** Google only lets you compare 5 terms at a time. Turn on *Compare ALL terms on one scale* and we'll put any number of terms on the same 0–100 scale (details below).

### Switching from the official Google Trends Scraper

You don't have to change your input. These fields work the same way: `searchTerms`, `isMultiple`, `timeRange`, `customTimeRange`, `geo`, `category`, `startUrls` and `maxItems`. Change the actor name in your API call, Zapier step or schedule, and that's it.

What's different:

- The output format is different (see below). If you parse the old `interestOverTime_timelineData` fields, you'll need to update that part.
- `spreadsheetId`, `viewedFrom`, `pageLoadTimeoutSecs` and `skipDebugScreen` are ignored. Without a browser there are no pages to load and no screenshots to skip. If you need Google Sheets input, open an issue and tell us.

### How to use it

**Look up a few terms one by one**

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

**Compare terms against each other (up to 5 per group)**

Turn on `isMultiple` and separate the terms with commas. Each comma-separated line is one comparison.

```json
{
  "searchTerms": ["coffee,tea", "iphone,samsung,xiaomi"],
  "isMultiple": true
}
```

**Compare more than 5 terms**

```json
{
  "searchTerms": ["pizza", "sushi", "tacos", "pho", "ramen", "burger", "kebab"],
  "compareAll": true
}
```

**City-level data for one country**

```json
{
  "searchTerms": ["bitcoin"],
  "geo": "VN",
  "regionResolution": "CITY"
}
```

**What's trending right now**

The same list you see on the *Trending now* page of Google Trends, for any country. Pick the last 4 hours, 24 hours, 48 hours or 7 days, and optionally one category.

```json
{
  "trendingNow": true,
  "geo": "VN",
  "trendingHours": "168",
  "trendingCategory": "17"
}
```

Each trend comes with its search volume (Google's bucket, so `200000` means "200K+"), % increase, when it started, whether it's still trending, its categories, related searches, and a link to open it in Google Trends. A busy country like the US has around 2,000 trends over 7 days. Worldwide isn't available on that page, so if you leave Location empty we use the United States.

You can also paste Google Trends explore URLs into `startUrls`. We read the `q=` term from the URL. Location and time come from the input fields, not from the URL.

### What you get

One item per search term. Here's a real (trimmed) result for `coffee` compared with `tea`:

```json
{
  "searchTerm": "coffee",
  "geo": "Worldwide",
  "timeRange": "today 12-m",
  "category": 0,
  "comparedWith": ["tea"],
  "interestOverTime": [
    { "date": "2025-10-05T00:00:00+00:00", "value": 61 },
    { "date": "2025-10-12T00:00:00+00:00", "value": 61 },
    { "date": "2026-10-04T00:00:00+00:00", "value": 59, "isPartial": true }
  ],
  "interestByRegion": [
    { "geoName": "Singapore", "value": 100, "geoCode": "SG" },
    { "geoName": "Australia", "value": 88, "geoCode": "AU" }
  ],
  "relatedQueries": {
    "top": [
      { "query": "coffee shop", "value": 100, "formattedValue": "100" },
      { "query": "coffee table", "value": 92, "formattedValue": "92" }
    ],
    "rising": [
      { "query": "how to remove coffee stain from carpet", "value": 8950, "formattedValue": "Breakout" },
      { "query": "how to brew pour over coffee", "value": 7800, "formattedValue": "Breakout" }
    ]
  }
}
```

**Exporting to Excel, CSV or HTML:** in the *Export* dialog, pick the **Search terms** view (or **Trending now**). You get one readable row per term with `latest`, `average`, `peak`, `peakDate`, `changePercent`, `topRegion`, `topQueries` and `risingQueries`. The default *All fields* view flattens every data point into its own column, which is great for code but hard to read in a spreadsheet.

A few notes on the fields:

- `value` in `interestOverTime` is `null` when Google has no data for that date. It's never a fake 0.
- `isPartial: true` marks the current week (or day, or hour), which isn't over yet. It will usually look lower than it ends up.
- City rows usually come without a `geoCode`, because Google doesn't give cities one. When Google sends coordinates, we include them.
- `changePercent` compares the first quarter of the period with the last quarter, so you can see at a glance whether a term is going up or down. For seasonal terms over 12 months, check `peakDate` too.
- If a term fails, its item only has `searchTerm` and `error`.

### Things worth knowing about Google Trends data

These come from Google, not from this scraper, but they trip people up:

- **There are no search volumes.** Google Trends only gives a relative index from 0 to 100, where 100 is the peak for your selection. If a tool shows you "monthly searches" from Trends, it's an estimate.
- **Regional maps don't compare across terms.** In a comparison, each term's `interestByRegion` uses its own 0–100 scale, the same as on the Google Trends website. "Singapore 100" for coffee and "Singapore 100" for tea doesn't mean the same number of searches.
- **Small places can top the list.** Trends is based on a sample. A tiny region with a handful of searches can show up high (St. Helena is a classic). We leave Google's numbers as they are rather than guess which ones to hide.
- **Numbers shift a little between runs**, for the same sampling reason. Rising queries for niche terms are especially noisy.
- **Related topics aren't returned anymore.** Google still shows the widget but sends it back empty, so we leave it out instead of giving you empty fields.

### How "compare all terms" works

Google compares at most 5 terms at once, and every comparison gets its own 0–100 scale. To join them, we use your **first term as an anchor**: it goes into every batch together with 4 other terms, and then we rescale each batch so the anchor matches its level in the first batch. That way all the numbers end up on one scale. They can go above 100, and they have decimals.

Pick a first term with medium popularity. If the anchor is tiny compared with the others, Google rounds it to 0 or 1, and the rescaling gets rough. If the anchor has no data at all in a batch, the terms in that batch come back with an `error` instead of wrong numbers.

This mode returns `interestOverTime` only, since regional maps and related queries can't be rescaled the same way.

### Time ranges

| Value | Range | One data point per |
|---|---|---|
| `now 1-H` | Past hour | minute |
| `now 4-H` | Past 4 hours | minute |
| `now 1-d` | Past day | 8 minutes |
| `now 7-d` | Past 7 days | hour |
| `today 1-m` | Past 30 days | day |
| `today 3-m` | Past 90 days | day |
| *(empty)* | Past 12 months | week |
| `today 5-y` | Past 5 years | week |
| `all` | 2004 to now | month |

For any other range, use `customTimeRange` with `YYYY-MM-DD YYYY-MM-DD`, for example `2024-01-01 2024-12-31`.

### Big runs

With the default settings (10 parallel requests), 1,000 terms take roughly 20–30 minutes. Set *Max concurrency* to 20 and it goes about twice as fast. Results are saved as each term finishes, so if a run hits its timeout you keep everything done so far. For many thousands of terms, raise the run timeout in the run options, or split the list across a few runs.

### Proxies

Google Trends blocks datacenter IPs within a few requests, so the default is Apify's residential proxy. Every term (and every retry) goes out through a different IP. You can switch to your own proxies in the *Proxy* section, but if you see lots of retries in the log, go back to residential.

### Pricing

You pay per search term that returns data, and per trending search returned. Failed terms are free. The price is shown on the Pricing tab. If you set a maximum cost per run, the scraper stops cleanly when it reaches it.

### Questions, bugs, ideas

Open an issue on the Issues tab. Please include the run ID, so we can see exactly what happened. We read every issue and usually reply within a day.

# Actor input Schema

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

Each term is scraped separately. Same field as the official Google Trends Scraper, so you can switch without changing your input.

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

If checked, "coffee,tea" is one comparison of coffee vs tea (max 5 per term, Google limit).

## `compareAll` (type: `boolean`):

Puts every search term on the same 0-100 scale using the first term as an anchor, even beyond Google's 5-term limit. Returns interest over time only. Tip: make the first term one of medium popularity.

## `trendingNow` (type: `boolean`):

Get what's trending right now in the selected Location (like the Trending now page on Google Trends): search volume, % increase, categories and related searches. Worldwide isn't available here, so it defaults to United States. Works on its own or together with Search terms.

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

How far back to look. 7 days in the US returns around 2,000 trends.

## `trendingCategory` (type: `string`):

Only return trends in this category.

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

0 = all of them.

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

Predefined time range. Default: past 12 months.

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

Overrides Time range. Format: YYYY-MM-DD YYYY-MM-DD, e.g. 2024-01-01 2024-12-31

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

Country to get Trends for. Default: Worldwide.

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

Limit results to a Google Trends category. Default: all categories.

## `includeRegions` (type: `boolean`):

Add interest by country / region / city for each term.

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

Only places where Google has data are returned (no fake zeros).

## `includeRelated` (type: `boolean`):

Add related queries and related topics (top and rising) for each term.

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

Paste explore URLs; the q= term is used. Location/time come from the fields above.

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

0 = no limit.

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

Google Trends blocks datacenter IPs quickly. Residential is recommended.

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

How many terms are fetched in parallel.

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

If Google blocks a request, retry with a new IP up to this many times.

## Actor input object example

```json
{
  "searchTerms": [
    "web scraping"
  ],
  "isMultiple": false,
  "compareAll": false,
  "trendingNow": false,
  "trendingHours": "24",
  "trendingCategory": "",
  "trendingMaxItems": 0,
  "timeRange": "",
  "geo": "",
  "category": "",
  "includeRegions": true,
  "regionResolution": "",
  "includeRelated": true,
  "maxItems": 0,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "maxConcurrency": 10,
  "maxRequestRetries": 8
}
```

# Actor output Schema

## `searchTerms` (type: `string`):

No description

## `trending` (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"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

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

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

```

## MCP server setup

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