# Keyword Search Volume, CPC & Difficulty — Google + Bing Bulk (`memo23/keyword-metrics`) Actor

Keyword search volume, CPC, competition, difficulty and search intent from Google Ads and Bing, with up to ~7 years of monthly history and a trend flag. One flat fee covers up to 1000 keywords per run. Expand seeds into keyword ideas or pull a competitor's ranked keywords. 111 countries.

- **URL**: https://apify.com/memo23/keyword-metrics.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** SEO tools, Automation, AI
- **Features:** Limited permissions
- **Stats:** 1,431 total users, 847 monthly users, 98.5% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.25 / google keyword batch

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/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 Metrics — Google + Bing Volume, CPC & Difficulty

<p align="center"><img src="https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/keyword-metrics-logo.png" width="140" alt="Keyword Metrics"></p>

Bulk keyword research that returns **Google Ads and Microsoft/Bing Ads metrics side by side on the same row**: average monthly search volume, CPC, competition, top-of-page bid ranges, **keyword difficulty**, **search intent**, and **up to ~7 years of monthly history**, plus a computed trend flag and month-over-month change.

> Difficulty, intent, `search_volume_trend` and the ~93-month series come from Google's Labs endpoint, which this actor uses for runs of **up to ~650 keywords**. Larger runs switch to the Ads endpoint — cheaper at that size, but it returns 12 months of history and none of those three extra columns. Split a big list into batches of 650 to keep them.

Three modes: **measure** up to 1000 keywords you already have, **expand** 20 seeds into thousands of related keywords, or take a **competitor's** domain and get every keyword it ranks for. **111 countries**, **46 languages**, one flat price per batch.

