# Google Trends Scraper: Compare & Bulk (`otterfetch/google-trends`) Actor

Google Trends interest over time, by region and related queries for any number of keywords. Compare up to 5 on one scale or bulk-scale hundreds. $0.002 per keyword, add-ons $0.001, no start fee. Never billed for empty or suspect data. AI-agent friendly: summary rows come first.

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

## Pricing

from $2.00 / 1,000 keywords

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: Compare & Bulk

Get Google Trends interest over time for one keyword or thousands. Run keywords on their own scale, compare up to 5 on a shared scale, or put any number on one shared scale in bulk mode. Add interest by region and related queries if you need them.

You pay per keyword that returns data, and nothing for empty, failed or suspect results. Every run checks that Google served real data before it bills you.

### Why this one

- One flat price per keyword: no start fee, no per-GB fee and no per-data-point fee.
- You are never billed for empty, failed or fake data, and every run checks for it.
- Compare up to 5 keywords, or bulk hundreds, on one shared scale.
- A clear status per keyword, so nothing fails silently.
- Works with AI agents and integrations: summary rows come first in the dataset.

### Quick start

1. Type your keywords in **Search terms**, or paste a link in **Import terms from a link**.
2. Pick a **Country** and a **Time range**. Optionally turn on **Include interest by region** or **Include related queries**.
3. Click **Start**. When the run ends, open the **Summary** view, or export the dataset as CSV.

### What you get

One summary row per keyword. These are real rows from a cloud run (US, past 12 months):

| keyword | average | peak date | latest | change % | trend |
|---|---|---|---|---|---|
| iphone | 60.54 | 2026-01-25 | 51 | -17.58 | down |
| taylor swift | 24.83 | 2026-06-28 | 15 | +73.61 | up |
| sourdough | 69.58 | 2026-01-18 | 61 | -0.83 | flat |
| matcha | 75.96 | 2026-04-12 | 61 | -11.85 | down |

With regions on, "air fryer" in the US over the past 12 months gave Wyoming 100, Kansas 36 and Nebraska 35 (real run).

With related queries on, the top related queries for "air fryer" include "air fryer chicken" and "ninja air fryer" (real run).

Values are Google's relative interest (0 to 100), not search volume.

### Pricing

Pay per event. You pay for results, not for time.

| Event | Price | Charged when |
|---|---|---|
| `keyword` | $0.002 | Interest over time came back for one keyword, place and time range (`success` or `low_precision`). |
| `region` | $0.001 | Region rows came back for that keyword. |
| `related-queries` | $0.001 | At least one top or rising query came back for that keyword. |

Prices shown are the current list prices; Apify shows the live price on the Actor page.

#### What 1 keyword actually costs

One keyword costs **$0.002**. Each add-on you switch on adds **$0.001** for that keyword, and only when that add-on returned data. So a keyword with regions and related queries costs $0.004 at most.

The plain facts:

- No start fee.
- No per-GB fee.
- No per-data-point billing: a keyword with 53 weekly points and one with 2,000 hourly points cost the same.
- You are never charged for empty results (`no_data`), failed keywords or suspect data (`suspect_decoy`). Related queries marked `partial` (rising list held back) are not charged either; the keyword and region events still are.
- If Google blocks a keyword's region or related-queries data after retries, the keyword's timeline is still returned and charged, and the missing add-on is marked `failed` (see `region_failure_reason` and `related_failure_reason` on the summary row) and not charged.
- The bulk anchor keyword, its pre-pass and the data check at the start of each run are free.
- Duplicate keywords with the same place, time range, category and search type are fetched once and billed once.
- The Actor respects your max total charge. It works out how many keywords the budget covers before it starts, and lists the rest as skipped in `RUN_SUMMARY`.

### What it does

