# Google Trends Scraper — Reliable, With Rising Queries (`dottti/google-trends-reliable`) Actor

Google Trends interest over time, interest by country, region and city, related queries and topics (top and rising) for up to 5 compared terms. Every run reports a clear status per term and only charges for rows with data.

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

## Pricing

from $3.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.
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 — Reliable, With Rising Queries

Get Google Trends data as structured JSON, CSV or Excel. Each run returns interest over time, interest by country, region or city, and related queries (top and rising). You can compare up to 5 terms on one scale.

The Actor is built to finish. Google limits automated traffic, so some requests get refused. When that happens, the run keeps everything it already fetched. Each term gets a clear status for each section. You pay only for rows that contain data.

### Who uses it

- **SEO and content teams.** They find rising and breakout queries for a topic before writing.
- **Market researchers.** They compare brands or products on one 0-100 scale, by country or region.
- **Analysts and data teams.** They feed weekly trend series into dashboards and models.
- **Regional teams.** It works with any language and any country, including Arabic terms in Saudi Arabia, the UAE or Egypt.

### What you get per term

| Section | What it is |
| --- | --- |
| Interest over time | The 0-100 series from the chart on Google Trends. |
| Interest by region | Countries for a worldwide search. Sub-regions for one country. Cities and US metro areas on request. |
| Related queries | Top and rising lists, 25 each at most. Rising items above +5,000% carry `isBreakout: true`. |
| Related topics | Optional and off by default. See "Limits". |
| Summary | Peak date and value, average, latest value, last 30 days against the 30 days before, and the breakout queries. |
| Trending now | Optional. The current Trending Now list for any country, with approximate traffic and news links. |

The summary is plain arithmetic on the series Google returned. It uses no AI and no estimates.

### Output example

Real output from a run on 2026-10-21. Input: `coffee`, worldwide, past 12 months. Long lists are cut to 2 or 3 items here.

```json
{
  "type": "term",
  "searchTerm": "coffee",
  "comparedWith": [],
  "geo": "Worldwide",
  "timeRange": "today 12-m",
  "resolvedTimeframe": "2025-10-21 2026-10-21",
  "searchType": "web",
  "trendsUrl": "https://trends.google.com/trends/explore?q=coffee&date=today+12-m",
  "status": "complete",
  "sectionStatus": {
    "interestOverTime": "ok",
    "interestByRegion": { "COUNTRY": "ok" },
    "relatedQueries": "ok"
  },
  "averageInterest": 77.3,
  "summary": {
    "points": 53,
    "peakDate": "2026-05-10T00:00:00.000Z",
    "peakValue": 100,
    "averageValue": 77.3,
    "latestValue": 57,
    "latestIsPartial": true,
    "last30DaysAverage": 69.4,
    "previous30DaysAverage": 81.3,
    "changeLast30VsPrevious30Pct": -14.6,
    "risingQueriesCount": 25,
    "breakoutQueries": [
      "how to remove coffee stain from carpet",
      "how to brew pour over coffee",
      "how to clean a coffee grinder"
    ],
    "hasBreakout": true
  },
  "interestOverTime": [
    { "date": "2025-10-19T00:00:00.000Z", "formattedTime": "Oct 19 – 25, 2025", "value": 65, "hasData": true, "isPartial": false },
    { "date": "2025-10-26T00:00:00.000Z", "formattedTime": "Oct 26 – Nov 1, 2025", "value": 57, "hasData": true, "isPartial": false }
  ],
  "interestByRegion": {
    "COUNTRY": [
      { "geoCode": "SG", "geoName": "Singapore", "value": 100, "hasData": true },
      { "geoCode": "AU", "geoName": "Australia", "value": 85, "hasData": true }
    ]
  },
  "relatedQueriesTop": [
    { "rank": 1, "query": "coffee shop", "value": 100, "formattedValue": "100", "link": "https://trends.google.com/trends/explore?q=coffee+shop&date=today+12-m" }
  ],
  "relatedQueriesRising": [
    { "rank": 1, "query": "how to remove coffee stain from carpet", "value": 7900, "formattedValue": "Breakout", "isBreakout": true, "link": "https://trends.google.com/trends/explore?q=how+to+remove+coffee+stain+from+carpet&date=today+12-m" }
  ],
  "scrapedAt": "2026-10-21T09:40:45.133Z"
}
```

An Arabic term in Saudi Arabia (`قهوة`, geo `SA`, language `ar`) returns Arabic region names and Google's Arabic labels. The breakout flag still works because it reads the number:

```json
{ "rank": 1, "query": "قهوة طهر", "value": 11900, "formattedValue": "ارتفاع هائل", "isBreakout": true }
```

A Trending Now row (`trendingNowGeos: ["SA"]`):

