# Keyword Comparison & Seasonality 📈 (Google Trends, 1 scale) (`tagadanar/keyword-comparison-seasonality`) Actor

Put 2 to 5 keywords on one shared Google Trends scale and see which is actually bigger, then get each keyword's season: peak and quiet months, a strength score, year-over-year direction and rising related queries. Re-run it monthly per topic set. No browser, no API key, usage included.

- **URL**: https://apify.com/tagadanar/keyword-comparison-seasonality.md
- **Developed by:** [Tagada Data](https://apify.com/tagadanar) (community)
- **Categories:** SEO tools, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 keyword analyses

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Keyword Comparison & Seasonality (Google Trends)

Give it 2 to 5 keywords. You get back which one is actually bigger, on the single
shared 0 to 100 scale Google uses when you add terms side by side in the Trends
UI, plus each keyword's season: the months it peaks, the months it goes quiet, a
strength score, whether it is up or down year on year, and the related queries
that are breaking out right now.

It is built for one recurring job: the content or SEO planner who sits down once
a month with a topic set and asks "which of these should I write about next, and
when does it actually get searched".

### Why not just open Google Trends

You can compare five terms in the Trends UI for free, one topic set at a time, on
screen. What it will not give you is the numbers, the month by month seasonality
read and the rising queries in one file you can diff against last month's. That
layer is what the paid Trends tools sell: Glimpse, the best known of them, stops
at 10 free searches a month and then starts at around $50 a month (checked
2026-08-17). This actor does the comparison and the seasonality part of that job
as a scheduled run, and charges $0.002 per keyword.

### The whole comparison is one run

Most Google Trends actors on this store bill per keyword and, more importantly,
several of them take **one keyword per run**, which means a run fee per keyword
and no shared scale at all. Comparing five keywords once a month:

| actor | what the job costs | notes |
| --- | ---: | --- |
| **this actor** | **$0.011** | one run, shared scale plus seasonality for all five |
| `doesaiknow/keyword-seasonality-breakout-tracker` | $0.095 | seasonality only, no cross-keyword comparison |
| `data_xplorer/google-trends-fast-scraper` | $0.110 | one keyword per run, so the $0.02 start is paid five times |
| `agenscrape/google-trends-scraper` | $0.150 | $0.025 start plus $0.025 per item |
| `george.the.developer/calibrated-google-trends-api` | $0.750 | calibrated comparison, no seasonality |
| `apify/google-trends-scraper` | from $0.015 | the pool leader, rated 3.22 with 22.8% of its runs timed out or failed |

Prices read from the public Store API on 2026-08-17. The leader's failure figure
is 19.1% timed out plus 3.7% failed across 21,120 runs over 30 days, from the
same source. This actor talks to Google's JSON endpoints directly, with no
browser and nothing to time out.

### What you get, per keyword

| field | what it is |
| --- | --- |
| `rank`, `ofKeywords` | where the keyword places in the set, by average interest |
| `pctOfLeader`, `isLeader` | how big it is against the biggest keyword in the set |
| `averageInterest`, `peakInterest`, `peakDate` | on the scale shared across the whole set |
| `sharedScale` | true when exactly one keyword holds the 100, which is the proof the values are comparable |
| `peakMonths`, `lowMonths` | the three strongest and three weakest calendar months |
| `seasonalityStrength` | 0 to 100. 0 is flat all year, 100 would be a single month carrying everything |
| `seasonalityLabel` | flat, mild, clear, strong or extreme, so a spreadsheet reads without a legend |
| `monthlyIndex` | all twelve months, the keyword's best month set to 100 |
| `yearOverYear`, `yearOverYearChangePct` | rising, falling or flat, at a 10% threshold |
| `risingQueries` | the breakout related queries for that keyword, with their growth |
| `interestOverTime` | the full weekly series on the shared scale, for charting |
| `seasonalityNote`, `yearOverYearNote` | filled in when a number is missing, saying exactly why |

### How the seasonality number is computed

No model, no smoothing, no black box. Every step:

1. Weekly interest is averaged inside each calendar month.
2. Each month is divided by its own year's average. This is the step that keeps
   a keyword which simply grew for five years from reading as "peaks in the most
   recent months". Growth is not a season.
3. Those ratios are averaged across the years.
4. The result is rescaled so the keyword's strongest month is 100. That is
   `monthlyIndex`.
5. `seasonalityStrength` is `(peak - trough) / peak`, as a percentage.
6. `peakMonths` is the top three months, `lowMonths` the bottom three.

Two exclusions, both deliberate: a year holding fewer than 10 months of data is
left out of the average, because a five year window starts and ends mid-year and
half a year would drag whichever months it covers; and the still-open final week
never enters an average, because Google itself marks it incomplete.

`yearOverYear` is the mean of the last 52 weeks against the 52 before them.
Rising above +10%, falling below -10%, flat between, because Trends noise moves a
few percent on its own.

### Two scales, and why

The comparison numbers come from one request carrying all the keywords together,
which is what makes Google normalise them against each other. Ask for them
separately and each one is rescaled to its own peak, so a 100 for one and a 100
for another mean nothing next to each other. That is the mistake this actor
exists to avoid, and `sharedScale` in the output is the check.

The seasonality numbers come from a second pass, one request per keyword on its
own, skipping the keyword that already holds the 100 because for that one the two
scales are the same thing. There is a reason for the second pass. On a shared
scale the 100 belongs to whichever keyword is biggest, and a big one flattens the
rest. Measured on `black friday`,
`christmas gifts`, `valentines day`, `halloween costumes` and `easter eggs` in the
US: one Black Friday week takes the 100 and compresses the other four into whole
numbers between 0 and 13, which leaves no readable season at all. Given its own
request each of the five comes back correct, peaking in November, December,
February, October and April respectively. Seasonality is a shape inside one
keyword, so it belongs on that keyword's own scale.

If a keyword still ends up too small to read, `seasonalityNote` says so rather
than publishing a pattern made of rounding. That answer is useful by itself: it
means the set is mismatched and that keyword wants closer rivals.

### Input

```json
{
  "keywords": ["ski holidays", "beach holidays"],
  "geo": "GB",
  "historyWindow": "today 5-y"
}
```

E-commerce planning, on YouTube instead of web search:

```json
{
  "keywords": ["air fryer", "instant pot", "slow cooker"],
  "geo": "US",
  "historyWindow": "today 5-y",
  "property": "youtube"
}
```

A quick comparison with no seasonality, over the last year only:

```json
{
  "keywords": ["chatgpt", "claude", "gemini"],
  "historyWindow": "today 12-m"
}
```

| input | |
| --- | --- |
| `keywords` | 2 to 5 keywords, required. Google compares at most 5 at once; extras are dropped with a warning in the log |
| `geo` | country, or leave empty for worldwide. Seasonality flips hemispheres, so this matters here |
| `historyWindow` | 5 years by default. 12 months returns the comparison only, and says so in the record |
| `property` | web, news, images, YouTube or Shopping. YouTube and Shopping seasons can peak weeks apart from web |

### Use cases

**Content calendars.** Run your topic set in January, read `peakMonths`, and
publish six to eight weeks ahead of each peak rather than during it.

**Choosing between two angles.** "Is anyone searching for X or for Y" is only
answerable on a shared scale. `pctOfLeader` answers it in one number.

**Catching a category turning over.** Re-run the same set monthly and watch
`yearOverYearChangePct` and `risingQueries`. A keyword going from flat to falling
two months running is a signal before it shows up in your traffic.

**Seasonal stock and ad budgets.** `monthlyIndex` is twelve numbers you can paste
straight into a spend plan.

### Questions people ask

**Is this real Google Trends data?** Yes, from the same JSON endpoints
trends.google.com calls. Nothing is estimated or modelled.

**Does it give absolute search volume?** No. Google Trends does not publish
absolute volume and neither does this actor. Everything here is relative
interest, which is what Trends actually measures.

**Why only 5 keywords?** Because Google itself compares at most 5 terms in one
request, and going past that would mean gluing separate scales together. Run
several sets if you have more, or use the sibling actor below for bulk lists.

**Why does one of my keywords have no seasonality?** Either the window is shorter
than two full years, or that keyword is too far behind the leader of the set for
Google's whole-number scale to hold a pattern. `seasonalityNote` says which.

**Can I schedule it?** That is what it is for. Point a monthly schedule at the
same keyword set and diff the datasets.

**Do I need an API key or a proxy?** Neither. Platform usage is included in the
price.

### Related actors

- [Google Trends Scraper (Bulk Keyword Lists & Trending Now)](https://apify.com/tagadanar/google-trends-scraper)
  — a bulk keyword list, interest by region, or live Trending Now with search
  volumes. This actor is the narrow version: one comparison set, done properly,
  meant to be re-run.
- [Trending Searches Today](https://apify.com/tagadanar/trending-searches-today)
  — what is trending right now, by country, with approximate search volumes and
  growth. Seasonality answers "when does this peak every year"; that actor
  answers "what is peaking today".

***

Keywords: compare keywords google trends, keyword seasonality, seasonal keyword
research, peak months keyword, google trends comparison shared scale, keyword
comparison api, glimpse alternative, rising related queries, year over year
search interest, seasonality analysis SEO, content calendar keyword planning.

# Actor input Schema

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

The keywords you want scored <b>against each other</b>. Google puts 2 to 5 terms on one shared 0–100 scale, so a value of 40 for one keyword really is half of another keyword's 80. Extra keywords past the fifth are dropped with a warning.

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

Where to measure the interest. Seasonality flips hemispheres, so this matters more here than on most Trends jobs.

## `historyWindow` (type: `string`):

5 years is the default because the seasonality read needs at least two full years to average. Pick 12 months for a quick comparison and the seasonality fields come back empty with the reason stated in the record.

## `property` (type: `string`):

Which Google surface the interest is measured on. Web search is what most content and SEO planning is about; YouTube and Shopping seasonality can peak weeks apart from it.

## Actor input object example

```json
{
  "keywords": [
    "ski holidays",
    "beach holidays"
  ],
  "geo": "",
  "historyWindow": "today 5-y",
  "property": ""
}
```

# Actor output Schema

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

One record per keyword: its place in the comparison, its seasonality and its rising queries.

# 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": [
        "ski holidays",
        "beach holidays"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tagadanar/keyword-comparison-seasonality").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": [
        "ski holidays",
        "beach holidays",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("tagadanar/keyword-comparison-seasonality").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": [
    "ski holidays",
    "beach holidays"
  ]
}' |
apify call tagadanar/keyword-comparison-seasonality --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tagadanar/keyword-comparison-seasonality"
        }
    }
}

```

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/D7bXcJCdTXATa3XEp/builds/IeLNAHP8FqBQTDl4T/openapi.json
