# Keyword Research — Search Volume, CPC & Ideas (`cheapapi/keyword-research-tool`) Actor

Google keyword search volume, CPC, competition & 12-month trends, plus keyword ideas, website keywords, difficulty and search intent. Pay per keyword.

- **URL**: https://apify.com/cheapapi/keyword-research-tool.md
- **Developed by:** [CheapAPI](https://apify.com/cheapapi) (community)
- **Categories:** SEO tools, Marketing, AI
- **Stats:** 21 total users, 14 monthly users, 87.3% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event + usage

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Keyword Research — Search Volume, CPC, Keyword Ideas & Difficulty

Get exact monthly Google search volume, CPC, competition, keyword difficulty, search intent and a 12-month trend for up to 10,000 keywords per run in 249 countries. You can also switch modes to find keyword ideas, keywords for any website, years of monthly history or **AI search volume**. You don't need an API key or a Google Ads account, and a keyword checked without a usable result costs only $0.0002.

### Why this Actor

- **10 keyword research modes in one Actor**: search volume, keyword ideas, long-tail suggestions, related keywords, keywords for a website, keyword difficulty, search intent, full keyword overview, historical data (up to about 4 years) and AI search volume. You don't need a separate tool for each job.
- **More data per keyword at no extra cost**: the default search volume row has 26 fields. Besides volume, CPC, low/high bids and competition you get **keyword difficulty (0–100), search intent and month-over-month, 3-month and year-over-year trend %** for every keyword served from the keyword database (the default). Many per-keyword tools return volume and CPC only.
- **Low price for small lists, fair price for large ones**: 10 keywords cost **$0.027** and 1,000 keywords cost **$1.23 on the Free plan ($0.63 on Gold)**, with difficulty and intent included (Apify platform usage is billed separately, usually $0.001–$0.005 for a small run). For a full 1,000-keyword list we are **not** the cheapest: batch-priced Actors cost $0.70–$1.99 on Free ($0.35–$0.40 on Gold), and a seed-suggestion Actor charges $1.00 per 1,000 rows. See the comparison below.
- **Exact numbers you can use right away**: volumes are exact numbers (not bands or ranges), and CPC and bids are numbers in USD (not text), so you can sort and filter them in a spreadsheet right away.

### Compared with alternatives

Typical run: **search volume for your own list of 10 or 1,000 keywords**. Prices are Actor fees per the public Apify Store listings, checked September 2026; user counts are rounded. "—" means the listing does not offer or state it.

| Option | 10 keywords, Free | 1,000 keywords, Free | 1,000 keywords, Gold | Billing (Free plan) | Difficulty + intent |
|---|---|---|---|---|---|
| Most-used keyword volume Actor (~1,200 users) | $0.12 | $12.00 | $8.00 | $0.012 per keyword | — |
| Flat-batch volume Actor (~790 users) | $1.99 | $1.99 | $0.40 | $1.99 per batch of up to 1,000 keywords | — |
| Batch-priced Google + Bing volume Actor (~400 users) | $0.70 | **$0.70** | **$0.35** | $0.20 per run + $0.50 per batch of up to 1,000 keywords | intent only |
| Per-keyword Actor with optional enrichment (~240 users) | $0.021 | $2.00 ($3.00 with difficulty + intent) | $1.60 ($2.40) | $0.001 per run + $0.002 per keyword, + $0.001 per keyword for difficulty/intent | paid add-on |
| **This Actor** | **$0.027** | $1.23 | $0.63 | $0.0145 per data request + $0.0012 per keyword with data | ✓ included |

What this means:

- **Small and medium lists**: this Actor is the cheapest option with difficulty and intent, because it has no per-run or per-batch minimum.
- **A full 1,000-keyword list**: we are **not** the cheapest. On the Free plan the batch-priced Google + Bing Actor costs $0.70 (and also returns Bing volume, which we do not); on Gold both batch-priced Actors ($0.35 and $0.40) cost less than our $0.63. They do not include keyword difficulty or the 3-month and year-over-year trend %.
- **Platform usage**: for this Actor, Apify platform usage is billed separately on top of the prices above (at the default 256 MB a small run typically uses about $0.001–$0.005).

**Keyword ideas from seed keywords** (1,000 idea rows, Free plan):

| Option | 1,000 ideas | Difficulty + intent | Notes |
|---|---|---|---|
| Seed-suggestion Actor, volume/CPC/intent (~270 users) | **$1.00** | intent only | $0.001 per suggestion; platform usage also billed to the user |
| Seed-suggestion Actor with difficulty (~530 users) | $3.00 | ✓ | $0.003 per keyword; one seed and up to 500 keywords per run |
| **This Actor** (*Keyword ideas* mode) | $2.01 | ✓ included | $0.0145 per page of up to 1,000 ideas + $0.002 per idea |

For plain idea lists without difficulty, the $1.00 Actor is cheaper than this one. Those two Actors expand seed keywords into suggestions; their listings do not describe looking up metrics for a list of your own keywords.

### Not included

- **Bing, YouTube or Amazon volume**: this Actor returns Google data only.
- **Live Google search results (rankings, snippets, ads)**: use [Google SERP Scraper](https://apify.com/cheapapi/google-serp-scraper).
- **Visibility of a brand in AI answers** (ChatGPT, Perplexity, AI Overviews): use [AI Search Visibility Tracker](https://apify.com/cheapapi/ai-search-visibility-tracker). This Actor's AI search volume shows demand, not who gets cited.
- **Backlinks and domain authority**: use [Backlink Checker](https://apify.com/cheapapi/backlink-checker) or [Domain SEO Analyzer](https://apify.com/cheapapi/domain-seo-analyzer).
- **Technical on-page audits**: use [SEO Site Audit](https://apify.com/cheapapi/seo-site-audit).
- **YouTube keyword ideas**: use [YouTube Search Scraper](https://apify.com/cheapapi/youtube-search-scraper) to see what ranks for a query on YouTube.

### What data you get

Search volume mode (default), one row per keyword:

| Field | Type | Example |
|---|---|---|
| `id` | string | `"0f02f3bb0cfda02f"` (stable: same keyword, mode and market give the same id in every run) |
| `keyword` | string | `"running shoes"` |
| `searchVolume` | integer | `246000` (average monthly Google searches) |
| `cpc` | number | `1.12` (average cost-per-click, USD) |
| `competition` | string | `"HIGH"` (`LOW` / `MEDIUM` / `HIGH`, paid competition) |
| `competitionIndex` | integer | `100` (0–100) |
| `lowBid` / `highBid` | number | `0.61` / `2.07` (top-of-page bid range, USD) |
| `keywordDifficulty` | integer | `71` (0–100, how hard it is to rank organically) |
| `searchIntent` | string | `"commercial"` (informational, navigational, commercial, transactional) |
| `secondaryIntents` | array | `["transactional"]` |
| `trendMonthlyPct` / `trendQuarterlyPct` / `trendYearlyPct` | number | `-18` / `22` / `0` (% change) |
| `monthlyTrend` | array | `[{ "year": 2026, "month": 8, "searchVolume": 201000 }, …]` oldest first |
| `coreKeyword` | string | `null` or the main keyword of its synonym group |
| `wordCount` | integer | `2` |
| `detectedLanguage` | string | `"en"` (estimated from the keyword text, not the market; one-word keywords can get another language — the market language is `languageCode`) |
| `categoryIds` | array | `[10021, 10178]` (Google product category ids) |
| `lastUpdated` | string | `"2026-09-16 03:19:59 +00:00"` (when the metrics were refreshed) |
| `mode`, `country`, `languageCode`, `locationCode`, `dataSource`, `scrapedAt` | context | `"searchVolume"`, `"US"`, `"en"`, `2840`, `"database"`, ISO timestamp |

Other modes add or swap fields:

| Mode | Extra fields |
|---|---|
| Idea modes | `seedKeyword`; related keywords add `depth` and `relatedKeywords` |
| Keywords for a website | `website`, `concepts` (keyword groups), `spellingCorrection` when present |
| Keyword difficulty | `keywordDifficulty` only (plus context) |
| Search intent | `searchIntent`, `intentProbability`, `secondaryIntents` with probabilities |
| Keyword overview | `topResultsAvgBacklinks`, `topResultsAvgReferringDomains`, `topResultsAvgRank`, `topResultsAvgDomainRank`, normalized volume estimates |
| Historical data | `monthsOfHistory`, `firstMonth`, `lastMonth`, `history` (monthly volume, CPC, competition, bids) |
| AI search volume | `aiSearchVolume`, `aiTrendMonthlyPct`, `aiTrendQuarterlyPct`, `aiMonthlyTrend` |
| Optional add-ons | `serpFeatures`, `serpResultsCount`, `serpUrl`, `serpLastUpdated` (search results info); `demographics` (age and gender) |

The **RUN_SUMMARY** record in the key-value store lists:

- keywords that had no data
- keywords that were not found
- skipped keywords
- any problems
- why the run stopped (result cap or budget)
- the events that were charged

### How to use

1. Open the Actor in the Apify Console and go to the **Input** tab.
2. Paste your keywords into **Keywords**, one per line (or keep the prefilled examples).
3. Pick a **Country**. Leave **Language** empty to use the country's main language.
4. Optional: change **What do you want?** to another mode, for example *Keyword ideas* or *AI search volume*.
5. Click **Start**. Most runs finish in a few seconds.
6. Open the **Output** tab and export as CSV, Excel, JSON, XML or HTML, or pick the *Ads & bids*, *Trends* or *AI search volume* view.

Ready-to-paste input:

```json
{
  "mode": "searchVolume",
  "keywords": ["running shoes", "best coffee maker", "keyword research"],
  "country": "US"
}
```

Keyword ideas with filters (easy, high-volume ideas):

```json
{
  "mode": "keywordIdeas",
  "keywords": ["coffee maker"],
  "country": "GB",
  "maxIdeasPerSeed": 300,
  "minSearchVolume": 50,
  "maxKeywordDifficulty": 30,
  "sortBy": "searchVolumeDesc"
}
```

Keywords for a website:

```json
{ "mode": "websiteKeywords", "websites": ["example.com"], "country": "US" }
```

#### API: curl

```bash
curl -X POST "https://api.apify.com/v2/acts/cheapapi~keyword-research-tool/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"keywords": ["running shoes", "best coffee maker"], "country": "US"}'
```

#### API: JavaScript (`apify-client`)

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_TOKEN>' });
const run = await client.actor('cheapapi/keyword-research-tool').call({
    keywords: ['running shoes', 'best coffee maker'],
    country: 'US',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const k of items) console.log(k.keyword, k.searchVolume, k.cpc, k.keywordDifficulty);
```

#### API: Python (`apify-client`)

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_TOKEN>")
run = client.actor("cheapapi/keyword-research-tool").call(run_input={
    "keywords": ["running shoes", "best coffee maker"],
    "country": "US",
})
for k in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(k["keyword"], k["searchVolume"], k["cpc"], k.get("keywordDifficulty"))
```

### Use cases

- **SEO content planning**: find long-tail ideas with volume, difficulty and intent. Then filter for easy informational keywords to write about.
- **PPC budgeting**: get CPC, top-of-page bid ranges and competition for thousands of keywords before you build a Google Ads campaign.
- **Competitor research**: list the keywords a competitor's domain or landing page is relevant for.
- **Market and product research**: compare demand for products across countries. Track seasonality with 12 months (or up to about 4 years) of monthly volume.
- **AI search / GEO planning**: see which topics people ask AI assistants about and how that demand is trending, next to classic Google volume.
- **Rank tracking and reporting**: add fresh metrics to your keyword lists in dashboards or Google Sheets every month.

### Modes

| Mode (`mode`) | Input | One row per |
|---|---|---|
| `searchVolume` (default) | your keywords | keyword: volume, CPC, competition, trend, difficulty and intent |
| `keywordIdeas` | seed keywords (combined) | new keyword idea |
| `keywordSuggestions` | seed keywords | long-tail phrase containing the seed |
| `relatedKeywords` | seed keywords | related keyword ("people also search for"), with depth and neighbours |
| `websiteKeywords` | `websites` (domains or URLs) | keyword relevant to the site |
| `keywordDifficulty` | your keywords | keyword with a 0–100 difficulty |
| `searchIntent` | your keywords | keyword with main and secondary intents and probabilities |
| `keywordOverview` | your keywords | keyword with every available metric |
| `historicalData` | your keywords | keyword with its monthly history |
| `aiSearchVolume` | your keywords | keyword with its estimated monthly AI search volume and 12-month trend |

### Advanced options

Every option has a working default. You only need the simple fields above.

| Option | Default | What it does |
|---|---|---|
| `language` | main language of the country | ISO code (`en`, `de`, `zh-TW`) or English name (`German`). |
| `websites` | – | Domains or page URLs for the *Keywords for a website* mode. |
| `websiteScope` | `site` | `site` = whole domain, `page` = only the exact URL. |
| `dataSource` | `auto` | Search volume mode only. `auto` reads the keyword database (fast, refreshed monthly, includes difficulty and intent). It fetches missing keywords live from the Google Ads keyword planner when the run is large enough. `database` = database only. `realtime` = always the live keyword planner. |
| `locationCode` | – | Google Ads geo-target code for a city or region (e.g. `1023191` = New York). Overrides Country. |
| `locationName` | – | Location in Google Ads format, e.g. `London,England,United Kingdom`. Overrides Country. |
| `coordinates` | – | `"latitude,longitude"` to measure searches around a point (real-time only). |
| `processingSpeed` | `auto` | `fast` or `economy` (queued, 1–3 hours) for real-time lookups and website keywords. The price is the same at every speed. |
| `includeMonthlyTrend` | `true` | Adds `monthlyTrend` (`aiMonthlyTrend` in the AI mode). |
| `trendMonths` | `12` | Months kept in the trend (1–60). |
| `dateFrom` / `dateTo` | – | Custom trend range, up to 4 years back (real-time only). |
| `includeSearchPartners` | `false` | Also count Google search-partner sites (real-time and website modes). |
| `includeAdultKeywords` | `false` | Keep adult keywords (real-time and website modes). |
| `includeSerpInfo` | `false` | Adds search result features (featured snippet, local pack, …) and the result count (database modes). |
| `includeDemographics` | `false` | Adds age and gender of searchers (paid add-on; search volume, overview and idea modes). |
| `maxResults` | `5000` | Hard cap on rows for the whole run (1–100,000). |
| `deduplicate` | `true` | Idea modes: a keyword returned by several seeds is output and charged once. |
| `maxIdeasPerSeed` | `100` | Ideas per seed (1–10,000). In *Keyword ideas* mode it is the total. |
| `sortBy` | `relevance` | Relevance, volume, CPC, competition or difficulty order. |
| `relatedDepth` | `1` | Related keywords: 0–4 hops from the seed. |
| `includeSeedKeyword` | `false` | Suggestions and related modes: also output the seed itself. |
| `closelyRelatedOnly` | `false` | Keyword ideas: only ideas very close in meaning. |
| `exactMatch` | `false` | Suggestions: seed words in the same order. |
| `ignoreSynonyms` | `false` | Idea modes: skip word-order and plural variants. |
| `replaceWithCoreKeyword` | `false` | Related keywords: use the main keyword of each synonym group. |
| `offset` | `0` | Idea modes: skip the first N ideas (continue a previous run). |
| `minSearchVolume` / `maxSearchVolume` | – | Volume range (AI volume in the AI mode). |
| `minCpc` / `maxCpc` | – | CPC range in USD. |
| `minKeywordDifficulty` / `maxKeywordDifficulty` | – | Difficulty range 0–100 (idea modes). |
| `searchIntents` | – | Keep only these main intents (idea modes). |
| `mustContain` / `mustNotContain` | – | Keep or drop keywords containing a word or phrase. |

Each lookup is paid, so a keyword that is looked up but removed by a filter costs $0.0002 (keyword checked without a result) instead of a full result price. Setting a date range, search partners or city/coordinate targeting switches the search volume mode to real-time data. The log tells you when this happens.

### Example output

Search volume mode (input: `{"keywords": ["phone"], "country": "US", "trendMonths": 3}`), a real row:

```json
{
  "id": "0f02f3bb0cfda02f",
  "keyword": "phone",
  "searchVolume": 673000,
  "cpc": 4.63,
  "competition": "HIGH",
  "competitionIndex": 76,
  "lowBid": 2.92,
  "highBid": 8,
  "keywordDifficulty": 54,
  "searchIntent": "informational",
  "secondaryIntents": null,
  "trendMonthlyPct": 22,
  "trendQuarterlyPct": 50,
  "trendYearlyPct": 50,
  "monthlyTrend": [
    { "year": 2026, "month": 6, "searchVolume": 550000 },
    { "year": 2026, "month": 7, "searchVolume": 673000 },
    { "year": 2026, "month": 8, "searchVolume": 823000 }
  ],
  "coreKeyword": null,
  "wordCount": 1,
  "detectedLanguage": "th",
  "categoryIds": [10007, 10878, 12171],
  "lastUpdated": "2026-09-16 03:19:59 +00:00",
  "mode": "searchVolume",
  "country": "US",
  "languageCode": "en",
  "locationCode": 2840,
  "dataSource": "database",
  "scrapedAt": "2026-09-29T05:06:56.864Z"
}
```

`detectedLanguage` is `"th"` here because the keyword database estimates the language from the keyword text alone, and a single word like "phone" can be mis-detected. It does not affect the metrics: the volume, CPC and trend are for the market you chose (`country` US, `languageCode` en).

Keyword ideas mode (input: `{"mode": "keywordIdeas", "keywords": ["phone"], "country": "US", "trendMonths": 3}`), one idea row:

```json
{
  "id": "2a37305c4b49a8d2",
  "keyword": "nothing phone",
  "searchVolume": 165000,
  "cpc": 0.31,
  "competition": "HIGH",
  "competitionIndex": 92,
  "lowBid": 0.03,
  "highBid": 0.38,
  "keywordDifficulty": 31,
  "searchIntent": "informational",
  "secondaryIntents": null,
  "trendMonthlyPct": 22,
  "trendQuarterlyPct": 0,
  "trendYearlyPct": 174,
  "monthlyTrend": [
    { "year": 2026, "month": 6, "searchVolume": 301000 },
    { "year": 2026, "month": 7, "searchVolume": 246000 },
    { "year": 2026, "month": 8, "searchVolume": 301000 }
  ],
  "coreKeyword": "phones nothing",
  "wordCount": 2,
  "detectedLanguage": "en",
  "categoryIds": [10007, 10878, 12171],
  "lastUpdated": "2026-09-12 02:47:34 +00:00",
  "mode": "keywordIdeas",
  "country": "US",
  "languageCode": "en",
  "locationCode": 2840,
  "seedKeyword": "phone",
  "dataSource": "database",
  "scrapedAt": "2026-09-29T05:07:12.418Z"
}
```

AI search volume mode (input: `{"mode": "aiSearchVolume", "keywords": ["seo"], "country": "US", "trendMonths": 3}`):

```json
{
  "id": "e80f8ac5279cf3dc",
  "keyword": "seo",
  "aiSearchVolume": 77880,
  "aiTrendMonthlyPct": -16,
  "aiTrendQuarterlyPct": -34,
  "aiMonthlyTrend": [
    { "year": 2026, "month": 6, "aiSearchVolume": 86786 },
    { "year": 2026, "month": 7, "aiSearchVolume": 93165 },
    { "year": 2026, "month": 8, "aiSearchVolume": 77880 }
  ],
  "mode": "aiSearchVolume",
  "country": "US",
  "languageCode": "en",
  "locationCode": 2840,
  "dataSource": "aiSearch",
  "scrapedAt": "2026-09-29T05:06:38.126Z"
}
```

### Pricing

**Typical cost: $0.027 for 10 keywords and $1.23 for 1,000 keywords on the Free plan ($0.63 on Gold), plus Apify platform usage billed separately.**

**Apify Free plan:** Apify does not pay developers for usage on its Free plan, so on the Free plan this Actor can be used for up to **$0.25 of results per calendar month** — enough to try it on a small input. When the allowance is used up, the run ends with a clear message (not an error). Any paid Apify plan removes the limit; prices are the same.

Pay per event. **Every data request is charged when it is made, even if it finds nothing** (the lookup itself is paid). Keywords you receive are charged as results; keywords that were looked up but are not in your output (no data, removed by your filters, duplicates) cost a small check fee. Requests rejected with an error are free. A request that was sent but timed out before answering is still charged like a request without results (it may already have been processed); for a keyword database request the keywords it asked for are then charged the check fee. Your Apify plan's prices are applied automatically.

Apify platform usage is billed separately by Apify (at the default 256 MB a small run typically uses about $0.001–$0.005). The prices and worked examples below are event fees only.

| Event | Free, Bronze, Silver | Gold and above |
|---|---|---|
| Data request (per request made, even if nothing is found) | $0.0145 | $0.0151 |
| Keyword result (volume, overview, difficulty, intent, history, AI volume) | $0.0012 | $0.0006 |
| Keyword idea (ideas, suggestions, related, website modes) | $0.002 | $0.002 |
| Website analyzed (website mode, replaces the data-request fee; charged even if no keywords are found) | $0.12 | $0.12 |
| Audience demographics add-on (per row with demographics) | $0.005 | $0.005 |
| Real-time small batch fee (opt-in only, see below) | $0.10 | $0.10 |
| Keyword checked without a result (no data, filtered out or duplicate) | $0.0002 | $0.0002 |
| Request without results (added when a keyword database request outputs nothing) | $0.0009 | $0.0003 |

How much one data request covers:

- search volume, overview and history: up to 700 keywords
- difficulty, intent, AI search volume and real-time volume: up to 1,000 keywords
- idea modes: one page of up to 1,000 ideas

With demographics on, the data request, the check fee and the no-result fee are charged twice (the lookup costs twice as much). With demographics on, a request whose rows come back without any demographics also gets the no-result fee.

The **real-time small batch fee** applies only if you explicitly choose real-time data and a real-time request returns too few keywords with data to cover it: under 82 keywords on the Free, Bronze and Silver plans, or under 163 keywords on Gold and above. Real-time-only options such as a date range or city targeting count as choosing real-time data. The fee is never charged with the default settings.

Worked examples (default settings):

| Run | Free, Bronze, Silver | Gold and above |
|---|---|---|
| 1 keyword, search volume | $0.0157 | $0.0157 |
| 10 keywords, search volume | $0.027 | $0.021 |
| 1,000 keywords, search volume (2 requests) | $1.23 | $0.63 |
| 1,000 keywords, AI search volume (1 request) | $1.21 | $0.61 |
| 100 keyword ideas for one seed | $0.21 | $0.21 |
| 1 website with 500 keywords found | $1.12 | $1.12 |
| 1 website, no keywords found | $0.12 | $0.12 |
| 1 keyword not in the keyword database (nothing found) | $0.0154 | $0.0154 |
| 100 keywords, 60 with data, 40 returned without data | $0.0945 | $0.0591 |
| Real-time data, 10 keywords | $0.127 | $0.121 |

Set **Maximum cost per run** in the run options to cap spending. The Actor stops cleanly at the limit and keeps everything collected so far.

### Integrations

- **Make, Zapier, n8n**: use the Apify app to start a run and receive the rows in your scenario.
- **Google Sheets**: send the dataset to a sheet with the Apify Google Sheets integration, or import the CSV export link.
- **Webhooks**: get notified (or trigger your pipeline) when a run succeeds or fails.
- **Schedules**: re-run the same keyword list weekly or monthly to track demand over time.
- **API and MCP**: call the Actor from any language through the Apify API (examples above), or let AI agents use it through the Apify MCP server.

### FAQ

**Is there a Free-plan limit, and is platform usage included?** On the Apify Free plan you can use up to $0.25 of this Actor's results per calendar month, enough to try it (Apify pays developers nothing for Free-plan usage while our data costs are real). Runs that reach the allowance stop cleanly with a message and keep everything collected; the allowance resets on the 1st, and any paid plan has no limit. Apify platform usage (compute) is not included: it is billed separately by Apify, typically $0.001–$0.005 for a small run at the default 256 MB, and shown in the run details.

**How accurate and fresh is the data?** Volumes are the Google Ads keyword planner numbers advertisers see: average monthly searches, rounded the way Google rounds them, as exact numbers rather than bands. Keyword database metrics are refreshed monthly (each row's `lastUpdated` shows when); real-time data is fetched during your run; AI search volume covers the last 12 full months.

**What is the difference between database and real-time data, and can I target a city?** The keyword database is the default: fast, refreshed monthly, with difficulty and intent. Real-time data asks the Google Ads keyword planner during your run and supports custom date ranges, search partners and city targeting (`locationName` such as `London,England,United Kingdom`, `locationCode` or `coordinates`), but has no difficulty or intent. Keywords missing from the database are listed in RUN_SUMMARY (`keywordsNotFound`); look them up with `dataSource: "realtime"` in a second run. Real-time-only options switch the run to real-time data automatically.

**What is AI search volume?** A model-based estimate of how often a keyword or question is asked in AI assistants and AI search each month, with a 12-month trend. Use it next to Google volume to spot topics growing in AI search; it is not an exact count from each assistant.

**Why did I get fewer rows than keywords, and why was I charged for them?** Very rare keywords may have no data (listed in `keywordsWithoutData` / `keywordsNotFound`); filters, `maxResults`, deduplication and the maximum cost per run can also reduce rows. Every lookup is paid when it is made, so a request that outputs nothing costs the data request plus the no-result fee ($0.0154), and keywords returned without data, filtered out or duplicated cost $0.0002 each. A keyword that is not returned at all is free. In the website mode each analyzed website costs $0.12 even with no keywords, and opt-in real-time requests with fewer than 82 keywords with data (163 on Gold) add the $0.10 small-batch fee. RUN_SUMMARY lists every charged event.

**How do I control my budget?** Set **Maximum cost per run** in the run options. The Actor checks the remaining budget before every request, asks for no more keywords than it can pay for in the worst case, and stops cleanly when the next request would not fit. `maxResults` caps the number of rows.

**Can I monitor keywords every month?** Yes. Save your input as a task and add a monthly schedule (the keyword database is refreshed monthly). Every row has a stable `id` (same keyword, mode and market give the same `id` in every run) and a `scrapedAt` timestamp, so you can append runs to one sheet or table and compare rows with the same `id`.

**Do I need an API key or a Google Ads account?** No. Everything runs on our own data infrastructure.

**Is it legal?** The Actor returns aggregated keyword statistics (search counts, bids, difficulty), not personal data. You are responsible for using the results in line with your local laws and the terms of the services you use them with.

**Something does not work. Where do I get help?** Open an issue on the Actor's **Issues** tab and include your run ID. The run's RUN_SUMMARY record helps us find the cause quickly.

### Limitations

- Up to 10,000 keywords per run in per-keyword modes and 200 seed keywords in idea modes. Each keyword can be at most 80 characters and 10 words. Longer ones are skipped and listed in RUN_SUMMARY.
- Search volume is Google-only. Rare keywords may return no volume; they cost at most the $0.0002 check fee.
- Keyword difficulty, intent, overview, history, ideas and demographics come from the keyword database. They cover country-level locations and the major languages, not city targeting.
- Custom date ranges, search partners and city or coordinate targeting are real-time-only options, without difficulty or intent.
- AI search volume is an estimate with 12 months of history, so there is no year-over-year change for it.
- Demographics are not available for every keyword or country. Only rows that include them are charged.
- Economy processing can take 1–3 hours.

### Privacy

The output contains only aggregated, anonymous keyword statistics. The Actor does not collect names, emails or any other personal data. Audience demographics are aggregate age and gender shares, never individual users.

# Actor input Schema

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

Choose the kind of keyword research. <b>Search volume</b> returns metrics for exactly the keywords you enter. The idea modes treat your keywords as seeds and return new keywords. <b>Keywords for a website</b> uses the Websites field below. <b>AI search volume</b> estimates how often each keyword is asked in AI assistants and AI search, with a 12-month trend.

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

Required in every mode except <b>Keywords for a website</b>. One keyword or phrase per line (max 80 characters and 10 words each). In the search volume, difficulty, intent, overview, history and AI search volume modes you can enter up to 10,000 keywords. In the idea modes these are the seed keywords (up to 200).

## `country` (type: `string`):

Country whose searches are measured. City or region targeting is available under Advanced.

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

Optional. ISO language code such as <code>en</code>, <code>de</code>, <code>pt</code>, <code>zh-TW</code> (English names like "German" also work). Leave empty to use the main language of the country.

## `websites` (type: `array`):

Domains or page URLs, one per line, e.g. <code>example.com</code> or <code>https://example.com/blog/post</code>. Returns keywords relevant to the site with volume, CPC and competition. Each analyzed website is charged, even if no keywords are found.

## `websiteScope` (type: `string`):

Whether to look at the whole domain or only the given page.

## `dataSource` (type: `string`):

Used by the search volume mode. <b>Automatic</b> reads the keyword database; keywords missing from it are listed in the run summary (switches to real-time only for real-time-only options). <b>Real-time</b> always asks the keyword planner (needed for custom date ranges, search partners and coordinates); every real-time request is charged, and a request that returns under 82 keywords with data (163 on Gold) adds a small-batch fee.

## `locationCode` (type: `integer`):

Optional numeric Google Ads geo-target code for a city or region (e.g. 1023191 = New York). Overrides Country. City/region targeting works with real-time planner data and website keywords.

## `locationName` (type: `string`):

Optional full location name in Google Ads format, e.g. <code>London,England,United Kingdom</code>. Overrides Country.

## `coordinates` (type: `string`):

Optional "latitude,longitude" (e.g. <code>40.7128,-74.0060</code>) to measure searches around a point. Real-time planner only.

## `processingSpeed` (type: `string`):

Applies to real-time planner lookups and website keywords. The price is the same in every mode.

## `includeMonthlyTrend` (type: `boolean`):

Adds a <code>monthlyTrend</code> array (<code>aiMonthlyTrend</code> in the AI mode) with the search volume of each recent month.

## `trendMonths` (type: `integer`):

How many most-recent months to keep in the trend (the default planner range is 12 months; the keyword database keeps up to about 4 years; AI search volume has 12 months).

## `dateFrom` (type: `string`):

Real-time planner only: first month of the trend (YYYY-MM-DD, up to 4 years back). Setting a date switches the data source to real-time.

## `dateTo` (type: `string`):

Real-time planner only: last month of the trend (cannot be later than the last full month).

## `includeSearchPartners` (type: `boolean`):

Real-time planner and website keywords: count searches on Google search-partner sites too.

## `includeAdultKeywords` (type: `boolean`):

Real-time planner and website keywords: keep adult keywords in the results.

## `includeSerpInfo` (type: `boolean`):

Database modes: adds which result types appear on the Google results page (featured snippet, local pack, …) and the total number of results.

## `includeDemographics` (type: `boolean`):

Search volume (keyword database), overview and idea modes: adds age and gender distribution of searchers plus an alternative volume estimate. Charged as an extra event only for rows that come back with demographics; the data request (and any check/no-result fee) is charged twice because the lookup costs twice as much (see pricing).

## `maxResults` (type: `integer`):

Hard cap on the number of dataset rows for the whole run. The run stops cleanly when it is reached.

## `deduplicate` (type: `boolean`):

Idea modes: if several seeds return the same keyword it is output (and charged as a result) once; later copies cost the $0.0002 check fee.

## `maxIdeasPerSeed` (type: `integer`):

How many ideas to return for each seed keyword. In "Keyword ideas" mode all seeds are combined, so this is the total.

## `sortBy` (type: `string`):

Order in which ideas are selected and returned. Also used by the real-time planner (difficulty sorting falls back to relevance there).

## `relatedDepth` (type: `integer`):

Related keywords mode: how many hops away from the seed to explore (0 = seed only, 4 = widest, up to thousands of keywords).

## `includeSeedKeyword` (type: `boolean`):

Suggestions and related modes: also output a row for the seed keyword itself.

## `closelyRelatedOnly` (type: `boolean`):

Keyword ideas mode: return only ideas very close in meaning to the seeds.

## `exactMatch` (type: `boolean`):

Suggestions mode: only return phrases containing the seed words in the same order.

## `ignoreSynonyms` (type: `boolean`):

Idea modes: skip keywords that are only word-order or plural variants of another result.

## `replaceWithCoreKeyword` (type: `boolean`):

Related keywords mode: replace each keyword with the main keyword of its synonym group.

## `offset` (type: `integer`):

Idea modes: start from the N-th idea (useful to continue a previous run).

## `minSearchVolume` (type: `integer`):

Only keep keywords with at least this monthly search volume (AI search volume in the AI mode).

## `maxSearchVolume` (type: `integer`):

Only keep keywords with at most this monthly search volume (AI search volume in the AI mode).

## `minCpc` (type: `number`):

Only keep keywords with a cost-per-click (USD) of at least this amount, e.g. <code>0.5</code>.

## `maxCpc` (type: `number`):

Only keep keywords with a cost-per-click (USD) of at most this amount, e.g. <code>5</code>.

## `minKeywordDifficulty` (type: `integer`):

Idea modes: only keep keywords with difficulty ≥ this value (0–100).

## `maxKeywordDifficulty` (type: `integer`):

Idea modes: only keep keywords with difficulty ≤ this value (0–100). Great for finding easy wins.

## `searchIntents` (type: `array`):

Idea modes: only keep keywords with one of these main intents.

## `mustContain` (type: `string`):

Only keep keywords containing this word or phrase.

## `mustNotContain` (type: `string`):

Drop keywords containing this word or phrase.

## Actor input object example

```json
{
  "mode": "searchVolume",
  "keywords": [
    "running shoes",
    "best coffee maker",
    "keyword research"
  ],
  "country": "US",
  "websiteScope": "site",
  "dataSource": "auto",
  "processingSpeed": "auto",
  "includeMonthlyTrend": true,
  "trendMonths": 12,
  "includeSearchPartners": false,
  "includeAdultKeywords": false,
  "includeSerpInfo": false,
  "includeDemographics": false,
  "maxResults": 5000,
  "deduplicate": true,
  "maxIdeasPerSeed": 100,
  "sortBy": "relevance",
  "relatedDepth": 1,
  "includeSeedKeyword": false,
  "closelyRelatedOnly": false,
  "exactMatch": false,
  "ignoreSynonyms": false,
  "replaceWithCoreKeyword": false,
  "offset": 0
}
```

# Actor output Schema

## `keywords` (type: `string`):

No description

## `allFields` (type: `string`):

No description

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

No description

## `aiSearch` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "mode": "searchVolume",
    "keywords": [
        "running shoes",
        "best coffee maker",
        "keyword research"
    ],
    "country": "US",
    "dataSource": "auto"
};

// Run the Actor and wait for it to finish
const run = await client.actor("cheapapi/keyword-research-tool").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 = {
    "mode": "searchVolume",
    "keywords": [
        "running shoes",
        "best coffee maker",
        "keyword research",
    ],
    "country": "US",
    "dataSource": "auto",
}

# Run the Actor and wait for it to finish
run = client.actor("cheapapi/keyword-research-tool").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 '{
  "mode": "searchVolume",
  "keywords": [
    "running shoes",
    "best coffee maker",
    "keyword research"
  ],
  "country": "US",
  "dataSource": "auto"
}' |
apify call cheapapi/keyword-research-tool --silent --output-dataset

```

## MCP server setup

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

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/uetsC14hR5QbRafRg/builds/fCcIIRb6uMqaaQs73/openapi.json
