# Keyword Volume & CPC · No Minimum (`steadyfetch/keyword-search-volume-scraper`) Actor

Never charged for a keyword with no data, and no minimum spend. Google Ads monthly search volume, CPC and competition for your keyword list. Real Keyword Planner figures — nothing modelled, nothing estimated, and every row says whether it was charged.

- **URL**: https://apify.com/steadyfetch/keyword-search-volume-scraper.md
- **Developed by:** [Steadyfetch Team](https://apify.com/steadyfetch) (community)
- **Categories:** SEO tools, AI, Agents
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

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

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

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

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

# README

## Keyword Volume & CPC · No Minimum

**Never pay for a keyword with no data, and no minimum spend per run.** Paste a keyword
list and get Google Ads average monthly searches, CPC, competition and 12-month trend
direction — or expand a keyword into new keyword ideas with the same metrics.

Real Google Ads Keyword Planner data through a licensed data provider. No "AI search
volume", no modelled numbers, no keyword-difficulty score we invented: every field is
Google's own figure, and `isEstimated` is `false` on every row for that reason.

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

Issues answered in about 3 hours.

Every row carries `charged` and `missReason`, so you can reconcile the invoice from the
dataset itself without opening the console. **Only rows with `charged: true` were billed.**

***

### Output

| field | notes |
|---|---|
| `keyword` | your own spelling, echoed back; `providerKeyword` is the lowercased form Google matched |
| `seed` | the keyword an idea came from — `null` for your own keywords |
| `avgMonthlySearches` | Google's average monthly searches. `0` means "fewer than Google reports", `null` means no data (and no charge) |
| `cpcUsd` | average cost per click |
| `competition` · `competitionIndex` | `LOW` / `MEDIUM` / `HIGH`, and the 0–100 index behind it |
| `lowTopOfPageBidUsd` · `highTopOfPageBidUsd` | the top-of-page bid range |
| `monthlySearchVolumes[]` | 12 months of `{year, month, searches}`, **oldest month first** |
| `trendDirection` | `rising` / `flat` / `falling`, derived from that series |
| `dataAsOf` | the last month Google itself reported, e.g. `2026-07` |
| `country` · `language` · `network` | the market this number is for |
| `source` · `isEstimated` | always `google_ads` and `false` |
| `servedFromCache` | whether this row came from our 30-day cache (see below) |
| `charged` · `missReason` · `statusReason` | the reconciliation trio |

Plus **one summary row** with `delivered`, `stoppedBy`, `resumeCursor` and `chargedEvents`.

***

### Agent / API paste-block

```
Actor:      steadyfetch/keyword-search-volume-scraper
Required:   keywords        (array of keywords; leave the default for uncharged samples)
Optional:   keywordsText    (string — paste a list, newline or comma separated)
            mode            (metrics-only | ideas | both, default metrics-only)
            country         (ISO code or English name, default US)
            language        (code or English name, default en)
            network         (google | google-and-partners, default google)
            maxIdeasPerSeed (integer, default 200 — ideas modes only)
            maxIdeaSeeds    (integer, default 5, max 20 — ideas modes only)
            maxItems        (integer, default 1000 — hard cap for the whole run)
            maxRunSeconds   (integer, default 900 — clean stop, never a timeout kill)
Charges:    keyword-result  once per keyword row delivered with data
Build spec: https://apify.com/steadyfetch/keyword-search-volume-scraper/api
Token:      https://console.apify.com/settings/integrations
```

```bash
curl -X POST "https://api.apify.com/v2/acts/steadyfetch~keyword-search-volume-scraper/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"keywords":["project management software","keyword research tool"],"country":"US"}'
```

Agents and MCP callers: **omit a field you do not want — do not send `null`.** An explicit
`null` is a type violation the platform rejects before the run is created.

***

### How the trend direction is worked out

The last three months of the 12-month series against the first three of the same series.
20% or more above → `rising`. 20% or more below → `falling`. Anything between → `flat`.
Fewer than six months of data → `null`, never a guess. The raw series ships with every
row, so you can apply your own rule instead.

***

### Two things about Google's numbers that most listings do not tell you

1. **Google quantises search volume.** Volumes come back on a coarse ladder — 5,400 /
   40,500 / 165,000 — not as exact integers. They are Google's own published
   figures, not ours, and they are not precise to the search.
2. **Google groups similar keywords.** Close variants can share one combined figure. If
   two of your keywords come back identical, that is usually why. Splitting them across
   separate runs sometimes separates them.

Neither is a defect in this actor. Both are how Keyword Planner works, and you are getting
exactly what an advertiser sees in the Google Ads UI.

***

### The 30-day cache

Google refreshes these volumes **monthly**, so a keyword looked up twice in the same month
returns the same numbers. We cache every lookup for 30 days and serve repeats instantly —
same data, no waiting. Rows served that way are marked `servedFromCache: true` and are
priced exactly like a fresh lookup, because they are exactly the same figures. There is no
start fee to charge you on top of them either.

***

### What you are never charged for

| situation | `missReason` | run status |
|---|---|---|
| Google has no volume for that keyword | `NO_DATA` | SUCCEEDED — the row shows `avgMonthlySearches: null` |
| A keyword Google Ads will not accept (over 80 characters, over 10 words, emoji) | `INVALID_KEYWORD` | SUCCEEDED — the row names the rule |
| The source rate-limited us | `THROTTLED` | SUCCEEDED — re-runnable, and the row says so |
| The source was unavailable this run | `PROVIDER_UNAVAILABLE` | SUCCEEDED — re-runnable |
| We could not reach the source at all | `PROVIDER_ACCOUNT` | SUCCEEDED — this one is on us, never on you |
| Input we could not read (unknown country, wrong type) | `USER_INPUT` | SUCCEEDED — the row names the fix |
| Your own `maxItems` / `maxRunSeconds` / cost cap | `STOPPED_AT_LIMIT` | SUCCEEDED — summary row + `resumeCursor` |

We never guess. A rate limit is reported as a rate limit, not as "this keyword has no
volume" — a temporary problem is never dressed up as a permanent verdict.

**This actor may fail when the platform changes things — failed items are never charged.**

***

### Limits are hard limits

`maxItems`, `maxIdeasPerSeed`, `maxIdeaSeeds` and `maxRunSeconds` stop the run exactly
where you set them. The run still finishes **successfully**, the summary row names which
limit bound, and `resumeCursor` lists the keywords that were not reached — so you continue
from there instead of paying to re-look-up what you already have.

There is no minimum charge per run and no start fee. A five-keyword run costs five
keyword rows, and a run where nothing has data costs nothing.

**And the cap belongs to the run, not to the attempt.** If a run is moved to another
server mid-way — or you resurrect it from the console — it continues from where it
stopped: no row you already have is delivered again, no keyword is looked up twice, and
no keyword is charged twice. `maxItems` still means what it said.

***

### FAQ

**How much does 1,000 keywords cost?**
1,000 rows of the `keyword-result` event, and nothing else — no start fee, no per-run
minimum, no metrics add-on. Keywords with no data are not rows you pay for.

**Is this real Google data or an estimate?**
Real. It is the Keyword Planner figure an advertiser sees in Google Ads, delivered through
a licensed data provider on our own credentials — you never supply a Google Ads login.
`isEstimated` is `false` on every row and there is no "AI search volume" field here.

**Why do two of my keywords have identical numbers?**
Google groups similar keywords under one combined figure. See the section above.

**Do duplicates cost twice?**
No. `SEO Tools`, `seo tools` and `  seo   tools  ` are one keyword, charged once, echoed
back with the first spelling you used. The same rule holds across the whole run: in
`ideas` or `both` mode, a suggestion that repeats a keyword already delivered — including
your own seed echoed back as one of its ideas — is skipped and never charged a second time.

**Can I get keyword ideas instead of metrics?**
Set `mode` to `ideas` (suggestions only) or `both`. Each of your keywords is expanded
separately so every idea row names the `seed` it came from.

**Which countries and languages work?**
Every country and language Google Ads reports on — pass a two-letter code or the English
name. An unrecognised value stops the run with a guidance row rather than quietly using a
different market.

**Does `{}` cost anything?**
No. With no keywords it returns uncharged sample rows so you can see the exact output shape
before spending anything.

***

### Steadyfetch trends & keyword suite

One actor per surface, one job each, the same contract everywhere: **all-inclusive pay per event,
no start fee, charged only on delivery** — so a workflow built for one of them ports to the next.

| What you want | Actor |
|---|---|
| Interest over time, related queries, regions, compare | [Google Trends · No Charge on Miss](https://apify.com/steadyfetch/google-trends-scraper) |
| What is trending right now, by country | [Google Trends Now · No Start Fee](https://apify.com/steadyfetch/google-trends-now-scraper) |
| Rising and Breakout queries, with the real growth number | **Breakout Keywords from Trends** *(publishing soon — `steadyfetch/breakout-keywords-scraper`)* |
| Autocomplete suggestions across 5 engines | **Autocomplete Keywords · 5 Engines** *(publishing soon — `steadyfetch/google-keyword-suggest-scraper`)* |
| Monthly search volume and CPC for a keyword list | **this actor** |
| What is trending on social platforms | [Social Trends · 4 Platforms](https://apify.com/steadyfetch/social-trends-scraper) |

**The rest of the steadyfetch shelf** — same contract everywhere: all-inclusive pay per event,
no start fee, charged only on delivery.

| Family | Actors |
|---|---|
| Ad creative intelligence | [Facebook](https://apify.com/steadyfetch/facebook-ads-transcript-scraper) · [Google Ads video](https://apify.com/steadyfetch/google-ads-video-transcript-scraper) · [TikTok](https://apify.com/steadyfetch/tiktok-ads-transcript-scraper) · [LinkedIn](https://apify.com/steadyfetch/linkedin-ads-transcript-scraper) · [Google Ads text & OCR](https://apify.com/steadyfetch/google-ads-creative-text-scraper) |
| **Trends & keywords** | [Google Trends](https://apify.com/steadyfetch/google-trends-scraper) · [Trends Now](https://apify.com/steadyfetch/google-trends-now-scraper) · Breakout keywords · Autocomplete keywords · Keyword volume & CPC · [Social trends](https://apify.com/steadyfetch/social-trends-scraper) |
| YouTube transcripts | YouTube videos · YouTube channels |
| Instagram | [Reel transcripts](https://apify.com/steadyfetch/instagram-reel-transcript-scraper) · Profile posts |
| Jobs | Indeed · Career sites by domain · Glassdoor · Multi-board |
| Amazon | Products · Search · Bestsellers · Sellers |
| Any media file | Speech to Text · any link or file |

Unlinked names are publishing shortly on the same account — search **steadyfetch** on Apify Store.

***

### Free templates

[github.com/steadyfetch/n8n-templates](https://github.com/steadyfetch/n8n-templates) —
import-validated n8n workflows.

# Actor input Schema

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

The keywords to look up. Leave the default in place to see uncharged sample rows first.

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

Paste a whole list here instead — one keyword per line, or comma-separated. Merged with the list above; duplicates are charged once.

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

Metrics only: volume and CPC for the keywords you supplied. Ideas: expand each keyword into new keyword suggestions with the same metrics. Both: do both.

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

Two-letter country code or the country's English name, for example US, GB, DE, IN, AU, CA.

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

Language code or its English name, for example en, es, de, fr, pt.

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

Google search only, or Google plus its search partners (partner volumes are higher).

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

Only used in the ideas modes. Caps how many suggestions each of your keywords may produce.

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

Only used in the ideas modes. Caps how many of your keywords are expanded in one run; the rest are reported back uncharged.

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

Hard cap on charged rows across the whole run.

## `maxRunSeconds` (type: `integer`):

The run stops cleanly before this many seconds and reports what is left, instead of being killed by a timeout.

## Actor input object example

```json
{
  "keywords": [
    "project management software",
    "keyword research tool"
  ],
  "mode": "metrics-only",
  "country": "US",
  "language": "en",
  "network": "google",
  "maxIdeasPerSeed": 200,
  "maxIdeaSeeds": 5,
  "maxItems": 1000,
  "maxRunSeconds": 900
}
```

# Actor output Schema

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

One row per keyword: average monthly searches, CPC, competition, top-of-page bid range, the 12-month series and the trend direction derived from it. Every row carries `charged` and `missReason`, so the invoice reconciles from the dataset itself. Only rows with charged = true were billed.

## `trend` (type: `string`):

The same rows narrowed to the month-by-month search volumes behind each keyword's trend direction, oldest month first.

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

Rows delivered, keywords with no data, keywords Google Ads would not accept, cache hit rate, and what stopped the run.

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

Present only when a lookup was rate-limited or the source was unavailable: the keyword and the reason. These are re-runnable, not permanent.

# 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",
        "keyword research tool"
    ],
    "country": "US",
    "language": "en"
};

// Run the Actor and wait for it to finish
const run = await client.actor("steadyfetch/keyword-search-volume-scraper").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",
        "keyword research tool",
    ],
    "country": "US",
    "language": "en",
}

# Run the Actor and wait for it to finish
run = client.actor("steadyfetch/keyword-search-volume-scraper").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",
    "keyword research tool"
  ],
  "country": "US",
  "language": "en"
}' |
apify call steadyfetch/keyword-search-volume-scraper --silent --output-dataset

```

## MCP server setup

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

```

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/ajAikTO5i3NRsIdgo/builds/tkiJLED5Nbg9oQ828/openapi.json