> **Next step after volumes:** [Competitor Keywords](https://apify.com/memo23/competitor-keywords) shows the keywords your competitors rank for and you don't, and tracks your live Google position for a keyword list with what moved since the last run.

***

### Why this one

Search-volume actors bill in ways that punish you for using them properly. This one does not.

| | This actor | Typical competitor |
|---|---|---|
| 1000 keywords, Google + Bing | **$0.55** | $2.70 |
| Difficulty · intent · ~93mo history | **≤650 keywords per run** | rarely offered at all |
| 1000 keywords, Google only | **$0.30** | $1.00 – $5.02 |
| Cost of 10 keywords vs 1000 | **Identical** | Often per-keyword |
| Keyword ideas from a seed | **Up to 20,000, one fee** | Capped, or a separate actor |
| Competitor's ranked keywords | **✅ same actor** | Usually a separate purchase |
| Countries | **111** | 14 – 53 |
| Monthly history | **~93 months** (≤650 kw) · 12 (above) | 12 |
| Keyword difficulty | **✅** | rarely |
| Search intent | **✅** | rarely |
| Languages | **46** | 9 – 47 |
| Free-plan keyword cap | 50 per run (1,000 on paid plans) | 200 |
| Free-plan engine restriction | **None** | Google only |

The upstream API bills per batch, not per keyword, so a run of 1000 keywords costs exactly what a run of 1 costs. This actor passes that structure through instead of inventing per-keyword or per-chunk fees on top of it. **Send your whole keyword list — splitting it up only costs you more.**

The same holds in ideas mode: one expansion can return up to 20,000 keywords for a single fee, so `maxIdeas` trims your dataset, never your bill.

***

> **Coming from a per-keyword tool?** Most keyword-volume actors bill per row — roughly $0.008-0.012 per keyword. That pricing punishes you for doing real research: 1000 keywords costs $8-12, and you start rationing your list. This actor bills per batch, so the same 1000-keyword Google scan is **$0.30** including the run start — 27-40× cheaper at scale, and the crossover where per-keyword gets more expensive is around **30 keywords**. Below that, per-keyword is cheaper; above it, you are overpaying. You also get Bing on the same row, keyword difficulty, search intent and ~93 months of history that per-keyword tools rarely include. If you are migrating, paste your existing keyword list straight in — the schema is one keyword per line, same as everywhere else.

***

> **Bing coverage, stated plainly:** Microsoft sells keyword data in **six countries** — US, UK, Canada, Australia, Germany, France — and **three languages** (English, French, German). That is Microsoft's limit, not this actor's. Anywhere else the row still arrives with a `bing_status` telling you why, and **the Bing batch is never charged.** Google covers all 111.

### How it works

<p align="center"><img src="https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-keyword-metrics.png" width="900" alt="How it works"></p>

Your keywords are deduplicated and normalised, checked against the cache, and screened for engine coverage and your own charge limit — **all before anything is billed**. Then one batch call per engine, one row per keyword, and the dataset is yours.

***

### Three modes

**`metrics`** — you have the keywords, you want the numbers. Up to 1000 per run, Google and Bing side by side.

**`ideas`** — you have a topic, you want the keywords. Up to 20 seeds in, related keywords out, each carrying the same volume/CPC/competition/history. Google-only: Microsoft has no keyword-expansion endpoint.

```json
{ "mode": "ideas", "keywords": ["wireless headphones"], "maxIdeas": 500, "minVolume": 100, "sortBy": "search_volume" }
```

**`competitors`** — you have a rival, you want their keywords. Give it a domain and it returns every term that site ranks for in Google organic, highest traffic value first, with position, the URL holding it, estimated monthly traffic and what that traffic would cost to buy through Ads.

```json
{ "mode": "competitors", "domain": "ahrefs.com", "country": "us", "maxDomainKeywords": 500 }
```

> **You pay one flat $0.90 for a competitors run, whatever `maxDomainKeywords` is set to.** The cap shapes your dataset, not your bill — it exists because the underlying data is priced per row on our side, which is why the ceiling is 3000 rather than the whole index. Rows come back sorted by traffic value, so a small cap still returns the keywords that matter.

***

### Input

| Field | Type | Default | Notes |
|---|---|---|---|
| `mode` | string | `metrics` | `metrics` measures your list; `ideas` expands your seeds; `competitors` reads a domain's rankings. |
| `keywords` | array of strings | — | Required in metrics and ideas modes (ignored in competitors). Up to 1000 in metrics mode, 20 seeds in ideas mode. Lowercased, whitespace-collapsed and deduplicated before the lookup, so casing and accidental duplicates cost you nothing. |
| `country` | string | `us` | ISO-3166 alpha-2, lowercase. 111 supported. Unrecognised codes fall back to `us` with a note in the log. |
| `language` | string | auto | 46 supported — exactly the set Google Ads accepts (note `iw` for Hebrew, `no` for Norwegian, `zh_CN`/`zh_TW` for Chinese). Left on Auto it follows the country — Germany queries German, Japan queries Japanese. |
| `includeGoogle` | boolean | `true` | Google Ads metrics. One batch fee. |
| `includeBing` | boolean | `true` | Microsoft Ads metrics. One batch fee. Ignored in ideas mode. |
| `domain` | string | — | **Competitors mode only, required.** Bare host — `ahrefs.com`, not `https://ahrefs.com/blog`. Scheme, path and `www.` are stripped. |
| `maxDomainKeywords` | integer | `1000` | Competitors mode only. How many ranked keywords to return, highest traffic value first. Shapes the dataset, not the price — a run is a flat $0.90 either way. Ceiling 3000. |
| `maxIdeas` | integer | `1000` | Ideas mode only. Caps the dataset, not the charge — one expansion returns up to 20,000 for the same fee. |
| `minVolume` | integer | `0` | Drop rows below this volume on both engines. Applied after the lookup. |
| `sortBy` | string | `relevance` | Upstream ordering. Decides which keywords survive the `maxIdeas` trim. |
| `searchPartners` | boolean | `false` | Count each engine's partner network in the volumes. Off by default, matching both Keyword Planners. |
| `includeAdultKeywords` | boolean | `false` | Let adult keywords through. Google-side only. |
| `dateFrom` / `dateTo` | string | — | History window as `yyyy-mm-dd`. Setting either switches the run to the Ads endpoint, which caps history at 12 months. Leave both empty for the default ~93-month series. |
| `bypassRunCache` | boolean | `false` | Force a live lookup instead of reusing a cached result. Charges full batch fees. |

```json
{
  "keywords": ["wireless headphones", "noise cancelling headphones", "bluetooth earbuds"],
  "country": "us",
  "includeGoogle": true,
  "includeBing": true
}
```

***

### Output

One row per keyword you asked for — **including keywords neither engine has data for**, so you can join results back onto your input list without missing rows shifting everything out of alignment.

```json
{
  "keyword": "wireless headphones",
  "search_intent": "commercial",
  "keyword_difficulty": 50,
  "google_search_volume": 165000,
  "bing_search_volume": 14800,
  "trend": "rising",
  "mom_change_pct": 22.4,
  "search_volume_trend": { "monthly": -63, "quarterly": 122, "yearly": 172 },
  "google_cpc": 0.78,
  "bing_cpc": 0.51,
  "google_low_top_of_page_bid": 0.42,
  "google_high_top_of_page_bid": 1.18,
  "bing_low_top_of_page_bid": 0.31,
  "bing_high_top_of_page_bid": 0.92,
  "google_competition": "HIGH",
  "google_competition_index": 87,
  "bing_competition": 0.84,
  "google_monthly_searches": [{ "year": 2025, "month": 11, "search_volume": 201000 }],
  "bing_monthly_searches": [{ "year": 2025, "month": 11, "search_volume": 17500 }],
  "country": "us",
  "language": "en",
  "google_status": "ok",
  "bing_status": "ok",
  "source": "live"
}
```

In competitors mode every row is a keyword the domain ranks for, and carries **`domain`**, **`rank_absolute`**, **`rank_group`**, **`ranking_url`**, **`ranking_title`**, **`estimated_traffic`** and **`estimated_traffic_cost`** alongside the usual metrics. Bing columns are `null`: this is Google organic ranking data and Microsoft publishes no equivalent.

In ideas mode every row is a keyword Google returned rather than one you asked for, the Bing columns are `null` with `bing_status: "skipped"`, and each row carries **`is_seed`** so you can tell your own seeds apart from what was discovered.

#### Field notes

- **`google_competition`** is `LOW` / `MEDIUM` / `HIGH`; **`google_competition_index`** is the same thing 0–100. **`bing_competition`** is a float — the two networks report competition differently and neither is converted to match the other.
- **`trend`** compares the mean of the last three months against the three before. Rising or falling needs a move of more than 10%; anything smaller is `flat`. Null when there is under six months of history. Averaging each side stops one spiky month from flipping the flag.
- **`mom_change_pct`** is the change between the two most recent months with data. Null when the earlier month was zero.
- **`bing_status`** — `ok`, `no_data` (Bing ran but knows nothing about this keyword), `skipped` (you turned Bing off, or you are in ideas mode), `unsupported_location` (Microsoft does not sell ads in this country), `unsupported_language` (Microsoft supports English, French and German only), `too_long` (the keyword is over Bing's 100-character limit), `error`.
- **`google_status`** — `ok`, `no_data`, `skipped`, `too_long` (over Google's 80-character / 10-word limit), `error`.
- **`keyword_difficulty`** — 0-100, how hard the organic top 10 is to break into. Metrics mode only.
- **`search_intent`** — `informational`, `navigational`, `commercial` or `transactional`. Metrics mode only.
- **`search_volume_trend`** — upstream's own percentage deltas over 1, 3 and 12 months, alongside our computed `trend`. Metrics mode only.
- **`source`** — `live` or `cache`.
- **`location_name`** — the city or region the run was measured in. Absent when you measured a whole country.
- **`ai_search_volume`** and **`ai_monthly_searches`** — present when `includeAiVolume` is on. How often the keyword is asked in AI assistants, and the last 12 months of that.
- Both networks quantize volumes into broad bands. Those bands are returned **unchanged** rather than smoothed into a fake-precise number.

***

### Pricing

| Event | Price | When |
|---|---|---|
| `actor-start` | $0.05 | Once per run. Covers validation, dedup and the cache lookup. Always charges. |
| `google-batch` | $0.25 | Once, after a successful Google call in metrics mode. Covers the whole keyword list. |
| `bing-batch` | $0.25 | Once, after a successful Bing call. Covers the whole keyword list. |
| `google-ideas` | $0.75 | Once, after a successful expansion in ideas mode. Covers every keyword returned, up to 20,000. |
| `domain-keywords` | $0.90 | Once, after a successful competitors run. Covers every ranked keyword returned, up to 3,000. |
| `ai-volume` | $0.25 | Once, after AI search volume comes back in metrics mode. Covers the whole keyword list. On the price list from 4 November 2026. |

A full 1000-keyword Google + Bing scan is **$0.55**. So is a 3-keyword scan — which is why you should send full lists. A 20,000-keyword idea expansion is **$0.80**. Adding AI search volume is **$0.25** more, for the whole list.

Set `location` to measure a city or region instead of the whole country (`Austin, Texas`). That run returns Google Ads volume for the place. Bing, difficulty, intent and the long history series are country-level, so they are left off and not charged.

Metrics runs are served from Google's Labs `keyword_overview` endpoint, which is billed per keyword rather than per task and is cheaper than the flat-rate Ads endpoint below ~650 keywords — while returning more: ~93 months of history instead of 12, plus difficulty and intent. Past that size, or when you set a custom date window, search partners or adult keywords, the run falls back to the Ads endpoint automatically. Your price does not change either way; only our cost does.

**Failed calls never charge.** Each batch event fires only after the upstream call returns data. If Microsoft has no coverage for your country, the Google half still ships and the Bing batch is not billed.

#### The cache

An identical scan is served from cache for the start fee alone, however long ago it was stored. Search volumes are monthly rolling averages. Set `bypassRunCache` to force a live lookup.

***

### FAQ

**Where does the data come from?**
Google Ads and Microsoft Ads keyword-planning endpoints — the same source their own Keyword Planners read from. Not scraped SERPs, not modelled estimates.

**Why is Bing volume so much lower than Google?**
Because it is. Microsoft's network is a fraction of Google's in most markets. That gap is the useful signal: a keyword where Bing's share is unusually high often has cheaper clicks and less competition.

**A keyword came back with nulls. Was I charged for it?**
Yes — billing is per batch, not per keyword, so an empty result costs the same as a full one. The row is still returned with nulls so your joins stay aligned.

**Why did Bing return nothing for my country?**
Microsoft sells ads in fewer countries than Google. The row arrives with `bing_status: "unsupported_location"` and you are not charged the Bing batch.

**Why was Bing skipped for my language?**
Microsoft's keyword endpoint accepts English, French and German only. Any other language is skipped before the call is made, so you see `bing_status: "unsupported_language"` and pay nothing for it — rather than paying for a rejection.

**I don't know which keywords to research yet.**
Set `mode` to `ideas` and give it up to 20 seeds. You get back the related keywords Google associates with them, each with the same volume, CPC and competition data. Use `minVolume` and `sortBy` to keep the useful end of the list.

**What are the limits on the free Apify plan?**
On the free Apify plan a run processes the first 50 keywords in metrics mode, returns up to 100 keyword ideas in ideas mode and up to 100 ranked keywords in competitors mode, and an account can start 5 runs in any 24 hours. Prices are the same as on paid plans. When a limit cuts a run short, the dataset gets one extra row with `source: "free_plan_notice"` saying so, and the run's status message says it too. A 6th run within 24 hours ends straight away without charging anything. Any paid Apify plan removes these limits: up to 1,000 keywords per run, the full idea and competitor ceilings, and no daily run limit.

**Can I get more than 1000 keywords?**
Not in one metrics run — that is the upstream task limit. Split into runs of 1000; each is billed as its own batch. Ideas mode is different: one run can return up to 20,000 keywords for a single fee.

**Is this safe to run from an AI agent?**
Yes. It runs under limited permissions — it reaches the keyword-data API and its own storage, nothing else in your account — so there is no broad-access approval step. It is callable over the Apify MCP server like any other actor.

**Does this pair with the Google Trends scraper?**
Yes, and they answer different questions. Trends gives relative interest on a 0–100 scale with no absolute numbers. This gives absolute monthly volume and what advertisers pay. Use Trends to spot a rising shape, this to size it.

***

### Explore more scrapers

Keyword Metrics answers *"is this keyword worth it?"*. These answer the rest of the question:

- **[Competitor Keywords & Keyword Gap](https://apify.com/memo23/competitor-keywords)** — the Google keywords your competitors rank for and you don't, one row per keyword with every competitor's position, an opportunity score and quick wins. It also tracks your live Google positions run to run. 88 countries.
- **[Ubersuggest Scraper](https://apify.com/memo23/ubersuggest-scraper)** — keyword volume, CPC and difficulty plus per-domain ranking keywords, backlinks and top pages. No account needed.
- **[Ahrefs Scraper](https://apify.com/memo23/ahrefs-scraper)** — Domain Rating, backlinks, referring domains, organic traffic and AI-visibility citations.
- **[Semrush Scraper](https://apify.com/memo23/semrush-scraper)** — authority score, traffic, ranks, backlinks, competitors and AI traffic for any domain.
- **[Moz Scraper](https://apify.com/memo23/moz-scraper)** — Domain Authority, spam score, linking root domains and ranking keywords.
- **[Similarweb Scraper](https://apify.com/memo23/similarweb-scraper)** — traffic, rank, visits and audience for a domain list.
- **[Google Trends Scraper](https://apify.com/memo23/google-trends-scraper)** — relative interest over time and the live Trending Now feed. Trends spots a rising shape; this actor sizes it in absolute volume.
- **[SEO Intelligence Suite](https://apify.com/memo23/seo-intelligence-suite)** — DR, traffic, AI-search visibility and Google presence for a domain in one call.
- **[AI Visibility Tracker](https://apify.com/memo23/ai-visibility-tracker)** — whether ChatGPT, Gemini and Perplexity cite your brand.

A typical pipeline: **Google Trends** to spot a rising topic → **Keyword Metrics** in ideas mode to expand it into a keyword set with real volume → **Ahrefs** or **Moz** to check whether you can realistically rank.

***

### 🤖 For AI Agents & LLM Apps

**What it does:** returns Google Ads and Microsoft Ads keyword metrics for a keyword list, or expands seed keywords into related ones. It measures demand for keywords; it does not list the pages that rank for them (the competitors mode covers one domain's rankings).

**Minimal input (tested):**

```json
{ "keywords": ["running shoes", "seo tools"], "country": "us" }
```

**Discovery input:**

```json
{ "mode": "ideas", "keywords": ["vegan protein powder"], "maxIdeas": 250, "minVolume": 100, "sortBy": "search_volume" }
```

**Output fields (flat, one row per keyword):**
`keyword`, `is_seed` (ideas mode only), `search_intent`, `keyword_difficulty`, `google_search_volume`, `bing_search_volume`, `trend`, `mom_change_pct`, `search_volume_trend`, `google_cpc`, `bing_cpc`, `google_low_top_of_page_bid`, `google_high_top_of_page_bid`, `bing_low_top_of_page_bid`, `bing_high_top_of_page_bid`, `google_competition`, `google_competition_index`, `bing_competition`, `google_monthly_searches[]`, `bing_monthly_searches[]`, `country`, `language`, `google_status`, `bing_status`, `source`.

**Behaviours that matter to an agent:**

- **Billing is per batch, not per keyword.** One keyword and 1000 cost the same. Batch aggressively; never loop one keyword per run.
- **Every requested keyword returns a row**, even when no engine has data — `null` metrics with a status field. Joins stay aligned; row count always equals input count in metrics mode.
- **Failed upstream calls are never charged.** Only `actor-start` always bills.
- **An identical input is served from cache** for the start fee alone, at any age. Set `bypassRunCache: true` only when you deliberately need fresh numbers.
- **Bing is Google-only outside 6 countries.** Check `bing_status` before treating a `null` Bing volume as zero demand.
- **Ideas mode is Google-only** and caps at 20 seeds; `maxIdeas` trims the dataset, not the bill.
- Runs under **limited permissions** — it reaches the keyword API and its own storage, nothing else in your account. No broad-access approval step.

***

### ⚠️ Disclaimer

This Actor retrieves keyword-planning data from Google Ads and Microsoft Ads through a licensed third-party data provider. It does not scrape private, personal, or authenticated content, and it collects no personal data.

Search volumes are quantized into broad bands by Google and Microsoft themselves and are returned **unchanged** — they are planning estimates, not exact counts, and should be treated as directional. Figures can differ from what you see in the Keyword Planner UI, which applies its own account-level filtering.

You are responsible for using the output in line with Google's and Microsoft's terms and any applicable law in your jurisdiction. This Actor is not affiliated with, endorsed by, or sponsored by Google LLC or Microsoft Corporation. Google Ads and Microsoft Ads are trademarks of their respective owners.

***

### SEO Keywords

keyword research tool, google keyword planner api, search volume api, bulk keyword metrics, keyword search volume scraper, cpc data api, keyword difficulty checker, search intent analysis, bing keyword volume, microsoft ads keyword data, google ads keyword data, seo keyword api, keyword ideas generator, related keywords api, long tail keyword finder, keyword volume checker bulk, ahrefs alternative, semrush alternative, ubersuggest alternative, moz alternative, keyword planner alternative, ppc keyword research, competition index keywords, top of page bid data, monthly search trend, keyword seasonality data, seo dashboard data source, n8n keyword research, make.com seo automation, zapier keyword data, apify seo actor, mcp keyword tool, ai agent keyword research, keyword clustering input, content gap keywords, multi country keyword research, international seo keywords

# Actor input Schema

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

**Metrics** measures the keywords you supply — up to 1000 in one batch. **Ideas** takes up to 20 seeds and returns the related keywords Google associates with them. **Competitors** takes a domain instead of keywords and returns every keyword it ranks for in Google organic, with position, estimated traffic and what that traffic would cost to buy.

## `domain` (type: `string`):

The site whose Google organic rankings you want, as a bare host — `ahrefs.com`, not `https://ahrefs.com/blog`. A scheme, path or leading `www.` is stripped automatically. Required in Competitors mode and ignored in the others.

## `maxDomainKeywords` (type: `integer`):

How many of the domain's ranked keywords to return, highest estimated traffic first. **Unlike every other limit in this actor, this one changes what you pay** — ranked keywords are billed per row, not per batch. Big sites rank for tens of thousands of terms; the top few hundred by traffic value are usually the interesting ones. Hard ceiling 3000 — beyond that a flat fee stops covering the per-row cost. Free Apify plan: at most 100 per run.

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

**Required in Metrics and Ideas modes** (Competitors mode uses `domain` instead and ignores this). In Metrics: up to 1000 keywords per run. In Ideas: up to 20 seeds. Billing is per batch, not per keyword — a run of 1000 keywords costs exactly the same as a run of 1. Anything past the limit is trimmed with a note in the log. Free Apify plan: the first 50 keywords per run are processed (up to 1,000 on paid Apify plans) and an account can start 5 runs a day.

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

Country to measure search demand in. Unrecognised codes fall back to United States with a note in the log.

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

Optional. A city, state or region inside the country above, written the way Google Ads names it: "Austin, Texas" or "Austin,Texas,United States". A numeric Google Ads location code also works. Leave empty to measure the whole country. A city run uses Google Ads volume for that place. Bing, keyword difficulty, search intent and the long history series stay country-level and are not charged for a city.

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

Language of the searchers. Left on Auto, it follows the country — Germany queries German, Japan queries Japanese — which is almost always what you want. These are exactly the 46 languages Google Ads accepts; note its quirks: Hebrew is `iw`, Norwegian is `no`, and Chinese is regional (`zh_CN` / `zh_TW`). Microsoft/Bing supports English, French and German only — any other language skips the Bing half without charging.

## `includeGoogle` (type: `boolean`):

Search volume, CPC, competition level and index, top-of-page bid range, keyword difficulty, search intent, and up to ~93 months of monthly history from Google.

## `includeBing` (type: `boolean`):

The same metrics from Microsoft Ads, on the same rows, so you can compare the two networks directly. **Microsoft sells keyword data in six countries only — US, UK, Canada, Australia, Germany and France — and in English, French and German.** Anywhere else the row still arrives, with a `bing_status` of `unsupported_location` or `unsupported_language`, and the Bing batch is not charged. Ignored in ideas mode.

## `includeAiVolume` (type: `boolean`):

Also return how often each keyword is asked in AI assistants, with 12 months of that history. One flat fee for the whole list. Metrics mode only, charged after the data comes back. Ideas and competitors runs ignore this and are not charged for it.

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

Stop after this many discovered keywords. One expansion can return up to 20,000; the fee is identical either way, so raise this freely if you want the full set. Free Apify plan: at most 100 ideas per run.

## `minVolume` (type: `integer`):

Drop rows whose monthly search volume is below this on both engines. Applied after the lookup — useful for cutting the long tail out of an Ideas run.

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

How the upstream ranks results before any trim. Matters most in Ideas mode, where the result set is far bigger than your maximum and this decides which keywords survive.

## `searchPartners` (type: `boolean`):

Count each engine's partner network in the volumes, not just the engine's own results. Raises volumes; off by default, matching both Keyword Planners.

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

Let adult-content keywords through. Google filters them out by default. Google-side only.

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

Start of the history window as `yyyy-mm-dd`. Setting either date switches the run to the Ads endpoint, which caps history at 12 months and reaches back four years. Leave both empty for the default ~93-month series.

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

End of the history window as `yyyy-mm-dd`. Leave empty to run to the latest available month. Setting either date caps history at 12 months — see 'History from'.

## `bypassRunCache` (type: `boolean`):

Force a live upstream lookup instead of reusing a cached result. Charges the full batch fees. Leave off unless you are deliberately re-testing.

## Actor input object example

```json
{
  "mode": "metrics",
  "domain": "ahrefs.com",
  "maxDomainKeywords": 1000,
  "keywords": [
    "running shoes",
    "trail running shoes",
    "best running shoes for flat feet"
  ],
  "country": "us",
  "language": "",
  "includeGoogle": true,
  "includeBing": true,
  "includeAiVolume": false,
  "maxIdeas": 1000,
  "minVolume": 0,
  "sortBy": "relevance",
  "searchPartners": false,
  "includeAdultKeywords": false,
  "bypassRunCache": false
}
```

# Actor output Schema

## `results` (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 = {
    "domain": "ahrefs.com",
    "keywords": [
        "running shoes",
        "trail running shoes",
        "best running shoes for flat feet"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/keyword-metrics").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 = {
    "domain": "ahrefs.com",
    "keywords": [
        "running shoes",
        "trail running shoes",
        "best running shoes for flat feet",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("memo23/keyword-metrics").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 '{
  "domain": "ahrefs.com",
  "keywords": [
    "running shoes",
    "trail running shoes",
    "best running shoes for flat feet"
  ]
}' |
apify call memo23/keyword-metrics --silent --output-dataset

```

## MCP server setup

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

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/HCtUG8wyEgBLXl409/builds/l7hJHsv0JmhyFzpnh/openapi.json