- **Interest over time** for any list of keywords, in a country, a subregion or worldwide, over any time range from the past hour to 2004 to present, or a custom date range.
- **Three modes.** `single` gives each keyword its own 0 to 100 scale. `compare` puts up to 5 keywords on one shared scale. `bulk` puts any number of keywords on one shared scale by comparing them through an anchor keyword.
- **Optional add-ons:** interest by region (countries, subregions or cities) and top and rising related queries.
- **A summary row per keyword:** average, peak, latest value, change over the last periods, trend, and a breakout flag.
- **Honest statuses.** Every keyword ends as `success`, `no_data`, `low_precision`, `failed` or `suspect_decoy`, so you can see what happened to each one. Related queries can also end as `partial`.
- **Inputs you can paste:** keywords, Google Trends explore links, or a CSV / Google Sheets link with one keyword per row.

Google Trends reports relative interest on a 0 to 100 scale, not search volume. See the FAQ.

### Who it is for

- **SEO teams** checking seasonality, rising queries and which topic is bigger.
- **E-commerce sellers** comparing product names by country and finding the regions that search for them most.
- **Analysts** pulling long keyword lists into a spreadsheet or warehouse on a schedule.
- **AI agents** that need a clear input, a clear status per keyword and a bill that matches what came back.

### Example inputs

Field keys below are the real input keys. Everything except the search terms is optional.

#### SEO: seasonality and rising queries

```json
{
  "searchTerms": ["air fryer"],
  "mode": "single",
  "geo": "US",
  "timeRange": "past_5_years",
  "includeRelatedQueries": true
}
```

#### E-commerce: which product name is bigger, and where

```json
{
  "searchTerms": ["air fryer", "slow cooker", "rice cooker"],
  "mode": "compare",
  "geo": "GB",
  "timeRange": "past_12_months",
  "includeRegions": true,
  "regionLevel": "auto"
}
```

#### Analysts: a long list on one scale

```json
{
  "importUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit",
  "mode": "bulk",
  "timeRange": "past_90_days",
  "timezone": "America/New_York",
  "dateFormat": "plain",
  "maxKeywords": 500
}
```

#### AI agents: one keyword, one call

```json
{
  "searchTerms": ["iphone 17"],
  "mode": "single",
  "geo": "US",
  "timeRange": "past_30_days",
  "includeSummary": true
}
```

This returns the full series (one `timeseries` row per date) plus one `summary` row. For a compact answer, read only the row where `type` is `summary`: it has the average, peak, latest value, change and trend.

### FAQ

**Can I look up a keyword that contains a comma?**
The data is fetched correctly, but Google Trends links treat a comma as a separator between keywords. So the `source_url` for such a keyword opens a search split into several keywords, not the one you sent.

**Is this search volume?**
No. Google Trends gives relative interest, from 0 to 100, not search volume. 100 is the peak for the keyword (or for the busiest keyword in a compare or bulk set) in the place and time range you picked. It does not tell you how many searches that is.

**Why do I get `no_data` for a keyword?**
Google shows no data for keywords that are too rare in the place and time range you chose. Try a wider range, a larger place (worldwide instead of a small subregion), or a more common spelling. You are not charged for it.

**Why is city data missing for some keywords?**
City data is best for popular keywords. Small keywords often return few cities or none. Use `regionLevel: "auto"` for countries, subregions and metro areas, which have more data.

**How do I handle very small keywords?**
Very small keywords are best run in their own bulk job. On a shared scale with a large keyword, a small one rounds down to 0 or 1 everywhere. Run it with other small keywords and the scale fits them.

**What does `suspect_decoy` mean?**
We have observed Google serving altered data to some traffic. The Actor checks every run and every row for signs of it, and does not bill rows flagged as suspect. If a keyword comes back as `suspect_decoy`, you are not charged for it. If the check at the start of a run fails, the run stops and charges nothing.

**What is the difference between the modes?**
In `single` mode every keyword has its own 0 to 100 scale, so a tiny keyword and a huge one both peak at 100. In `compare` and `bulk` mode they share one scale, so you can see which is bigger. Compare takes up to 5 keywords. Bulk takes any number by comparing them through an anchor keyword.

