# Keyword Search Volume — Google CPC & Trends, Multi-Country (`saliga/keyword-search-volume`) Actor

Google search volume, CPC, competition and up to 48 months of trend for a keyword list, in up to 20 countries in one run: one row per keyword and country. Keyword ideas mode. Load keywords from a list, a file or another Actor's dataset. $3 per 1,000 keywords with data + $0.19 per lookup.

- **URL**: https://apify.com/saliga/keyword-search-volume.md
- **Developed by:** [Salih Küçükkayış](https://apify.com/saliga) (community)
- **Stats:** 4 total users, 3 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.10 / 1,000 keyword results

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

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

## What's an Apify Actor?

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

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

## How to integrate an Actor?

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

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

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

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

# README

Get Google keyword search volume, CPC, competition and trend for a list of keywords, in one country or in up to 20 countries in a single run: one row per keyword and country.

**$3 per 1,000 keywords with data** ($2.70, $2.40 and $2.10 on the Starter, Scale and Business plans), **plus $0.19 per lookup.** A lookup is one batch of up to 1,000 keywords in one country, charged whenever Google answers, even if no keyword in it has data. Keywords with no data and invalid keywords have no keyword fee, and failed lookups are free. No subscription, and platform usage is included. (Plus a tiny $0.00005 start fee per run.)

### What you get

- **Many countries in one run.** Give one keyword list and several countries (`["US", "GB", "DE"]`). You get one row per keyword and country, ready to pivot.
- **Real Google Ads figures.** Average monthly searches, CPC, competition level and index, and the top-of-page bid range, as an advertiser sees them in Keyword Planner. Nothing is modelled or estimated.
- **Up to 48 months of history.** Month-by-month search volume, with the 3-month trend, the peak month and, from 13 months up, the year-on-year change already worked out.
- **Keyword ideas.** Turn your keywords into new ones, most relevant first, with the same figures. Filter by minimum volume so you only pay for ideas worth having.
- **The keyword fee is only for answers.** A keyword Google has no figure for comes back marked `no_data`, with no keyword fee. The $0.19 lookup fee is charged for every lookup Google answers. If three lookups in a row return no data at all, the run stops so a wrong country or language does not keep costing you.
- **Bring keywords from anywhere.** Paste them, link a text, CSV or JSON file (a published Google Sheet works), or point to the dataset of another Actor.
- **Stops at your spending limit.** Set "Maximum cost per run" and the run never goes over it. Keywords it did not reach are listed, uncharged, so you can run just those next time.

### Typical uses

- **Compare markets before you expand.** One list, ten countries, one table: see where demand is.
- **Size a content plan.** Volume, trend and peak month for every topic on your list.
- **Plan ad budgets.** CPC and top-of-page bid ranges by country.
- **Enrich another Actor's output.** Point `datasetId` at a dataset of keywords and get the figures as new rows.

### Input

```json
{
  "keywords": ["project management software", "crm software"],
  "countries": ["US", "GB", "DE"],
  "mode": "volume",
  "historyMonths": 24
}
```

| Field | Meaning |
|---|---|
| `keywords` | Your keywords, up to 10,000 per run. Up to 80 characters and 10 words each (Google Ads limits). Duplicates are removed. |
| `countries` | One or more countries, up to 20 per run: two-letter codes (`US`, `GB`, `TR`) or names (`Germany`, `Deutschland`). Default `US`. |
| `mode` | `volume` (default), `ideas`, or `both`. |
| `language` | Optional language code (`en`, `de`, `es`, …). Empty means all languages in the country. |
| `historyMonths` | 12 to 48. Default 12. Only changes how many months `monthlySearches` holds: `searchVolume` is always Google's average over the last 12 months. |
| `maxIdeas`, `minIdeaVolume`, `maxIdeaSeeds` | Ideas modes only: how many ideas per country, the smallest volume worth returning, and how many of your keywords to use as seeds (20 per lookup). |
| `keywordsUrl`, `datasetId`, `keywordField` | Other ways to pass keywords, and the name of the column or field that holds them. |
| `maxKeywords` | Stop after this many keywords. |
| `includePartners`, `includeAdult` | Count Google search partners; ask for adult keywords. |

### Output

One row per keyword and country. Notes about the input itself (an invalid keyword, a country we could not place) are rows too, with an empty `country` or `keyword`.

| Field | Meaning |
|---|---|
| `keyword` | Your keyword, spelled the way you sent it |
| `country`, `language` | The market the figures are for |
| `searchVolume` | Average monthly searches over the last 12 months (Google's own figure) |
| `cpcUsd` | Average cost per click, in US dollars |
| `competition`, `competitionIndex` | `LOW` / `MEDIUM` / `HIGH`, and the 0 to 100 index behind it |
| `lowTopOfPageBidUsd`, `highTopOfPageBidUsd` | Top-of-page bid range |
| `monthlySearches` | `[{ "year": 2026, "month": 8, "searches": 12100 }, …]`, oldest month first |
| `trend3mPct` | Last 3 months against the 3 months before, in percent |
| `trendDirection` | `rising` (+15 % or more), `falling` (−15 % or less), otherwise `flat` |
| `trendYoYPct` | Latest month against the same month a year earlier (needs 13+ months of history) |
| `peakMonth` | The month (1 to 12) with the most searches in the last 12 months |
| `dataMonth` | The latest month Google reported, for example `2026-08` |
| `spellingCorrection` | Set when Google read the keyword as a different spelling; the figures are for that spelling |
| `type`, `seeds` | `keyword` for your own keywords; `idea` for suggestions, with the keywords they came from |
| `status`, `note` | `ok`, or why there is no figure (see below) |
| `charged` | `true` only on rows you paid for |
| `index` | Position of the keyword in your list (0-based), to sort results back into your order |

A run summary (counts, lookups, and why the run stopped) is saved as `SUMMARY` in the run's key-value store. If some keywords were not looked up, the dataset lists the first 1,000 of them and the full list, by country, is saved as `NOT_LOOKED_UP`, ready to paste into the next run.

#### Rows with no keyword fee

A `no_data` row still belongs to a lookup Google answered, so that lookup's fee is charged. All other rows below cost nothing.

| `status` | What happened |
|---|---|
| `no_data` | Google publishes no volume for this exact phrase in this country. Try the shorter head term. |
| `invalid_keyword` | Over 80 characters, over 10 words, or a symbol Google Ads does not accept (this includes `+`, so `c++` cannot be looked up). The note names the rule. |
| `input_error` | A country or language we could not place, or one the source has no data for. Nothing is guessed. |
| `spending_limit` | Your "Maximum cost per run" was reached before this keyword. |
| `free_plan_limit` | Past the free-plan allowance (see below). |
| `skipped` | Three lookups in a row returned no data at all, so the run stopped buying more. Check the keywords, country and language. |
| `throttled`, `provider_error` | The data source was busy or unavailable. Run those keywords again later. |

### Three things to know about Google's numbers

1. **Volumes are rounded.** Google reports search volume in steps (1,300, 1,600, 12,100, …), not exact counts.
2. **Close variants are grouped.** Two similar keywords can come back with the same combined figure.
3. **Some real phrases have no figure.** Long or very local phrases often return nothing, even when people search for them. Those rows carry no keyword fee.

Google updates these figures once a month, so running the same list more often than monthly returns the same numbers.

### Apify free plan

Every lookup costs us real money at the data source, and free-plan runs earn nothing. So on the Apify free plan this Actor gives one lookup a day for up to 10 keywords in one country, enough to see real data. Everything else in the run comes back as uncharged `free_plan_limit` rows. Any paid Apify plan has no such limits.

### Using it from an AI agent or code

The Actor works as a tool through the [Apify MCP server](https://mcp.apify.com?tools=saliga/keyword-search-volume) and through the Apify API. Send `{"keywords": [...], "countries": ["US"]}`. Every row has a `status`, so an agent can tell a keyword with no data from one that failed.

### Good to know

- The figures come from Google Ads Keyword Planner through a licensed data provider. You do not need a Google Ads account.
- This Actor is not affiliated with, endorsed by or sponsored by Google. "Google", "Google Ads" and "Keyword Planner" are trademarks of Google LLC.
- A run that is moved to another server, or resurrected, continues where it stopped. Nothing is looked up or charged twice.
- Pricing: one `keyword-result` charge per keyword row with data, one `lookup` charge per batch of up to 1,000 keywords in one country (keyword ideas are a separate lookup per 20 seed keywords), plus $0.00005 when a run starts.
- Questions or a missing feature: open an issue on the Actor page.

### What it costs

| Run | Price (no discount) |
|---|---|
| 100 keywords, 1 country | $0.49 |
| 1,000 keywords, 1 country | $3.19 |
| 1,000 keywords, 5 countries | $15.95 |

These assume every keyword has data. Keywords with no data have no keyword fee. On a paid Apify plan the keyword fee is 10 %, 20 % or 30 % lower.

### Why use this instead of checking country by country?

- **One run, many markets.** Up to 20 countries for the same list, each with its own row, instead of repeating the lookup for every market.
- **History and trend already worked out.** Up to 48 months per keyword, with the 3-month trend, year-on-year change and peak month as columns.
- **Pay for answers.** No keyword fee for keywords Google has no figure for.

### FAQ

**Do I need a Google Ads account?** No.

**Which countries are supported?** Most countries Google Ads targets. Use two-letter codes (`US`, `GB`, `TR`) or names. Unsupported ones come back as uncharged `input_error` rows.

**How fresh is the data?** Google updates it once a month. The `dataMonth` column shows the latest month in each row.

**Why do some keywords have no data?** Google publishes no figure for many long or very local phrases. Those rows are marked `no_data` and have no keyword fee. Try the shorter head term.

**Can I get keyword ideas?** Yes: set `mode` to `ideas` or `both`. Ideas come back with the same figures; use `minIdeaVolume` to skip small ones.

### More from this developer

- [Bulk HTTP Requests](https://apify.com/saliga/bulk-http-requests): call any API once for every row of a CSV, JSON list or Apify dataset.
- [Website Screenshot + Change Detection](https://apify.com/saliga/website-screenshot-change-detection): screenshots of many URLs on desktop and mobile, with visual change detection between runs.
- [Document to Markdown](https://apify.com/saliga/document-to-markdown): PDF, Word, PowerPoint, Excel and scanned images to clean Markdown with tables and RAG chunks, $2 per 1,000 pages.
- [Audio to Text](https://apify.com/saliga/audio-to-text): audio, video and podcast feeds to timestamped text, SRT/VTT subtitles and RAG chunks with Whisper, $5 per 1,000 audio minutes.
- [Video to Scenes](https://apify.com/saliga/video-to-scenes): scene cuts, one keyframe per scene, a contact sheet and the transcript of each scene, $2 per 1,000 frames.
- [Career Site Jobs](https://apify.com/saliga/career-site-jobs): open jobs from Greenhouse, Lever, Ashby, Workable, Recruitee and Workday career sites, with a new-jobs monitor and a hiring summary per company, $1 per 1,000 jobs.

# Actor input Schema

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

One keyword per line. Up to 80 characters and 10 words each (Google Ads limits), up to 10,000 keywords per run. Duplicates are removed and charged once.

## `countries` (type: `array`):

One or more countries, up to 20 per run. Use two-letter codes (US, GB, DE, FR, TR, JP) or country names. Each country is its own lookup, so the same list can be compared across markets in one run.

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

Search volume for your keywords, new keyword ideas based on them, or both.

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

Optional. A language code such as en, de, es, fr or tr. Leave empty to count searches in all languages in the country (recommended).

## `historyMonths` (type: `integer`):

How many months of monthly search volume to return per keyword. 12 is the default. Ask for 13 or more to get the year-on-year change. Up to 48 (Google keeps four years).

## `maxIdeas` (type: `integer`):

Only for the ideas modes. The most relevant ideas come first. You pay per idea returned.

## `minIdeaVolume` (type: `integer`):

Only for the ideas modes. Ideas below this monthly search volume are dropped and not charged.

## `maxIdeaSeeds` (type: `integer`):

Only for the ideas modes. Ideas are generated from your first keywords, 20 per lookup.

## `keywordsUrl` (type: `string`):

Link to a text file (one keyword per line), a CSV with a keyword column, or a JSON list. A published Google Sheet (CSV link) works.

## `datasetId` (type: `string`):

Use the output of another Actor as the keyword list. Set the field name below.

## `keywordField` (type: `string`):

The column (CSV) or field (JSON, dataset) that holds the keyword.

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

Stop after this many keywords. 0 means the maximum of 10,000.

## `includePartners` (type: `boolean`):

Count searches on Google search partner sites as well as Google itself.

## `includeAdult` (type: `boolean`):

Ask for data on adult keywords. Google may still return nothing for them.

## Actor input object example

```json
{
  "keywords": [
    "project management software",
    "crm software"
  ],
  "countries": [
    "US"
  ],
  "mode": "volume",
  "historyMonths": 12,
  "maxIdeas": 200,
  "minIdeaVolume": 0,
  "maxIdeaSeeds": 20,
  "keywordField": "keyword",
  "maxKeywords": 0,
  "includePartners": false,
  "includeAdult": false
}
```

# Actor output Schema

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

One row per keyword and country: search volume, CPC, competition, trend and status.

## `fullResults` (type: `string`):

Every field, including the month-by-month search volume series.

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

Counts for the run: delivered, without data, invalid, not looked up, lookups, and why the run stopped.

# 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": [
        "project management software",
        "crm software"
    ],
    "countries": [
        "US"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("saliga/keyword-search-volume").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": [
        "project management software",
        "crm software",
    ],
    "countries": ["US"],
}

# Run the Actor and wait for it to finish
run = client.actor("saliga/keyword-search-volume").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": [
    "project management software",
    "crm software"
  ],
  "countries": [
    "US"
  ]
}' |
apify call saliga/keyword-search-volume --silent --output-dataset

```

## MCP server setup

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

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/0CdJEp19J6oawNM67/builds/t2PxsfXeC0QAdGjI9/openapi.json
