# Google Trends Keyword Monitor & Rising Trend Finder (`groupoject/trendpulse-keyword-monitor`) Actor

Bulk Google Trends keyword monitoring, rising keyword detection, and SEO opportunity scoring.

- **URL**: https://apify.com/groupoject/trendpulse-keyword-monitor.md
- **Developed by:** [Group Oject](https://apify.com/groupoject) (community)
- **Categories:** SEO tools, AI, E-commerce
- **Stats:** 2 total users, 0 monthly users, 50.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 results

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

## TrendPulse Keyword Monitor

**Bulk Google Trends keyword monitoring, rising keyword detection, and SEO opportunity scoring.**

> 🔑 **Setup in 60 seconds:** get a free [SerpApi key](https://serpapi.com/users/sign_up) (100 searches/month free), paste it into the `serpApiKey` input field, and run. SerpApi handles Google's anti-bot for you — no proxy fight, no 429s.

Upload hundreds or thousands of keywords and get a clean ranked report showing which keywords are **rising**, **declining**, **stable**, **volatile**, or **breaking out** across selected countries and time ranges — plus a composite **TrendPulse Score** for ranking opportunities.

---

### What this Actor does

TrendPulse Keyword Monitor pulls publicly available Google Trends interest-over-time data and related-query data for every keyword you submit, then runs each result through a deterministic scoring pipeline that produces:

- A **trend status** (`breakout`, `rising`, `stable`, `declining`, `volatile`, `insufficient_data`)
- **Growth %**, momentum, volatility, and confidence sub-scores (0–100)
- A composite **TrendPulse Score** (0–100) for easy ranking
- **Related queries**, **rising queries**, **breakout terms**, and **related topics**
- A short list of **content angle suggestions** and a **recommended action**

Every keyword produces exactly one dataset row — even when fetching fails — so the dataset is monetization-ready and easy to filter.

---

### Who is this for?

- **SEO teams & agencies** — identify rising keywords before they are competitive.
- **Content creators & newsletter writers** — find timely angles for blog posts, videos, newsletters.
- **eCommerce sellers** — spot product trends seasonally and by region.
- **YouTubers** — track topic interest curves and breakout terms.
- **Market researchers** — measure category-level interest shifts.
- **Affiliate marketers** — score keyword baskets for prioritization.

---

### Popular trend monitoring use cases

- **Rising keyword alerts** - run weekly to find topics gaining search interest before competitors react.
- **Breakout topic discovery** - surface keywords and related queries with sudden Google Trends momentum.
- **SEO opportunity scoring** - rank keyword baskets by TrendPulse Score, growth, and confidence.
- **YouTube topic validation** - check if video ideas are rising, stable, volatile, or declining.
- **eCommerce demand monitoring** - compare product categories and seasonal keywords by country.
- **Newsletter and content brief planning** - turn rising queries into timely editorial angles.

---

### Features

- ✅ Bulk input via array, textarea, or comma-separated text
- ✅ Country / language / time-range / category support
- ✅ Composite **TrendPulse Score** with transparent weights
- ✅ Rising, breakout, declining, volatile, stable classification
- ✅ Related queries, rising queries, related topics, breakout terms
- ✅ Deterministic content-angle suggestions (no LLM cost)
- ✅ Per-keyword recommended action
- ✅ **Five fetch modes** — SerpApi (recommended), Apify scraper, direct HTTP, browser, auto
- ✅ Retries with exponential backoff + jitter
- ✅ Per-keyword error isolation — one failure does not kill the run
- ✅ Clean summary + key-value outputs for downstream automation

---

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `keywords` | string[] | — | Keyword list (array form) |
| `keywordsText` | string | — | One keyword per line or comma-separated |
| `geo` | string | `"US"` | Google Trends geo code (`US`, `GB`, `FR`, `MA`, ... — empty for Worldwide) |
| `language` | string | `"en"` | Language code |
| `timeRange` | enum | `"today 12-m"` | `now 7-d` / `today 1-m` / `today 3-m` / `today 12-m` / `today 5-y` |
| `category` | string | `"0"` | Google Trends category ID |
| `includeRelatedQueries` | boolean | `true` | Fetch top + rising related queries |
| `includeRelatedTopics` | boolean | `true` | Fetch related topics (entities) |
| `includeContentAngles` | boolean | `true` | Generate content-angle suggestions |
| `maxKeywords` | integer | `500` | Cap (1–10,000) |
| `requestDelayMs` | integer | `1000` | Delay between requests |
| `maxConcurrency` | integer | `3` | Parallel workers (1–10). |
| **`fetchMode`** | enum | `"serpapi"` | **`"serpapi"`** (recommended, BYO key) / `"apify-scraper"` (Starter+ plan) / `"auto"` / `"browser"` / `"http"` |
| **`serpApiKey`** | string (secret) | — | **Required when `fetchMode="serpapi"`.** Free SerpApi key — get one at [serpapi.com](https://serpapi.com). |
| `browserNavigationTimeoutMs` | integer | `60000` | Browser-mode only |
| `browserWarmupMs` | integer | `2000` | Browser-mode only |
| `proxyConfiguration` | object | — | Optional, only useful for non-SerpApi fetch modes |
| `debugMode` | boolean | `false` | Verbose logs |

At least one of `keywords` / `keywordsText` is required.

#### Example input (recommended — SerpApi mode)

```json
{
  "keywords": ["chatgpt", "claude ai", "ai agents", "vibe coding"],
  "geo": "US",
  "language": "en",
  "timeRange": "today 12-m",
  "fetchMode": "serpapi",
  "serpApiKey": "@SERPAPI_KEY",
  "includeRelatedQueries": true,
  "includeRelatedTopics": false,
  "maxConcurrency": 2
}
````

Notes:

- `"@SERPAPI_KEY"` references an [Apify Secret](https://docs.apify.com/platform/actors/development/programming-interface/environment-variables#secret-environment-variables) (recommended for production). For quick testing, paste the literal key string instead.
- One keyword → 1 SerpApi call (timeseries) + optionally 1 more call (related queries) + optionally 1 more call (related topics). Plan accordingly.

More examples in [`examples/`](examples/).

***

### Output

Every keyword produces one dataset row:

```json
{
  "keyword": "ai agents",
  "geo": "US",
  "language": "en",
  "timeRange": "today 12-m",
  "category": "0",
  "currentAverageInterest": 78.4,
  "previousAverageInterest": 32.1,
  "minInterest": 12,
  "maxInterest": 100,
  "latestInterest": 92,
  "growthPercentage": 144.2,
  "absoluteChange": 46.3,
  "momentumScore": 81,
  "volatilityScore": 22,
  "confidenceScore": 88,
  "trendPulseScore": 87.4,
  "trendStatus": "rising",
  "relatedQueries": ["ai agent framework", "best ai agents"],
  "risingQueries": ["ai agent framework"],
  "topQueries": ["best ai agents"],
  "relatedTopics": ["Artificial intelligence"],
  "breakoutTerms": [],
  "contentAngles": [
    "Add this keyword to your next content calendar.",
    "Target long-tail variants like: best ai agents."
  ],
  "recommendedAction": "Prioritize now",
  "dataPointsCount": 52,
  "source": "google-trends-serpapi",
  "fetchedAt": "2026-06-13T20:50:18.000Z",
  "warnings": [],
  "error": null
}
```

#### Key-value store outputs

- `SUMMARY` — aggregate stats (counts, average score, top opportunities)
- `TOP_RISING_KEYWORDS` — flagged `rising` / `breakout` keywords
- `TOP_DECLINING_KEYWORDS` — worst performers
- `RUN_METADATA` — input echo + timestamps
- `ERRORS` — per-keyword failures
- `OUTPUT` — convenience object combining the above

Default sort is `trendPulseScore DESC`, then `growthPercentage DESC`, then `confidenceScore DESC`.

***

### How TrendPulse Score works

The TrendPulse Score is a 0–100 composite designed to surface the keywords most worth acting on right now.

```
trendPulseScore =
    growthComponent       * 0.35
  + momentumComponent     * 0.25
  + relatedDemandComponent* 0.15
  + breakoutComponent     * 0.10
  + confidenceComponent   * 0.10
  - volatilityPenalty     * 0.05
```

All sub-components are normalized to 0–100 before weighting. The result is clamped to `[0, 100]`. Weights are intentionally simple, transparent, and tunable in [`src/scoring.ts`](src/scoring.ts).

| Component | What it measures |
|---|---|
| Growth | Current-period vs. previous-period interest |
| Momentum | Slope of the most recent half of the series |
| Related demand | Volume + freshness of related/rising queries |
| Breakout | 100 if Google flagged a rising query as "Breakout", else 0/70 |
| Confidence | Data density + signal strength vs. noise floor |
| Volatility (penalty) | Coefficient of variation across the series |

***

### Use cases

- **Weekly SEO brief** — schedule a daily/weekly Apify run to detect rising keywords.
- **Trend dashboards** — pipe `SUMMARY` into Looker / Sheets via the Apify API.
- **Editorial calendar** — sort by `trendPulseScore`, filter by `trendStatus = rising | breakout`.
- **Inventory planning** — pair eCommerce SKUs with regional `geo` runs.
- **Newsletter curation** — promote breakout terms in your "what's rising" section.

***

### Limitations

- Google Trends interest scores are **normalized estimates** — they are relative, not absolute search volumes.
- Scores may vary by region, time range, and category. Compare like-for-like.
- In SerpApi mode, your free tier is **100 searches/month**. Each keyword consumes 1 search (timeseries) + 1 per related-data block you enable.
- Some keywords return insufficient data — those rows are still pushed with `trendStatus: "insufficient_data"`.
- Related queries / topics availability depends on Google Trends' own data quality per region.

***

### Fetch modes

The Actor supports five ways to pull Google Trends data. Pick one with `fetchMode`:

| Mode | Reliability | Cost | When to use |
|---|---|---|---|
| **`serpapi`** *(default)* | ✅ High | Free tier 100/mo, then ~$0.01/search | **Recommended.** Works on any Apify plan. Just paste your free SerpApi key. |
| `apify-scraper` | ✅ High | ~$0.0001–0.0003/result + Apify Starter+ plan | Calls `apify/google-trends-scraper` under the hood. Requires Apify **Starter** or higher plan. |
| `auto` | ⚠ Mixed | Apify Proxy bandwidth | Tries HTTP first, falls back to Playwright browser. Works only with a strong residential proxy. |
| `browser` | ⚠ Mixed | Apify Proxy bandwidth | Playwright Chromium. Slow (~8–15s/keyword). Works only with a strong residential proxy. |
| `http` | ❌ Often blocked | Apify Proxy bandwidth | Fastest, but Google rate-limits aggressively unless you have premium residential. |

**For first-time setup, use `serpapi`** — it's the only mode that works reliably on Apify's Creator plan and across all proxy configurations.

***

### FAQ

**Q: Why does the same keyword score differently across runs?**
A: Google Trends interest is normalized within the requested window, geo, and category. Changing any of those changes the baseline.

**Q: Can I export to CSV / Excel?**
A: Yes — Apify's dataset UI exports CSV, JSON, XLSX, HTML, RSS, and XML out of the box.

**Q: Do I need a SerpApi key?**
A: Only if you use `fetchMode: "serpapi"` (the default and recommended mode). Free tier covers 100 searches/month. Get one at [serpapi.com](https://serpapi.com).

**Q: Can I use this Actor without paying anyone other than Apify?**
A: Yes — pick `fetchMode: "apify-scraper"` and run on an Apify Starter plan or higher. Apify charges you per upstream result instead of SerpApi.

**Q: How is my SerpApi key handled?**
A: It's flagged as `isSecret: true` in the input schema — Apify masks it in the UI and never displays it in run logs. Our code logs only request metadata (keyword, geo, time range), never the key itself.

**Q: Is mock data ever used in production?**
A: No. Mock data only runs when both `debugMode = true` AND `useMockData = true`.

**Q: Can I run 10,000 keywords?**
A: Yes — set `maxKeywords` up to 10,000. In SerpApi mode that's 10,000+ searches; plan your SerpApi billing accordingly.

***

### Troubleshooting

#### SerpApi 401 / 403

Your `serpApiKey` is missing, invalid, or expired.

- Confirm the key at [serpapi.com/manage-api-key](https://serpapi.com/manage-api-key)
- If you exposed it anywhere, **regenerate it** on that page and update your input or Apify Secret
- For Apify Secrets, paste the new key into Console → **Account → Secrets → SERPAPI\_KEY**, then reference it as `"@SERPAPI_KEY"` in the input

#### SerpApi 429 (rate-limited)

You've consumed your monthly search quota or you're spiking too fast.

- Check your usage at [serpapi.com/manage-api-key](https://serpapi.com/manage-api-key) (free tier = 100/mo)
- Wait until next billing cycle, upgrade your SerpApi plan, or switch to `fetchMode: "apify-scraper"` (which needs Apify Starter+ plan)

#### All keywords return `insufficient_data`

The timeseries came back too short (< 4 points).

- Widen `timeRange` (`today 12-m` or `today 5-y`) — niche terms have very sparse 7-day data.
- Check `warnings` field on the dataset rows for the underlying cause.
- Verify the keywords aren't misspelled — Google Trends does not auto-correct.

#### Trying non-SerpApi fetch modes and hitting 429 / blocked

Google Trends aggressively rate-limits direct scraping. If `auto`, `browser`, or `http` modes consistently return 429:

- This is expected on most Apify proxy plans. **Switch to `fetchMode: "serpapi"`** — that's why it's the default.
- If you must use direct scraping, use a premium third-party residential proxy (Bright Data, Oxylabs, IPRoyal) via `proxyConfiguration.proxyUrls`.

***

### Pricing recommendation (Store listing)

Each keyword produces exactly **one dataset row**, which makes this Actor a clean fit for **pay-per-result** monetization on the Apify Store.

**Suggested seller price**: **$0.50 per 1,000 dataset rows**.
**Suggested free quota**: first 100 results/month free (trial).

How the math works:

- In `serpapi` mode the buyer pays their own SerpApi cost (~$10 per 1,000 keywords after the free tier).
- In `apify-scraper` mode the buyer pays their own upstream Apify event cost (~$0.10–$0.30 per 1,000 results).
- Your per-result fee on top covers your dev time + the scoring/ranking value.

Per-event (PPE) billing hooks are not enabled by default. If you want to switch from pay-per-result to PPE, isolate the hook in a new `src/monetization.ts` and call it after `pushResult()`.

***

### Legal / compliance

This Actor collects **publicly accessible** Google Trends interest data only. It does **not**:

- bypass logins or paywalls
- scrape private user data
- evade captchas with credential-grade techniques

Use it in line with Google's Terms of Service and Apify's Store quality standards. Interest scores are **normalized estimates** and should not be presented as exact search volumes.

***

### Changelog

See [CHANGELOG.md](CHANGELOG.md).

# Actor input Schema

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

List of keywords to analyze. You can also paste keywords as text in the next field.

## `keywordsText` (type: `string`):

Paste one keyword per line, or comma-separated. Useful for bulk uploads (hundreds to thousands).

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

Google Trends geo code (e.g. US, GB, CA, AU, MA, FR, DE). Use an empty string for Worldwide.

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

Language code (e.g. en, fr, es, de).

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

Google Trends time window.

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

Google Trends category ID (default '0' = all categories).

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

Fetch top + rising related queries for each keyword.

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

Fetch related topics (entities) for each keyword.

## `includeContentAngles` (type: `boolean`):

Generate deterministic content angle suggestions based on trend status and related queries.

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

Maximum number of keywords to process. Excess keywords are truncated with a warning.

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

Delay between requests to avoid rate limiting. Recommended: 800–2000ms.

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

Number of keywords processed in parallel. Keep low (1–4) to avoid 429 errors.

## `fetchMode` (type: `string`):

How to fetch Google Trends data. 'serpapi' (recommended): bring your own free SerpApi key — works on any Apify plan, no proxy fight. 'apify-scraper': calls Apify's official google-trends-scraper Actor (requires Apify Starter+ plan). Other modes scrape directly and require working proxy access.

## `serpApiKey` (type: `string`):

Required when fetchMode is 'serpapi'. Get a free key (100 searches/month) at https://serpapi.com. Your key is never logged.

## `browserNavigationTimeoutMs` (type: `integer`):

Per-keyword navigation timeout in browser mode. Increase for slow proxies.

## `browserWarmupMs` (type: `integer`):

Extra dwell time after page load to let late XHRs fire. Increase if related-queries are missed.

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

Use Apify Proxy (recommended: residential or Google SERP groups for best reliability).

## `useMockData` (type: `boolean`):

If true AND debugMode is true, use synthetic data instead of fetching Google Trends. Useful for testing the pipeline.

## `debugMode` (type: `boolean`):

Enable verbose logging.

## Actor input object example

```json
{
  "keywords": [
    "chatgpt",
    "claude ai",
    "ai agents",
    "vibe coding"
  ],
  "geo": "US",
  "language": "en",
  "timeRange": "today 12-m",
  "category": "0",
  "includeRelatedQueries": true,
  "includeRelatedTopics": true,
  "includeContentAngles": true,
  "maxKeywords": 500,
  "requestDelayMs": 1000,
  "maxConcurrency": 3,
  "fetchMode": "serpapi",
  "browserNavigationTimeoutMs": 60000,
  "browserWarmupMs": 2000,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "useMockData": false,
  "debugMode": false
}
```

# Actor output Schema

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

One row per keyword: TrendPulse score, trend status, growth, related queries, content angles.

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

Aggregate stats — totals, average TrendPulse score, top opportunities, top decliners.

## `topRising` (type: `string`):

Keywords flagged as rising or breakout.

## `topDeclining` (type: `string`):

Keywords flagged as declining.

## `errors` (type: `string`):

Keywords that failed, with their error messages.

# 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": [
        "chatgpt",
        "claude ai",
        "ai agents",
        "vibe coding"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("groupoject/trendpulse-keyword-monitor").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": [
        "chatgpt",
        "claude ai",
        "ai agents",
        "vibe coding",
    ],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("groupoject/trendpulse-keyword-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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": [
    "chatgpt",
    "claude ai",
    "ai agents",
    "vibe coding"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call groupoject/trendpulse-keyword-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=groupoject/trendpulse-keyword-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Google Trends Keyword Monitor & Rising Trend Finder",
        "description": "Bulk Google Trends keyword monitoring, rising keyword detection, and SEO opportunity scoring.",
        "version": "1.0",
        "x-build-id": "KBGvs5qj2Gw5JE37i"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/groupoject~trendpulse-keyword-monitor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-groupoject-trendpulse-keyword-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/groupoject~trendpulse-keyword-monitor/runs": {
            "post": {
                "operationId": "runs-sync-groupoject-trendpulse-keyword-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/groupoject~trendpulse-keyword-monitor/run-sync": {
            "post": {
                "operationId": "run-sync-groupoject-trendpulse-keyword-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "keywords": {
                        "title": "Keywords",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "List of keywords to analyze. You can also paste keywords as text in the next field.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "keywordsText": {
                        "title": "Keywords as text",
                        "type": "string",
                        "description": "Paste one keyword per line, or comma-separated. Useful for bulk uploads (hundreds to thousands)."
                    },
                    "geo": {
                        "title": "Country / Geo",
                        "type": "string",
                        "description": "Google Trends geo code (e.g. US, GB, CA, AU, MA, FR, DE). Use an empty string for Worldwide.",
                        "default": "US"
                    },
                    "language": {
                        "title": "Language",
                        "type": "string",
                        "description": "Language code (e.g. en, fr, es, de).",
                        "default": "en"
                    },
                    "timeRange": {
                        "title": "Time range",
                        "enum": [
                            "now 7-d",
                            "today 1-m",
                            "today 3-m",
                            "today 12-m",
                            "today 5-y"
                        ],
                        "type": "string",
                        "description": "Google Trends time window.",
                        "default": "today 12-m"
                    },
                    "category": {
                        "title": "Category",
                        "type": "string",
                        "description": "Google Trends category ID (default '0' = all categories).",
                        "default": "0"
                    },
                    "includeRelatedQueries": {
                        "title": "Include related queries",
                        "type": "boolean",
                        "description": "Fetch top + rising related queries for each keyword.",
                        "default": true
                    },
                    "includeRelatedTopics": {
                        "title": "Include related topics",
                        "type": "boolean",
                        "description": "Fetch related topics (entities) for each keyword.",
                        "default": true
                    },
                    "includeContentAngles": {
                        "title": "Include content angle suggestions",
                        "type": "boolean",
                        "description": "Generate deterministic content angle suggestions based on trend status and related queries.",
                        "default": true
                    },
                    "maxKeywords": {
                        "title": "Max keywords",
                        "minimum": 1,
                        "maximum": 10000,
                        "type": "integer",
                        "description": "Maximum number of keywords to process. Excess keywords are truncated with a warning.",
                        "default": 500
                    },
                    "requestDelayMs": {
                        "title": "Request delay (ms)",
                        "minimum": 0,
                        "maximum": 10000,
                        "type": "integer",
                        "description": "Delay between requests to avoid rate limiting. Recommended: 800–2000ms.",
                        "default": 1000
                    },
                    "maxConcurrency": {
                        "title": "Max concurrency",
                        "minimum": 1,
                        "maximum": 10,
                        "type": "integer",
                        "description": "Number of keywords processed in parallel. Keep low (1–4) to avoid 429 errors.",
                        "default": 3
                    },
                    "fetchMode": {
                        "title": "Fetch mode",
                        "enum": [
                            "serpapi",
                            "apify-scraper",
                            "auto",
                            "browser",
                            "http"
                        ],
                        "type": "string",
                        "description": "How to fetch Google Trends data. 'serpapi' (recommended): bring your own free SerpApi key — works on any Apify plan, no proxy fight. 'apify-scraper': calls Apify's official google-trends-scraper Actor (requires Apify Starter+ plan). Other modes scrape directly and require working proxy access.",
                        "default": "serpapi"
                    },
                    "serpApiKey": {
                        "title": "SerpApi API key",
                        "type": "string",
                        "description": "Required when fetchMode is 'serpapi'. Get a free key (100 searches/month) at https://serpapi.com. Your key is never logged."
                    },
                    "browserNavigationTimeoutMs": {
                        "title": "Browser navigation timeout (ms)",
                        "minimum": 5000,
                        "maximum": 300000,
                        "type": "integer",
                        "description": "Per-keyword navigation timeout in browser mode. Increase for slow proxies.",
                        "default": 60000
                    },
                    "browserWarmupMs": {
                        "title": "Browser warm-up dwell (ms)",
                        "minimum": 0,
                        "maximum": 60000,
                        "type": "integer",
                        "description": "Extra dwell time after page load to let late XHRs fire. Increase if related-queries are missed.",
                        "default": 2000
                    },
                    "proxyConfiguration": {
                        "title": "Proxy configuration",
                        "type": "object",
                        "description": "Use Apify Proxy (recommended: residential or Google SERP groups for best reliability)."
                    },
                    "useMockData": {
                        "title": "Use mock data (debug only)",
                        "type": "boolean",
                        "description": "If true AND debugMode is true, use synthetic data instead of fetching Google Trends. Useful for testing the pipeline.",
                        "default": false
                    },
                    "debugMode": {
                        "title": "Debug mode",
                        "type": "boolean",
                        "description": "Enable verbose logging.",
                        "default": false
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