**Can I get trending now, daily trends or related topics?**
No. This Actor returns interest over time, interest by region and related queries.

### Advanced

#### Sample output

The dataset has one row type per `type` field. In the dataset, summary rows come first, then region, related query and timeseries rows. A view (for example "Summary") picks the columns but still lists every row, so in a view's CSV keep the rows whose columns are filled, or call the API with `view=summary` and a `limit` equal to your keyword count to get only the summary rows. These rows were produced by the Actor's own row builders from recorded test data for the keyword "air fryer" (US, past 12 months, `single` mode). The `region` rows come from a real run for "iphone" with the same settings.

**`timeseries`** (one row per date):

```json
{
  "type": "timeseries",
  "keyword": "air fryer",
  "status": "success",
  "geo": "US",
  "time_range": "today 12-m",
  "category": 0,
  "search_type": "web",
  "mode": "single",
  "unit_id": "2f0714b2927b",
  "source_url": "https://trends.google.com/trends/explore?q=air%20fryer&geo=US&date=today%2012-m",
  "date": "2025-10-12T00:00:00+00:00",
  "value": 53,
  "is_partial": false,
  "scale_note": "",
  "is_anchor": false
}
```

The last point of a range is often still being collected, so it comes back with `"is_partial": true`. It is left out of the summary.

**`summary`** (one row per keyword):

```json
{
  "type": "summary",
  "keyword": "air fryer",
  "status": "success",
  "geo": "US",
  "time_range": "today 12-m",
  "category": 0,
  "search_type": "web",
  "mode": "single",
  "unit_id": "2f0714b2927b",
  "source_url": "https://trends.google.com/trends/explore?q=air%20fryer&geo=US&date=today%2012-m",
  "average": 66.58,
  "peak_value": 100,
  "peak_date": "2026-04-12T00:00:00+00:00",
  "latest_value": 57,
  "change_pct": -14.45,
  "trend": "down",
  "breakout": false,
  "data_status": "success",
  "failure_reason": null,
  "related_status": "success",
  "region_status": "success",
  "region_failure_reason": null,
  "related_failure_reason": null,
  "is_anchor": false
}
```

`change_pct` compares the last 4 complete periods with the 4 before them. `trend` is `up`, `down` or `flat` (flat is within 10% either way). `breakout` is true when the latest complete period is the peak and at least twice the average.

**`region`** (one row per region, highest first):

```json
{
  "type": "region",
  "keyword": "iphone",
  "status": "success",
  "geo": "US",
  "time_range": "today 12-m",
  "category": 0,
  "search_type": "web",
  "mode": "single",
  "unit_id": "f81e55cdde10",
  "source_url": "https://trends.google.com/trends/explore?q=iphone&geo=US&date=today%2012-m",
  "level": "subregion",
  "region_name": "Wyoming",
  "region_code": "US-WY",
  "value": 100
}
```

A second row from the same run: `"region_name": "Louisiana"`, `"region_code": "US-LA"`, `"value": 63`.

**`related_query`** (`list` is `top` or `rising`; a top row has `"list": "top"`, `"rank": 1`, `"query": "air fryer chicken"`, `"value": 100`, `"formatted_value": "100"`):

```json
{
  "type": "related_query",
  "keyword": "air fryer",
  "status": "success",
  "geo": "US",
  "time_range": "today 12-m",
  "category": 0,
  "search_type": "web",
  "mode": "single",
  "unit_id": "2f0714b2927b",
  "source_url": "https://trends.google.com/trends/explore?q=air%20fryer&geo=US&date=today%2012-m",
  "list": "rising",
  "rank": 18,
  "query": "ninja glass air fryer",
  "value": 650,
  "formatted_value": "+650%"
}
```

#### Getting one row type only

The dataset has four views in the Apify Console: **Interest over time**, **Summary**, **Interest by region** and **Related queries**. Each view shows the columns for one row type. Apify dataset views cannot filter rows by value, so a view lists every row and leaves the columns that do not apply empty.

