# Keyword Search Volume API: Google Keyword Planner data (`kkingsbe/keyword-search-volume`) Actor

Google Keyword Planner search volume, CPC, competition, bids and 12-month trend for up to 10,000 keywords per run, any country, region or city. Every keyword gets a row; repeats are free until Google publishes new figures; invalid, no-data and zero-volume keywords are free.

- **URL**: https://apify.com/kkingsbe/keyword-search-volume.md
- **Developed by:** [Kyle Kingsberry](https://apify.com/kkingsbe) (community)
- **Categories:** SEO tools
- **Security:** Limited permissions
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 keyword with searches

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

## Keyword Search Volume API: Google Keyword Planner volume, CPC, competition and trend

Paste up to 10,000 keywords and get Google Keyword Planner metrics for each one: **average monthly searches, CPC, competition, top-of-page bids, month-by-month history and a computed trend**, for any country, region or city, in one flat schema. Every keyword you send gets a row, in your order. You pay **$0.12 per run plus a per-keyword price you can compute before you run**, and only for keywords that come back with searches. Ask for the same keyword in the same market again before Google publishes new figures and you get it back **free**, marked `repeat: true`.

No Google Ads account, developer token or OAuth setup. Works with an empty input, from the Console, the API, schedules, n8n, Make, Zapier, and AI agents through Apify's MCP server.

| keyword | avgMonthlySearches | cpcUsd | competition | competitionIndex | trend.direction | dataMonth |
| --- | --- | --- | --- | --- | --- | --- |
| project management software | 201,000 | 40.32 | LOW | 3 | flat | 2026-09 |
| crm for small business | 4,400 | 51.28 | LOW | 22 | rising | 2026-09 |
| email marketing tools | 4,400 | 101.75 | LOW | 6 | rising | 2026-09 |

*A real run of the default input, United States, English, Google Search, 2 November 2026.*

### Contents

- [What you get](#what-you-get)
- [What it does not do](#what-it-does-not-do)
- [How much does it cost to check keyword search volume?](#how-much-does-it-cost-to-check-keyword-search-volume)
- [How to use it](#how-to-use-it)
- [Use it from an AI agent (MCP)](#use-it-from-an-ai-agent-mcp)
- [Integrations: API, Python, JavaScript, n8n, Make, Zapier, Google Sheets](#integrations)
- [Three things about Google's numbers](#three-things-about-googles-numbers)
- [Is it legal? Privacy](#is-it-legal-privacy)
- [FAQ](#faq)
- [How it compares](#how-it-compares)
- [Changelog](#changelog)
- [Feedback and support](#feedback-and-support)

### What you get

One row per distinct keyword you send, in the order you sent them, then idea rows if you asked for ideas, then one summary row.

| Field | What it is |
| --- | --- |
| `status` | `ok` for keyword and idea rows (found or not); `skipped` or `source_error` when a keyword was not measured, with the reason; `summary` for the last row. |
| `keyword` | Your keyword exactly as you sent it, so you can join results back to your list. Idea rows carry the keyword as Google returned it. |
| `normalizedKeyword` | What was actually looked up: trimmed, lower-cased, spaces collapsed, surrounding quotes and `?` `!` `,` `(` `)` removed. |
| `inputCount` | How many times this keyword appeared in your input. It is charged once. |
| `found` | `true` when Google reported a search volume for the keyword, including `0`. |
| `reason`, `message` | Why a row has no figures (`no_data`, `invalid_keyword`, `spending_limit`, `max_items`, `free_plan_limit`, `source_error`) and, in plain words, what to do about it. |
| `kind`, `seed` | `metric` for your keywords, `idea` for related keywords. `seed` names the seed an idea came from when you expanded a single seed. |
| `location`, `locationCode`, `language`, `network` | The market the figures are for, as Google Ads names it. |
| `avgMonthlySearches` | Google's average monthly searches over the last 12 months. |
| `cpcUsd` | Average cost per click, in US dollars. |
| `competition`, `competitionIndex` | `LOW`, `MEDIUM` or `HIGH`, and the same on a 0 to 100 scale. |
| `lowTopOfPageBidUsd`, `highTopOfPageBidUsd` | The bid range advertisers paid to appear at the top of the page. |
| `monthlySearches` | Month by month, newest first: `{ "yearMonth": "2026-09", "searches": 5400 }`. 12 months by default, up to 48. |
| `trend` | `direction` (`rising`, `flat` or `falling`: the last three months against the three before, with a 10% threshold; `null` under six months of history) and `changePct1m`, `changePct3m`, `changePct12m` (the latest month against one, three and twelve months earlier; twelve needs `monthsBack` of 13 or more). |
| `dataMonth` | The latest month Google has published, `YYYY-MM`. Repeats are free until this changes. |
| `repeat`, `firstSeenAt` | `true` when your account already received this keyword in this market this data month, and when it first did. Returned again free. |
| `charged`, `chargedEvent`, `chargedUsd` | Whether this row was charged, as `keyword` or `idea`, and how much. |
| `retryable` | `source_error` rows only: whether running again may help. |
| `servedFromCache` | Reserved for a shared cache planned for a later version; always `false` today. |
| `raw` | The provider's original row, only when `includeRaw` is on. |

A full row:

```json
{
  "status": "ok",
  "keyword": "CRM for Small Business",
  "normalizedKeyword": "crm for small business",
  "inputCount": 1,
  "found": true,
  "reason": null,
  "message": null,
  "kind": "metric",
  "seed": null,
  "location": "United States",
  "locationCode": 2840,
  "language": "en",
  "network": "google_search",
  "avgMonthlySearches": 4400,
  "cpcUsd": 51.28,
  "competition": "LOW",
  "competitionIndex": 22,
  "lowTopOfPageBidUsd": 8.96,
  "highTopOfPageBidUsd": 53.12,
  "monthlySearches": [{ "yearMonth": "2026-09", "searches": 5400 }, { "yearMonth": "2026-08", "searches": 6600 }],
  "trend": { "direction": "rising", "changePct1m": -18.2, "changePct3m": 86.2, "changePct12m": null },
  "dataMonth": "2026-09",
  "repeat": false,
  "servedFromCache": false,
  "charged": true,
  "chargedEvent": "keyword",
  "chargedUsd": 0.008,
  "firstSeenAt": "2026-11-02T18:11:06.243Z",
  "raw": null
}
```

(`monthlySearches` is shortened here; the real row carries all 12 months.)

The **summary row** (`status: "summary"`, always last) tells you what the run did: how many keywords were charged (`chargedCounts`), the run's computed cost (`computedCostUsd`), how many were repeats, zero-volume, no-data, invalid or skipped and why, how many upstream lookups were bought, the data month, and any warnings in plain sentences. Agents should read it before deciding what to do next. The same object is saved as `OUTPUT` in the run's key-value store.

#### Keyword ideas

Set `mode` to `ideas` to expand your keywords as seeds into related keywords with the same metrics, or to `both` to get metrics for your keywords and ideas in one run. `maxIdeas` (default 100) caps the idea rows, `sortBy` decides which ideas are kept (highest search volume by default), and `minSearchVolume` drops small ideas. Google returns hundreds to thousands of ideas per request, so you can ask for up to 10,000. When several seeds are expanded together Google does not say which seed produced which idea, so `seed` is filled only when you expand one seed.

In `both` mode, ideas are fetched first, and any of your own keywords that appear among the ideas are answered from them, so a separate lookup is often not needed and the run finishes faster. An idea that is one of your keywords appears once, as your keyword's row.

### What it does not do

- **No keyword difficulty or search intent.** Those are third-party model estimates, not Google figures. This actor returns only what Google Ads reports.
- **No SERP features, rankings or competitor domain keywords.**
- **No "AI search volume".** Some tools sell estimates of how often a keyword is asked of chatbots; there is no source for that figure, so it is not offered here.
- **No Bing or Microsoft Advertising volumes** yet. Planned.
- **No current month.** Google publishes a month's figures only after it ends, around the middle of the next month.
- **No exact counts.** Google rounds volumes into buckets (see [Three things about Google's numbers](#three-things-about-googles-numbers)).

### How much does it cost to check keyword search volume?

This actor uses pay-per-event pricing. You pay a fixed amount per run, plus a price per keyword that comes back with searches. Prices depend on your Apify plan:

| Event | Free plan | Starter | Scale | Business |
| --- | --- | --- | --- | --- |
| Run start | $0.12 | $0.12 | $0.12 | $0.12 |
| Keyword with searches | $0.012 | $0.008 | $0.006 | $0.005 |
| Idea with searches | $0.008 | $0.005 | $0.004 | $0.0035 |

**Cost of a run = $0.12 + keyword price × new keywords + idea price × new ideas**, where "new" means not already delivered to your account in this market this data month, with a search volume above zero. To know the most a run can cost before you start it, assume every keyword is new.

Worked examples, new keywords, metrics mode:

| Keywords | Free plan | Starter | Scale | Business |
| --- | --- | --- | --- | --- |
| 5 | $0.18 | $0.16 | $0.15 | $0.145 |
| 100 | $1.32 | $0.92 | $0.72 | $0.62 |
| 1,000 | $12.12 | $8.12 | $6.12 | $5.12 |
| 10,000 | not available (see below) | $80.12 | $60.12 | $50.12 |
| 1,000 again in the same data month | $0.12 | $0.12 | $0.12 | $0.12 |

**Never charged:**

- Keywords you already received in the same market this data month (`repeat: true`). You get the figures again free.
- Keywords Google has no data for (`reason: "no_data"`).
- Keywords with an average of zero searches. You still get the row.
- Keywords Google Ads would reject (`reason: "invalid_keyword"`, for example an emoji or `@`). They are never sent.
- Duplicates in your input. Each distinct keyword is charged once.
- Skipped, error and summary rows.

**Set a spending limit.** Every Apify run accepts a maximum total charge (`maxTotalChargeUsd` in the API, "Max cost per run" in the Console). The actor reads it before buying any data: keywords that would not fit in the limit are not looked up and come back as `skipped` with `reason: "spending_limit"`, and the summary row says how many. `maxItems` (default 1,000) caps new keywords per run in the same way; raise it to 10,000 for big lists.

**Free plan.** A run on Apify's free plan looks up at most 1,000 new keywords (one Google lookup). The rest come back as `skipped` with `reason: "free_plan_limit"`, and repeats are still answered. Free plan accounts receive $5 of Apify credit each month.

### How to use it

1. Open the actor, paste your keywords (one per line), pick a location if it is not the United States, and start it.
2. Or call it from the API, a schedule, an integration or an AI agent with JSON input. Every field has a default; `{}` measures three demo keywords.

#### Input

| Field | Default | What it does |
| --- | --- | --- |
| `keywords` | three demo keywords | Keywords to measure or expand. Up to 10,000 distinct per run. |
| `keywordsText` | empty | Optional: a list as text, one per line or comma-separated. Merged after `keywords`. |
| `mode` | `metrics` | `metrics`, `ideas` or `both`. |
| `location` | `United States` | Country, region or city as Google Ads names it (`Germany`, `California`, `Austin, Texas`), or a numeric Google Ads location id (`2840`). |
| `language` | empty | Language code or name (`de`, `German`). Empty means the main language of the location. 46 languages are supported. |
| `network` | `google_search` | `google_search`, or `google_search_and_partners` to include Google's search partner sites. |
| `includeMonthlySearches` | `true` | Include the month-by-month history on each row. |
| `monthsBack` | 12 | Months of history, 1 to 48. Above 12 the lookup can take longer. |
| `maxIdeas` | 100 | `ideas` and `both` modes: total idea rows. |
| `sortBy` | `search_volume` | `ideas` and `both` modes: which ideas `maxIdeas` keeps: `search_volume`, `relevance` (Google's order), `competition_index` or `cpc`. |
| `minSearchVolume` | 0 | Drop ideas below this average monthly volume. Never applied to your own keywords. |
| `includeAdultKeywords` | `false` | Include adult keywords; Google Ads leaves them out by default. |
| `maxItems` | 1,000 | Hard cap on new keywords looked up and charged in this run. Repeats are not counted. |
| `includeRaw` | `false` | Add the provider's original row under `raw`. |

Keywords are cleaned before they are looked up, because a single keyword Google Ads rejects would otherwise fail the whole batch: case, extra spaces, surrounding quotes and `?` `!` `,` `(` `)` are removed (so `what is the best bbq in austin?` is measured as `what is the best bbq in austin`). Keywords that still contain characters Google rejects (`%`, `@`, `|`, `<`, `>`, emoji), are longer than 80 characters or have more than 10 words come back with `reason: "invalid_keyword"` and a message naming the problem, and are not charged.

Locations accept the Google Ads name with or without spaces after commas, a unique beginning of it, or the numeric id. When a name matches several places (`London` is in England, Ontario and Arkansas), or none, the run stops at once with the closest matches, so you can send the full name. A run that stops on invalid input costs only the $0.12 run start, which Apify charges when any run begins; no keyword is charged.

#### Examples

**1. Measure a list for one country**

```json
{
  "keywords": ["projektmanagement software", "crm software", "e-mail marketing tools"],
  "location": "Germany"
}
```

German is picked automatically for Germany.

**2. A whole keyword inventory, every month**

```json
{
  "keywordsText": "plumber near me\nemergency electrician\nroofing contractor\nhvac repair",
  "location": "Austin, Texas",
  "maxItems": 10000
}
```

Save it as a task and schedule it monthly (see below).

**3. Expand seeds and keep the big ones**

```json
{
  "keywords": ["email marketing"],
  "mode": "ideas",
  "maxIdeas": 200,
  "minSearchVolume": 500
}
```

**4. Your keywords plus ideas, with two years of history**

```json
{
  "keywords": ["running shoes", "trail running shoes"],
  "mode": "both",
  "maxIdeas": 50,
  "monthsBack": 24
}
```

#### Run it on a schedule

Save your input as a task and add an Apify schedule that runs it once a month, a few days after the middle of the month, when Google has usually published the previous month. Runs inside the same data month return your keywords free as repeats, so a schedule that fires twice, or a list that grows a little between runs, does not pay twice for the same figures. When Google publishes a new month, every keyword is new data and is charged again. `dataMonth` on every row tells you which month the figures are from.

#### Memory: how repeats are recognised

The actor remembers what it delivered to you in a key-value store called `keyword-volume-memory` in your own Apify account, one set of entries per market and data month, with the figures, so a repeat costs nothing to look up. It never sees other users' memory and nobody else sees yours. Delete the store (Storage, Key-value stores) to start fresh; entries from earlier data months are removed automatically.

One exception, stated plainly: if two of your runs overlap in time, each may charge a keyword the other delivered, because neither has finished saving yet. From then on, it is remembered for every run in that data month.

### Use it from an AI agent (MCP)

This actor is built to be called by agents: every field has a default, every keyword you send gets a row, errors name the field and say what to send instead, and the cost of a run can be computed before it starts.

Add it to any MCP client through Apify's hosted MCP server:

```text
https://mcp.apify.com/?tools=kkingsbe/keyword-search-volume
```

**Claude Code**

```bash
claude mcp add --transport http apify "https://mcp.apify.com/?tools=kkingsbe/keyword-search-volume" --header "Authorization: Bearer YOUR_APIFY_TOKEN"
```

**Claude Desktop and claude.ai:** add a custom connector with the URL above and sign in to Apify when asked.

**Cursor** (`~/.cursor/mcp.json`) and **VS Code** (`.vscode/mcp.json`, use the key `servers` instead of `mcpServers` and add `"type": "http"`):

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com/?tools=kkingsbe/keyword-search-volume",
      "headers": { "Authorization": "Bearer YOUR_APIFY_TOKEN" }
    }
  }
}
```

**Copy this into your agent's instructions:**

```text
To get Google search volume, CPC, competition and trend for keywords, call the Apify actor
kkingsbe/keyword-search-volume with JSON input:
  {"keywords": ["kw 1", "kw 2", ...], "location": "United States", "mode": "metrics"}
- location: a country, region or city name ("Germany", "Austin, Texas") or a Google Ads location id.
- mode "ideas" expands the keywords into related keywords; add "maxIdeas" and "minSearchVolume".
- One output row per distinct keyword, in input order, then idea rows, then a final row with
  status "summary". Read the summary: chargedCounts, computedCostUsd, warnings.
- found=false rows have reason "no_data" (Google has nothing) or "invalid_keyword" (fix and resend).
- status "skipped" rows were not looked up (spending limit, maxItems or free-plan limit): run again.
- Cost: $0.12 per run + about $0.005 to $0.012 per keyword with searches. Repeats in the same
  data month, no-data, zero-volume and invalid keywords are free. Send whole lists in one run.
```

Calls through MCP usually return within the client's wait time: in testing, runs answered from memory took 2 to 5 seconds, small fresh lookups 3 to 28 seconds, and ideas runs 11 to 31 seconds. A run that outlasts the MCP server's wait comes back as still running with its run ID; fetch its dataset when it finishes. Ask for 12 months of history unless you need more.

Agents can also pay per run without an Apify subscription through Apify's support for x402 agent payments; see Apify's documentation for the current setup.

### Integrations

#### API (cURL)

Run and wait for the results in one call:

```bash
curl -X POST "https://api.apify.com/v2/acts/kkingsbe~keyword-search-volume/run-sync-get-dataset-items" \
  -H "Authorization: Bearer YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"keywords": ["crm software", "email marketing tools"], "location": "United States"}'
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("kkingsbe/keyword-search-volume").call(
    run_input={"keywords": ["crm software", "email marketing tools"], "location": "United Kingdom"}
)
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row["status"] == "summary":
        print("cost", row["computedCostUsd"], "warnings", row["warnings"])
    elif row["found"]:
        print(row["keyword"], row["avgMonthlySearches"], row["cpcUsd"], row["trend"]["direction"])
```

#### JavaScript

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

const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('kkingsbe/keyword-search-volume').call({
    keywords: ['crm software', 'email marketing tools'],
    location: 'Austin, Texas',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const row of items.filter((r) => r.status === 'ok' && r.found)) {
    console.log(row.keyword, row.avgMonthlySearches, row.cpcUsd);
}
```

#### n8n, Make, Zapier

Use Apify's integration in each tool: the "Run an Actor" action with `kkingsbe/keyword-search-volume` and the JSON input above, then "Get dataset items" for the results. Filter on `status` equal to `ok` and `found` equal to `true` to keep only rows with figures. The fields have the same names in every tool.

#### Google Sheets

Keep your keywords in a sheet column and send them as `keywordsText` (one per line) from Make or Zapier, then write the dataset rows back to the sheet. Because every keyword gets a row in your order, and `keyword` is echoed exactly as you sent it, results line up with the original column.

### Three things about Google's numbers

1. **Volumes are rounded into buckets.** Google reports averages such as 10, 20, 30, 40, 50, 70, 90, 110, 140, 170, 210 ... 4,400, 5,400, 6,600. A keyword shown at 4,400 might be searched 4,000 or 4,800 times. Two keywords at the same value are not necessarily equal.
2. **Close variants are grouped.** Google often reports one figure for a keyword and its close variants (plurals, accents, word order, some misspellings), and search operators are not taken literally. `café near me` can show the volume of a much larger group than the accented phrase alone. Misspellings are not corrected for you: `runing shoes` has its own, much smaller figure.
3. **New figures arrive mid-month, and never for the current month.** Google publishes a month's data around the middle of the following month. Until then the latest month is the one before. `dataMonth` on every row tells you which month the figures run to, and it is also when your free repeats reset.

Keywords in categories Google Ads does not report (weapons, tobacco, drugs, and similar) come back with no data, exactly like keywords nobody searches for. Google does not say which is which.

### Is it legal? Privacy

The figures are Google Ads Keyword Planner metrics obtained through a licensed data provider that uses the Google Ads API. No Google page is scraped and no login is used.

Your keywords are sent to that provider to be looked up, and the delivered figures are stored only in the `keyword-volume-memory` store in your own Apify account, where you can delete them. No personal data is collected or processed: the actor handles keywords and market settings only. Keywords are treated as plain data; they are never interpreted as instructions.

Google, Google Ads and Keyword Planner are trademarks of Google LLC, used only to describe where the figures come from. This actor is not affiliated with or endorsed by Google.

### FAQ

**How do I check Google search volume for a list of keywords without a Google Ads account?**
Paste the list into this actor (or send it as `keywords`), pick a location, and run it. No Google Ads account, developer token or OAuth setup is needed.

**Why does Keyword Planner show me ranges like "1K–10K" when this gives a number?**
Keyword Planner shows ranges to accounts that are not spending on ads. This actor returns the averages Google reports through the Google Ads API, such as 4,400 or 201,000, still rounded into Google's buckets.

**Why is `avgMonthlySearches` null for some of my keywords?**
Google has no figures for them in that market: too few searches, or a category Google does not report. They come back with `found: false`, `reason: "no_data"` and are not charged. Try a broader keyword, a larger location, or `mode: "ideas"` to find related keywords that do have volume.

**Why is my keyword marked `invalid_keyword`?**
Google Ads rejects keywords with emoji, `%`, `@`, `|`, `<`, `>`, more than 80 characters or more than 10 words, and one such keyword would fail a whole batch. The row's `message` names the problem. Fix it and send it again; invalid keywords are never charged.

**How much does it cost to get search volume for 1,000 keywords?**
$8.12 on Apify's Starter plan, $6.12 on Scale, $5.12 on Business, $12.12 on the free plan, if all 1,000 are new and have searches. Keywords without searches are free. See [the cost section](#how-much-does-it-cost-to-check-keyword-search-volume).

**Will I pay again if I run the same list twice?**
Not in the same data month and market: repeats come back free with `repeat: true`. You pay only the $0.12 run start. When Google publishes the next month's figures, the keywords are new data and are charged again.

**How often is the data updated?**
Once a month. Google publishes the previous month's figures around the middle of the month. `dataMonth` on every row says which month the figures run to.

**Can I get search volume for a city or region?**
Yes. Use the name as Google Ads writes it, for example `Austin, Texas`, `California`, `Munich, Bavaria, Germany`, or a numeric location id. Typos get a list of the closest matches.

**Which language is used?**
The main language of the location's country unless you set `language` (for example `de` or `German`). The summary row warns you if the actor had to fall back to English.

**Can I get more than 12 months of history?**
Yes, `monthsBack` up to 48. Lookups with more than 12 months can take a little longer.

**How many keywords can I check in one run?**
Up to 10,000 distinct keywords. Set `maxItems` to 10,000, because the default is 1,000. On Apify's free plan a run looks up at most 1,000 new keywords.

**What happens to questions like "what is crm?"**
`?`, `!`, `,` and parentheses are removed before the lookup, as Keyword Planner ignores them anyway, so the question is measured as `what is crm`. Your original text stays in `keyword`.

**Does it return keyword difficulty or search intent?**
No. Those are estimates made by third parties, not Google figures. This actor returns only what Google Ads reports.

**Does it support Bing?**
Not yet. It is planned.

**How do I reset what the actor remembers?**
Delete the key-value store `keyword-volume-memory` in your Apify account (Storage, Key-value stores). The next run starts fresh, and charges as if nothing had been delivered before.

**Is it safe to call from an AI agent?**
Yes. Keywords are plain data, never instructions; the output fields are numbers and the keyword text. The actor runs with Apify's limited permissions, so beyond its own run storage and the `keyword-volume-memory` store it creates, it cannot reach the data in your account.

### How it compares

Checked against the public Apify Store listings and input schemas on 2 November 2026. Prices change; check each listing.

| | This actor | aitorsm/keyword-volume | steadyfetch/keyword-search-volume-scraper | memo23/keyword-metrics | wrenfield-data/keyword-search-volume |
| --- | --- | --- | --- | --- | --- |
| Runs with an empty input | Yes | No, `keywords` required | Yes | Yes | No, `keywords` required |
| Price per keyword, free plan to Business | $0.012 to $0.005 | $0.012 to $0.008 | $0.012 to $0.004 | $0.25 per batch of up to 1,000 | $0.004 to $0.0033 |
| Other fees | $0.12 per run | default start fee only | $0.19 per run when a fresh lookup is needed | $0.05 per run | $0.25 per request of up to 1,000 |
| Can the cost be known before the run | Yes | Yes | No, the lookup fee depends on cache state | Yes | Mostly (small lookups may skip the request fee) |
| Repeat keywords free | Yes, until Google publishes new figures | Not offered | Yes, for 30 days | Identical input from cache, start fee charged | No (cached keywords are billed like fresh) |
| Row for every input keyword, in order | Yes, with `found` and `inputCount` | Partly (its FAQ covers missing keywords) | Not stated | Yes | Yes, with `found` |
| Rejected keywords explained before sending | Yes | Not stated | Not stated | Not stated | Not stated |
| Computed trend | Yes | No (monthly series only) | Yes | Yes | Yes |
| Keyword difficulty and intent | No | No | No | Yes (third-party) | Yes (database source) |
| Bing volumes | Not yet | No | No | Yes | No |

Choose another actor if you need Bing figures or keyword difficulty today. Choose this one if you check the same lists repeatedly, call it from agents, or want every keyword accounted for in the output at a price you can compute in advance.

### Changelog

- **0.1 (2 November 2026):** first release. Metrics, ideas and both modes; country, region and city locations; per-account repeat memory by data month; validation of keywords before lookup; computed trend; tiered pay-per-event pricing.

### Feedback and support

Found a keyword that came back wrong, a location that does not resolve, or a message that was not clear? Open an issue on the actor's Issues tab with the run ID; issues are answered within a day.

If the actor saved you time, a short review on the Store helps other people find it.

# Actor input Schema

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

Keywords to measure (metrics) or expand (ideas). Up to 10,000 distinct keywords per run. Case, extra spaces, surrounding quotes and ? ! , ( ) are ignored; duplicates are charged once.

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

Optional: paste a list, one per line or comma-separated. Merged after `keywords`.

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

metrics: figures for the keywords you supplied. ideas: expand them as seeds into related keywords with the same figures. both: metrics for your keywords plus ideas.

## `location` (type: `string`):

Country, region or city as Google Ads names it (United States, Germany, California, Austin, Texas) or a numeric Google Ads location id. Ambiguous names list the matches.

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

Language name or code (46 supported, for example de or German). Empty means the main language of the location.

## `network` (type: `string`):

google_search: Google Search only. google_search_and_partners: adds Google's search partner sites.

## `includeMonthlySearches` (type: `boolean`):

Include the month-by-month search counts on each row.

## `monthsBack` (type: `integer`):

Months of history on each row, ending at the latest month Google has published. Above 12 the lookup is slower (can exceed an AI agent's 30-second wait).

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

ideas and both modes only: total idea rows for the run.

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

ideas and both modes only: which ideas maxIdeas keeps, highest first.

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

Drop ideas (never your own keywords) below this average monthly search volume.

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

Include adult keywords in results; Google Ads omits them by default.

## `maxItems` (type: `integer`):

Hard cap on new keywords looked up and charged in this run. Repeats are free and not counted. The run's maximum charge is respected as well.

## `includeRaw` (type: `boolean`):

Add the provider's original row under raw.

## Actor input object example

```json
{
  "keywords": [
    "project management software",
    "crm for small business",
    "email marketing tools"
  ],
  "keywordsText": "",
  "mode": "metrics",
  "location": "United States",
  "language": "",
  "network": "google_search",
  "includeMonthlySearches": true,
  "monthsBack": 12,
  "maxIdeas": 100,
  "sortBy": "search_volume",
  "minSearchVolume": 0,
  "includeAdultKeywords": false,
  "maxItems": 1000,
  "includeRaw": false
}
```

# Actor output Schema

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

One row per distinct input keyword in input order, then idea rows, then the summary row.

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

Counts, computed cost, data month and warnings for the run (the same object as the last dataset row).

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("kkingsbe/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 = {}

# Run the Actor and wait for it to finish
run = client.actor("kkingsbe/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 '{}' |
apify call kkingsbe/keyword-search-volume --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kkingsbe/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/jNRlI0rkfqr4wGXnl/builds/WhL9JBvs0ThHi0P9I/openapi.json