```json
{
  "type": "trendingNow",
  "geo": "SA",
  "rank": 1,
  "title": "جائزة أفضل لاعب في آسيا",
  "approxTraffic": "2000+",
  "approxTrafficMin": 2000,
  "publishedAt": "2026-10-21T09:40:00.000Z",
  "news": [{ "title": "سالم الدوسري أفضل لاعب آسيوي للمرة الثالثة", "source": "العربية", "url": "https://www.alarabiya.net/..." }]
}
```

#### Flat format

Set `outputFormat` to `flat` for one row per data point. Use it for spreadsheets. Each row has a `type`: `interestOverTime`, `interestByRegion`, `relatedQuery`, `relatedTopic` or `summary`. One term over 12 months worldwide gave 162 rows: 53 dates, 58 countries, 50 related queries and 1 summary.

### How it handles Google's limits

Google answers fast callers with HTTP 429 or a redirect to a check page. The Actor handles this in five ways.

1. **Pacing.** It waits 3.5 seconds plus a random 0 to 1.5 seconds between requests. You can raise this.
2. **Backoff.** A refused request is retried with growing waits: 5, 10, 20, 40 seconds.
3. **Fresh sessions.** After two refusals in a row it starts a new session with a new Google cookie.
4. **Proxy fallback.** If refusals continue across sessions, it moves from no proxy to Apify datacenter proxy, then to residential proxy. You can turn off the residential step.
5. **A second pass for related queries.** Google limits the related-queries endpoint harder than the others. If it refuses, the Actor stops asking for related lists for a while. It finishes the rest of the run, then retries the refused lists after a 30-second pause.

Every row shows what happened in `sectionStatus`. Example of a partial result: `"relatedQueries": "failed: relatedQueries: gave up after 5 attempts (last: HTTP 429)"`. The run summary in the key-value store (`RUN_SUMMARY`) lists each term's status. It also lists the request count, HTTP status counts, retries, proxy tier and bytes transferred.

**Run outcome rules**

- The run ends as **Succeeded** when at least one row has data. Terms that failed get a row with `status: "failed"` and `charged: false`.
- The run ends as **Failed** when Google refused every request. The message says so. Nothing is charged.
- Bad input fails at once with a list of problems. Nothing is fetched and nothing is charged.

### Pricing

- **Search term: $0.005** for each term that returned data ($5 per 1,000 terms). Google slows down automated requests, so most of the work is per term.
- **Result row: $0.0002** each ($0.20 per 1,000 rows).

A run for 10 terms in the default format costs about $0.05.

- In the default format, one row holds one search term with all its sections.
- In flat format, every data point is a row, so one term can be 150 rows or more.
- Each Trending Now item is one row.
- Rows with no data and rows for failed terms are free.
- The Actor stops when your run cost limit is reached. Terms it did not fetch are listed as `skipped_cost_limit` and are not charged.

### Input

| Field | What it does |
| --- | --- |
| `searchTerms` | Terms to look up. Any language. |
| `compareTerms` | Compare terms in groups of up to 5 on one 0-100 scale. |
| `startUrls` | Google Trends explore URLs. Terms and settings are read from the URL. |
| `timeRange` | Past hour up to 2004 to present. Default: past 12 months. |
| `customTimeRange` | `YYYY-MM-DD YYYY-MM-DD`. Overrides `timeRange`. |
| `geo` | Empty for worldwide, a country code (`SA`), or a region code (`US-CA`). |
| `category` | Google Trends category number. 0 means all. |
| `searchType` | `web`, `news`, `images`, `youtube` or `shopping`. |
| `regionResolutions` | `auto`, plus `COUNTRY`, `REGION`, `CITY` or `DMA`. Each extra level is one more request. |
| `trendingNowGeos` | Countries for the Trending Now list. |
| `outputFormat` | `perTerm` (default) or `flat`. |
| `language` | Language of region and topic names, for example `en-US` or `ar`. |
| `proxyConfiguration` | Your own proxy. This turns off the automatic fallback. |
| `requestDelayMs`, `maxRetries` | Pacing and retry limits. |

Example:

```json
{
  "searchTerms": ["iphone", "samsung galaxy", "google pixel"],
  "compareTerms": true,
  "geo": "US",
  "timeRange": "today 12-m",
  "regionResolutions": ["auto", "CITY"]
}
```

### Limits

- **Values are relative.** Google Trends gives 0-100 scores. It does not give search volumes.
- **Related queries are refused most often.** In our tests, Google refused this endpoint far more often than the others. The term row is still delivered with its other sections, and the status says what failed.
- **Related topics are off by default.** In every test on 2026-10-21, Google returned an empty topics list to automated requests. The same lists appeared on the website. Google also does not offer related topics when you compare terms. If you turn this on and the list is empty, the row says so and you pay nothing extra.
- **Small places have no data.** Google marks cities and regions with too little search volume as having no data. They are left out of the output, the same way the website hides them. A term can have an empty city list.
- **The summary needs 60 days.** For short ranges (past hour to past 30 days), the 30-day comparison is `null` and `changeNote` explains why.
- **Speed depends on Google.** One term needs about 5 requests. With no refusals that is about 25 seconds at the default pacing. When Google limits traffic, the Actor waits and retries, so a run can take several minutes.
- **Rising lists change.** Google's rising lists are recalculated often. Two runs a few minutes apart can return different rising items.