To get one type only, filter on the `type` field after you export. In Google Sheets, add a filter on the `type` column. With the Apify API or a client, request the dataset items and keep the rows where `type` equals `summary` (or `timeseries`, `region`, `related_query`). The `fields` parameter limits which columns come back.

#### Statuses

Each row carries a `status`. The summary row also repeats the keyword's status as `data_status`, and adds `related_status` and `region_status` for the add-ons, plus `related_failure_reason` and `region_failure_reason` when an add-on failed or, for `partial`, was held back.

| Status | Meaning | Billed? |
|---|---|---|
| `success` | Interest over time came back and passed the checks. | Yes |
| `low_precision` | Data came back, but the keyword peaked under 5 on its scale (in bulk, also when the anchor was weak in its batch), so its values are coarse. | Yes |
| `no_data` | Google has no data for this keyword, place and time range. | No |
| `failed` | The keyword could not be fetched. The summary row has a `failure_reason`. | No |
| `suspect_decoy` | The data looked altered, so the Actor will not vouch for it. | No |
| `partial` | Only for `related_status`: top related queries were returned, rising ones were held back as suspect (their rows are `suspect_decoy`), and related queries were not charged. `related_failure_reason` says why. | No (related queries only) |

Keywords with `no_data`, `failed` or `suspect_decoy` always get a summary row, even if you switch the summary off, so every keyword you sent is visible in the dataset.

`low_precision` is billed because data was returned. It means the keyword peaked under 5 on its scale, so its values are coarse (a single step from 1 to 2 looks like a doubling). In `compare` mode that is the shared scale. In `bulk` mode it is also set when the anchor was weak (peaked under 5) in the keyword's batch, so the shared scale is unreliable, and `scale_note` says which case applies. `single` mode never sets it. If you have very small keywords, run them in their own bulk job so they share a scale with each other and not with a giant.

#### Run summary and status message

While a run is going, the status message shows progress. When it ends, the message is a plain one-line recap, for example:

```
Done: 12 success, 1 no_data. Charged: 12 keyword.
```

It lists how many keywords ended in each status, what was charged, and why any keywords were skipped (your max cost, a time limit, or your `maxKeywords` limit).

A fuller record is saved in the run's key-value store under `RUN_SUMMARY`. It holds the count per status, the events charged per type, the estimated run cost, the canary result, the anchor used in bulk mode, skipped keywords and any warnings.

#### unit_id and source_url

Every row also carries `unit_id` and `source_url`. `unit_id` is a 12-character id built from the keyword, place, time range, category and search type, so the same keyword with the same settings always gets the same id. `source_url` is the Google Trends link for that keyword and those settings. In `compare` and `bulk` mode the link lists the keywords that were fetched together, so it opens the same comparison.
`unit_id` stays the same from run to run. In the rare case that the platform restarts a run and the same rows are pushed twice, dedupe on `unit_id` (together with `type` and `date`, or `region_name`, or `list` and `rank`). `source_url` opens the same keyword, place, time range, category and search type on Google Trends, so you can check any number by eye.

#### All inputs

All inputs and what they do:

| Field (key) | What it does |
|---|---|
| Search terms (`searchTerms`) | Keywords, or pasted Google Trends explore links. A link's own country, time range, category and search type apply to its terms. |
| Import terms from a link (`importUrl`) | A CSV link or a Google Sheets link shared as "anyone with the link" (a "Publish to web" link also works). One keyword per row in the first column. |
| Mode (`mode`) | `single`, `compare` (up to 5 keywords) or `bulk` (any number). Default `single`. |
| Anchor term (`anchorTerm`) | Bulk only. Leave empty to let the Actor pick a steady one. |
| Country or region (`geo`) | `US`, `GB`, or a subregion such as `US-CA`. Empty means worldwide. |
| Time range (`timeRange`) | From `past_hour` to `all_time`, or `custom` with `startDate` and `endDate`. Default `past_12_months`. |
| Category (`category`) | One top-level Google Trends category. Default all categories. |
| Search type (`searchType`) | `web`, `youtube`, `news`, `images` or `shopping`. |
| Include interest by region (`includeRegions`) | Adds region rows. Billed as an extra event. |
| Region detail (`regionLevel`) | `auto` or `city`. Auto follows Google's default level for the area: countries for worldwide, subregions (states) for a country, metro areas for a US state. |
| Include related queries (`includeRelatedQueries`) | Adds top and rising related queries. Billed as an extra event. |
| Include summary row (`includeSummary`) | One summary row per keyword. On by default. |
| Timezone (`timezone`) | IANA name such as `Asia/Manila`. Default `UTC`. |
| Date format (`dateFormat`) | `iso` or `plain`. |
| Maximum keywords (`maxKeywords`) | Safety limit for scheduled runs. Extra keywords are skipped and listed in the run summary. |

#### Integrations

You can run the Actor from other tools with the same input. Each tool starts the Actor and reads its dataset. The setup screens differ by tool and change over time, so use each tool's Apify integration and paste the input below.

##### Zapier

Use the Apify integration to run the Actor, then read the dataset items it produced.

```json
{
  "searchTerms": ["coffee", "tea"],
  "mode": "compare",
  "geo": "US",
  "timeRange": "past_12_months"
}
```

Back come the dataset rows: one `summary` row per keyword plus the `timeseries` rows. Filter on `type` in a later step if you only want the summaries.

##### Make

Use the Apify module to run the Actor and then get its dataset items.

```json
{
  "importUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit",
  "mode": "bulk",
  "timeRange": "past_90_days",
  "maxKeywords": 200
}
```

Back come the same rows as in the sample output, one item per row, which you can map to your next module.

##### Google Sheets

To send keywords in, use `importUrl` with a sheet shared as "anyone with the link", or a sheet published to the web (File, Share, Publish to web). To get results out, open the run's dataset in the Apify Console, choose Export, and pick CSV, then open the file in Google Sheets (File, Import). The dataset also has a CSV download link you can use the same way. The "All fields" CSV export lists columns alphabetically; export a view (Summary, Interest over time, Interest by region, Related queries) for tidy columns.

```json
{
  "importUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit",
  "mode": "single",
  "geo": "US"
}
```

Back comes a dataset you can export as CSV and open in a sheet. Filter the `type` column to see one row type at a time.

##### Apify MCP from Claude

Connect Claude to the Apify MCP server, then ask Claude to run this Actor. The input is the same JSON.

```json
{
  "searchTerms": ["iphone 17", "pixel 10"],
  "mode": "compare",
  "geo": "US",
  "timeRange": "past_30_days"
}
```

Claude gets the dataset rows back, including the `status` for each keyword and the summary row, so it can tell a keyword with no data from a failed one.

### Issues

Report problems in the Issues tab; the developer answers within 2-3 days. Include the run link and the keyword that went wrong if you can.

# Actor input Schema

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