### Data source

The Actor calls the same public data endpoints that the Google Trends website calls when you open an explore page. Trending Now comes from Google Trends' public RSS feed. No Google account or API key is used.

### Development

```bash
npm install
npm test
node src/main.js
```

Unit tests replay real Google responses saved in `test/fixtures`. Set `GT_SAVE_RESPONSES=<folder>` to save every raw response of a local run.

# Actor input Schema

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

Words or phrases to look up. Each term gets its own row with every section you select. Any language works, for example Arabic.

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

On: terms are compared in groups of up to 5, like the Compare button on Google Trends. All terms in a group share one 0-100 scale. Off: each term is fetched alone on its own scale.

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

Paste explore URLs from trends.google.com. Terms, country, date range, category and search type are read from the URL.

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

Same choices as the Google Trends date picker.

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

Overrides the time range. Format: YYYY-MM-DD YYYY-MM-DD, for example 2025-01-01 2025-06-30.

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

Leave empty for worldwide. Use a 2-letter country code (US, SA, AE, GB) or a region code (US-CA, SA-01).

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

Google Trends category number. 0 means all categories. Examples: 7 Finance, 45 Health, 71 Food and Drink, 958 Jobs and Education, 5 Computers and Electronics.

## `searchType` (type: `string`):

Which Google search the data comes from.

## `includeInterestOverTime` (type: `boolean`):

The 0-100 time series.

## `includeInterestByRegion` (type: `boolean`):

Countries for worldwide searches, sub-regions for a country.

## `includeRelatedQueries` (type: `boolean`):

Rising lists include a breakout flag.

## `includeRelatedTopics` (type: `boolean`):

Off by default. In our tests Google returned this list empty for automated requests, and it is never offered when comparing terms. If empty, sectionStatus says so and nothing extra is charged.

## `includeSummary` (type: `boolean`):

Peak date, average, last 30 days versus the 30 days before, and breakout flags. Plain arithmetic on the returned series.

## `regionResolutions` (type: `array`):

auto = Google's default (countries for worldwide, sub-regions for a country). Add CITY for cities, REGION for sub-regions, COUNTRY for countries, DMA for US metro areas. Each extra level is one more request.

## `includeLowVolumeRegions` (type: `boolean`):

Same as the checkbox on Google Trends.

## `trendingNowGeos` (type: `array`):

2-letter country codes. Adds the current Trending Now searches for each country, with approximate traffic and news links.

## `outputFormat` (type: `string`):

perTerm: one row per search term with every section inside it. flat: one row per data point (one date, one region, one query), easier for spreadsheets but many more rows, and every row is charged.

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

Language for region and topic names, for example en-US or ar.

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

Leave off to use the automatic fallback below. If you set a proxy here, it is used for every request and the fallback is disabled.

## `autoProxyFallback` (type: `boolean`):

Starts without a proxy. If Google keeps answering 429, switches to Apify datacenter proxy, then residential.

## `allowResidentialFallback` (type: `boolean`):

Turn off to never use residential proxy.

## `requestDelayMs` (type: `integer`):

Google rate-limits fast callers. A random 0-1.5 s is added on top.

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

Retries with growing waits and fresh sessions before a section is marked failed.

## Actor input object example

```json
{
  "searchTerms": [
    "coffee"
  ],
  "compareTerms": false,
  "timeRange": "today 12-m",
  "geo": "",
  "category": 0,
  "searchType": "web",
  "includeInterestOverTime": true,
  "includeInterestByRegion": true,
  "includeRelatedQueries": true,
  "includeRelatedTopics": false,
  "includeSummary": true,
  "regionResolutions": [
    "auto"
  ],
  "includeLowVolumeRegions": false,
  "outputFormat": "perTerm",
  "language": "en-US",
  "autoProxyFallback": true,
  "allowResidentialFallback": true,
  "requestDelayMs": 3500,
  "maxRetries": 6
}
```

# Actor output Schema

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

Interest over time, interest by region, related queries and topics, summary fields and a status per term.

## `runSummary` (type: `string`):

Per-term status, requests made, HTTP status counts, retries, proxy tier used and bytes transferred.

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

// Run the Actor and wait for it to finish
const run = await client.actor("dottti/google-trends-reliable").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": ["coffee"] }

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dottti/google-trends-reliable"
        }
    }
}
```

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/1qrq3DlLYp2rKH5T5/builds/fNEhuUABl9P2C54TV/openapi.json