Keywords to look up, one per entry, for example "coffee" or "iphone 17". You can also paste a Google Trends explore link (for example https://trends.google.com/trends/explore?q=coffee\&geo=US). A pasted link is used exactly as Google showed it, with Google's defaults for anything it leaves out (worldwide, past 12 months, all categories, web search), so the country, time range, category and search type below do not apply to it. Required unless you give an import link.

## `importUrl` (type: `string`):

Optional https link to a CSV file or a Google Sheets link (shared as "anyone with the link", or a "Publish to web" link). One keyword per row in the first column; a header row named keyword, term or query is skipped. Example: https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit

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

How keywords are scaled. Single gives each keyword Google's own 0 to 100 scale. Compare puts up to 5 keywords on one shared scale so you can see which is bigger. Bulk does the same for any number of keywords by comparing them through an anchor keyword.

## `anchorTerm` (type: `string`):

Bulk mode only. The keyword every other keyword is compared against. Leave empty to let the Actor pick a steady one automatically. Example: "weather".

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

The country the searches came from. Pick a country by name, or leave it on Worldwide. Example: United States. Pasted Google Trends links keep their own country.

## `subregion` (type: `string`):

Narrow the search to a state or region inside the country you picked, using Google's code. It must start with the country code. Example: US-CA for California when the country is United States. Leave empty for the whole country.

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

How far back to look. Shorter ranges give finer detail (hourly or daily points), longer ranges give weekly or monthly points. Choose Custom to use the start and end date below.

## `startDate` (type: `string`):

First day of a custom range, as YYYY-MM-DD, for example 2024-01-01. Only used when Time range is Custom.

## `endDate` (type: `string`):

Last day of a custom range, as YYYY-MM-DD, for example 2024-06-30. Only used when Time range is Custom.

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

Limit results to one top-level Google Trends category, for example Health. This helps with ambiguous words such as "apple". For a subcategory, paste a Google Trends explore link that already has the category set into Search terms.

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

Which Google search the interest data comes from. Web search is the usual choice.

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

Add rows showing which regions search for each keyword the most. Billed as an extra event per keyword when region data is returned.

## `regionLevel` (type: `string`):

How detailed the region rows are. Automatic follows Google's default level for the area: countries for a worldwide search, subregions (states) for a country, and metro areas for a US state. Cities works best for popular keywords. Only used when interest by region is on.

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

Add rows with the top and rising related searches for each keyword, for example "coffee beans" or "coffee maker". Billed as an extra event per keyword when queries are returned.

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

Add one row per keyword with its average, peak, latest value, change and trend. Keywords with no data always get a summary row so you can see why.

## `timezone` (type: `string`):

Timezone used for dates in the output, as an IANA name, for example Asia/Manila or America/New_York.

## `dateFormat` (type: `string`):

How dates are written in the output rows.

## `maxKeywords` (type: `integer`):

Safety limit for scheduled runs. Keywords beyond this number are skipped and listed in the run summary. Example: 100. Leave empty for no limit.

## `healthCheck` (type: `boolean`):

For the Actor owner only. Makes the run fail when the built-in data check fails or fake data is detected, so a scheduled run can raise an alert. Leave off.

## Actor input object example

```json
{
  "searchTerms": [
    "iphone",
    "samsung galaxy",
    "google pixel"
  ],
  "mode": "compare",
  "geo": "US",
  "timeRange": "past_12_months",
  "category": "0",
  "searchType": "web",
  "includeRegions": false,
  "regionLevel": "auto",
  "includeRelatedQueries": false,
  "includeSummary": true,
  "timezone": "UTC",
  "dateFormat": "iso"
}
```

# Actor output Schema

## `summary` (type: `string`):

One row per keyword: status, average, peak value and date, latest value, % change, trend, and the status of the region and related-queries add-ons. Start here.

## `timeseries` (type: `string`):

One row per keyword and date: Google's relative interest (0 to 100, not search volume) and whether the period is still partial.

## `region` (type: `string`):

One row per keyword and region (country, subregion, metro or city), with Google's relative interest. Only when regions were requested.

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

Top and rising related queries per keyword, with value and formatted value (for example +250% or Breakout). Only when related queries were requested.

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

Counts per status, charged events, canary check result and request statistics for the whole run (key-value store record RUN_SUMMARY).

# 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": [
        "iphone",
        "samsung galaxy",
        "google pixel"
    ],
    "mode": "compare",
    "geo": "US"
};

// Run the Actor and wait for it to finish
const run = await client.actor("otterfetch/google-trends").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": [
        "iphone",
        "samsung galaxy",
        "google pixel",
    ],
    "mode": "compare",
    "geo": "US",
}

# Run the Actor and wait for it to finish
run = client.actor("otterfetch/google-trends").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": [
    "iphone",
    "samsung galaxy",
    "google pixel"
  ],
  "mode": "compare",
  "geo": "US"
}' |
apify call otterfetch/google-trends --silent --output-dataset

```

## MCP server setup

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

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/BBTTt0678O01hNRNV/builds/Nss1B5H9gArHjNn1l/openapi.json
