Google Keyword Search Volume API: 7 Countries + Global
Pricing
from $2.00 / 1,000 keyword results
Google Keyword Search Volume API: 7 Countries + Global
Bulk Google keyword search volume API: monthly volume, CPC, competition and 12-month trend for up to 10,000 keywords a run. Global, US, UK, Canada, Australia, New Zealand, India and South Africa only. Keywords with no data return null and are charged; invalid and failed ones are free.
Pricing
from $2.00 / 1,000 keyword results
Rating
0.0
(0)
Developer
Quarrywise
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 hours ago
Last modified
Categories
Share
Keyword search volume API for bulk keyword lists: paste up to 10,000 keywords and get monthly search volume, cost per click (CPC) and advertiser competition for each one, in one table you can download as JSON, CSV or Excel or read through the API. The numbers are Google Keyword Planner data from the Keywords Everywhere API, used with the provider's permission; not affiliated with Keywords Everywhere or Google.
Markets: Global, United States, United Kingdom, Canada, Australia, New Zealand, India and South Africa only. Other countries are not available from our data source, and this Actor does not estimate them. There is no language setting.
What you get for every keyword
- Search volume: the source's own 12-month average of monthly searches in the market you choose, rounded the way Google Keyword Planner rounds (for example 301,000 rather than 291,500). That is what we measured in our live test on 2026-10-26: every volume matched the average of the source's 12 monthly values, snapped to Keyword Planner's volume steps. The source does not document it. Spikes in those monthly values can raise it (see "Known data issue" below).
- CPC: the cost per click advertisers pay, converted into the currency you choose (about 130
currencies). In our live test the same keyword cost USD 0.47 with
usdand GBP 0.35 withgbp: a real conversion, not a relabelled dollar amount. The list is the source's own and still holds ten retired currencies, marked "retired" (ANG, BYR, EEK, HRK, MRO, SKK, SLL, STD, VEF and ZMK); whether the source still converts them at a current rate is not known (we checked conversion live for USD, GBP and AUD only), so use EUR instead of HRK, EEK and SKK. - Competition: the advertiser competition index from 0 (low) to 1 (high), as reported by the source. It is about paid search, not SEO ranking difficulty. A 0 may mean the source has no competition data for the keyword rather than low competition (in our live test a keyword with 480 searches a month came back with competition 0 and no bid estimate).
- Monthly values, on request: the source's 12 monthly values for this keyword, labelled by the
source, oldest first, with ISO months (
2026-09). Off by default (includeTrend), same price. Read "Known data issue" below before you use them: they looked a month or more older than their labels in our check. - An honest "no data": a keyword the source has no data on gets
status: "no_data"and empty (null) numbers, never a made-up 0. See "No data is not zero" below. - Clean input handling: pasted blocks are split into lines; case, extra spaces, invisible
characters and match-type symbols (
"...",[...],+word) are removed; duplicates are looked up and charged once.
Typical uses: keyword research and content planning, sizing a list of topics before writing, checking CPC before a paid campaign, enriching a spreadsheet or a database of keywords, and giving an AI agent or an automation real search demand numbers.
How to use it
- Paste your keywords, one per line (up to 10,000 lines per run).
- Pick the market (country), the CPC currency and the data source.
- Run it. Each keyword becomes one row. The Overview tab shows volume, CPC and competition. The
"Status and errors" tab shows every row with its status and, for
invalidandfailedrows (which are free), the reason. Dataset views cannot filter rows, and the API returns every row, so to list only the problems, download the dataset as CSV or Excel and filter thestatuscolumn forinvalidandfailed, or filterstatusin your own code after reading the items.
From code or an automation, call the Apify API, for example
POST https://api.apify.com/v2/acts/quarrywise~keyword-search-volume-api/run-sync-get-dataset-items
with your Apify token in the Authorization: Bearer header and the input JSON as the body. The
call waits at most 300 seconds; for lists above about 5,000 keywords start the run asynchronously
and read the dataset when it finishes. Apify's apps for Make, Zapier and n8n, and Apify's MCP server
for AI agents (https://mcp.apify.com?tools=quarrywise/keyword-search-volume-api), work the same way.
Input
| Field | What it does | Default |
|---|---|---|
keywords | Keywords, one per line, 1 to 10,000 lines per run (pasted blocks count line by line). Duplicates (ignoring case and spacing) are looked up and charged once | required |
country | global, us, uk, ca, au, nz, in or za. global sends no country filter and returns the source's global data | us |
currency | Currency for CPC only, as a lowercase code such as usd, gbp or eur. Search volume is not affected | usd |
dataSource | gkp: Google Keyword Planner only. cli: Google Keyword Planner plus clickstream data. Same price either way | gkp |
includeTrend | Adds the source's 12 monthly values for this keyword, labelled by the source. For rough direction only, not timing (see "Known data issue" below). Same price | false |
There is no language setting: the source has none, and volume is per market.
Example:
{"keywords": ["keyword research", "content marketing", "email marketing"],"country": "us","currency": "usd","dataSource": "gkp","includeTrend": false}
Output fields
One dataset row per unique keyword: the invalid rows come first, then every other keyword
(ok, no_data and failed rows) in the order you entered them (the first occurrence counts when
a keyword appears twice). To match rows to your own list, join on input_keyword (as you entered
it) or keyword (as looked up) rather than on row position. Keywords that were not looked up
because the run reached your maximum charge get no row. After a restart a keyword can appear twice
(see "Aborts, restarts and safety stops" below): keep its ok or no_data row. Every row has the
same fields.
| Field | Meaning |
|---|---|
keyword | The keyword as looked up: lowercase, spaces collapsed, match-type symbols removed |
input_keyword | The keyword as you entered it (the first spelling when duplicates were merged) |
status | ok, no_data, invalid or failed |
search_volume | The source's own 12-month average of monthly searches, rounded as Keyword Planner rounds; spikes in the source's monthly values can raise it (see "Known data issue"); null on no_data, invalid and failed rows (an ok row always has it) |
cpc | Cost per click in cpc_currency, two decimals as the source sends them; null when there is no data, when the source sent 0.00 (no bid estimate, see below), or when the value could not be read or trusted; never 0 |
cpc_currency | The currency code you chose, for example USD; null when cpc is null |
competition | Advertiser competition index as reported by the source, 0 to 1; 0 may mean the source has no competition data for the keyword, not low competition; null when there is no data or the value could not be read |
trend | The source's 12 monthly values for this keyword, labelled by the source: [{"month": "2026-09", "search_volume": 480}, ...], oldest first; for rough direction only, not timing (see "Known data issue"); null when not requested (the default) or no data |
country | The market, or global |
data_source | gkp or cli |
error_reason, error_message | Why an invalid or failed keyword has no data; null otherwise |
retrieved_at | When the row was produced (ISO 8601, UTC) |
The source returns every keyword exactly as it was sent and in the same order (checked in our
live test); the Actor still matches each answer to its keyword by the keyword itself, and a keyword
it cannot match safely gets a free not_returned row instead of someone else's numbers.
Example rows, built from the source's answers in our live test on 2026-10-26 (country us, data
source gkp, currency usd, includeTrend: true so the first row shows the source's monthly
values; with the default false its trend is null):
{"keyword": "running shoes","input_keyword": "Running Shoes","status": "ok","search_volume": 301000,"cpc": 0.47,"cpc_currency": "USD","competition": 1,"trend": [{ "month": "2025-10", "search_volume": 550000 },{ "month": "2025-11", "search_volume": 368000 },"... 10 more months, oldest first, up to 2026-09 ..."],"country": "us","data_source": "gkp","error_reason": null,"error_message": null,"retrieved_at": "2026-10-26T17:51:49.000Z"}
{"keyword": "quokka sanctuary entrance tickets","input_keyword": "quokka sanctuary entrance tickets","status": "no_data","search_volume": null,"cpc": null,"cpc_currency": null,"competition": null,"trend": null,"country": "us","data_source": "gkp","error_reason": null,"error_message": null,"retrieved_at": "2026-10-26T17:51:49.000Z"}
A run summary (keyword counts, charged rows, warnings and the settings used) is saved in the
key-value store record OUTPUT, not in the dataset. A run that is not stopped early also says on
the run page what it saved, for example
Done: 3 keyword rows saved (3 charged). Details in the OUTPUT record.No data is not zero
The source answers a keyword it has no data on with a volume of 0, a CPC of 0.00, a competition of 0
and an empty trend, without a "not found" flag (seen in our live test: the keyword still costs the
source one credit). Showing that as 0 searches would be misleading, so this Actor reads it as
status: "no_data" and leaves the numbers empty (null). That reading is our interpretation of an
answer with no volume and no monthly searches.
no_data: a volume of 0 where the trend is empty or no month is above 0 (every month 0 or without a value), with a CPC or competition value present as in the source's no-data answer. All numbers arenull. A bare volume of 0 with neither is a freefailedrow (unexpected_response), notno_data.- A volume of 0 with at least one month above 0 in the trend is a measured zero (the 12-month
average rounds to 0):
status: "ok",search_volume: 0. - A volume above 0 with an empty trend is
okwithtrend: []. - A missing volume is never shown as 0, and a row without a volume is never charged, not even as
no_data: when the source answers a keyword without a volume (not seen live), whatever its trend holds, the keyword gets a freefailedrow (unexpected_response). We do not work out a volume from the trend ourselves, because the source's rounding is not documented. A month the source sent without a value hassearch_volume: nullin the trend. - On
okrows the source sends a CPC of 0.00 when it has no bid estimate for the keyword (seen live for a keyword with 70 searches a month and a competition of 0.02). That is not a price of 0, so this Actor outputscpc: nullandcpc_currency: nullfor it (an average over your rows is not pulled down), and the run summary counts those rows ascpc_zero_as_null. - When the source sends CPC, competition or the trend in a format we cannot read, or reports the CPC
with another symbol than the one of the currency you chose, that value is
null, the row staysok, and the run summary says how many rows were affected. That symbol check only works for a currency with a symbol of its own: the source writes nine currencies as a bare$(ARS, AUD, CLP, COP, KYD, MOP, MXN, NZD and USD), so for those it cannot tell them apart. In our live test the source did convert:running shoesin Australia came back at 0.24 in AUD and 0.17 in USD.
no_data rows are charged like ok rows: the source bills us for every keyword it answers,
including keywords without data, and "no data" is a real answer about that keyword.
Known data issue: source data age (checked 2026-10-28)
The source labels its 12 monthly values with the last 12 months (on 2026-10-28: October 2025 to September 2026), but in our check the values looked older than their labels, by an amount that differs per keyword and per market:
- United States and Global: about 1 month late. Seasonal peaks fall in the month after the
event:
christmas giftspeaks in January,halloween costumesin November,in March andvalentines day giftsblack friday dealsin December. For 7 US keywords we compared with Google Ads data from another provider, every monthly value equalled that data for the month before. - Canada, Australia and the United Kingdom: often 2 to 3 months late, for some keywords more.
snow blowerin Canada peaks at June and July 2026 (165,000 each), against 8,100 for October to December 2025: a winter keyword peaking in summer, so far more than 3 months off.peaks in July to August in Canada and Australia (Mother's Day is in May there) and in June in the UK (Mothering Sunday was in March);mothers day giftsvalentines day giftspeaks in April in Canada. For 2 UK keywords compared with that other data, the values were 2 and 3 months older than their labels (a third UK keyword matched no single offset). Some keywords there look only about 1 month late:halloween costumesin Canada peaks in November, andchristmas giftsin January in Australia and in December and January (tied) in the UK. - Shared spikes. Unrelated commercial keywords carry identical spikes from about April 2026: in
the US,
crm software,project management softwareandblack friday dealsall show 550,000 (June), 246,000 (July), 201,000 (August) and 201,000 (September); in the Global data, four software keywords all show 823,000 for June 2026.
What it means for you:
- Use
trendfor rough direction only (for example a steady, rising or seasonal keyword), not for timing: do not read the month of a peak from it. That is why it is off by default. search_volumeis the source's own 12-month average, so such spikes can raise it. Globalhas aemail marketing softwaresearch_volumeof 201,000, while its values for October 2025 to March 2026 range from 8,100 to 22,200.- The
clidata source returned the same values for the keywords we checked. - This Actor passes the source's numbers through unchanged: it only converts month names to ISO months and sorts them oldest first (a comparison of the raw answers with our rows found 0 differences). Because the offset differs per keyword, we do not try to correct it.
Pricing
Pay per result: USD 2.00 per 1,000 keyword rows (USD 0.002 per keyword), on every Apify plan, plus Apify's small start fee per run.
- Charged:
okandno_datarows (keywords the source answered, including "no data"). - Free: duplicates (merged before lookup),
invalidkeywords (never sent), andfailedlookups (for example when the source does not answer). - Your maximum charge per run is respected: before every batch the Actor checks how many
keywords your remaining maximum charge can pay for and looks up only those. When it is used up the
run ends (it still shows as succeeded) with a status message saying how many keywords got no row,
the remaining keywords are neither looked up nor charged, and the run summary (
OUTPUT) showsstatus: "limit-reached"andkeywords_not_processed_budget. The lowest maximum charge you can set for this Actor is USD 0.05, which pays for 24 keywords after Apify's start fee. - Every Apify plan, the same limits. A keyword cap for Apify's free plan (100 keywords a run) is
built but switched off in this version, until we have checked how Apify reports paid plans to a
run; free-plan runs are not capped. The run log names the plan it detected, for information only
(
Plan: ...). If we switch the cap on, the changelog will say so first.
Cost examples, when every keyword is unique, valid and answered (each one a charged row):
| Run | Charged keyword rows | Cost |
|---|---|---|
The prefilled example (3 keywords, us) | 3 | USD 0.006 |
| 1,000 keywords | 1,000 | USD 2.00 |
| 10,000 keywords (the maximum per run) | 10,000 | USD 20.00 |
The costs are for the keyword rows only: Apify's small start fee per run comes on top. Duplicates, invalid keywords and failed lookups are free, so they make a run cheaper, never dearer. Set your maximum charge per run above the cost, since the start fee comes off it first: at exactly USD 20.00 a 10,000-keyword run stops at least one keyword short.
Rows that are free: invalid and failed keywords
status | error_reason | When |
|---|---|---|
invalid | empty | Nothing is left after removing spaces, invisible characters and match-type symbols |
invalid | too_long | Longer than 80 characters (Google Ads keyword limit) |
invalid | too_many_words | More than 10 words (Google Ads keyword limit) |
invalid | no_letters_or_digits | No letter or digit at all |
invalid | rejected_by_source | The source rejected this keyword as invalid |
failed | rejected_in_batch | The source rejected a request containing this keyword when the run had reached its limit of 30 rejected requests, so it stopped narrowing down which keyword caused it; try it again in a shorter list |
failed | not_returned | The source's answer did not include this keyword, or we could not match it safely (for example an echo that fits two of your keywords) |
failed | unexpected_response | The source's answer for this keyword had an unexpected format, or no volume |
failed | source_error | The source did not answer (timeout, server error or rate limit), or the run stopped early for a safety reason (see "Aborts, restarts and safety stops" below); error_message says which |
failed | service_unavailable | The keyword data service is temporarily unavailable for this Actor |
Invalid keywords are filtered out before any lookup: they would come back without data anyway. When the keyword data service is temporarily unavailable for this Actor, the run ends early with a message saying how many keywords were not looked up; those are not charged, so you can simply run them again later. When the source rejects the request settings themselves (the whole list and three single keywords from it), the run stops with a message that names the country, currency and data source it used, so you can check them.
Aborts, restarts and safety stops
- Abort. If you abort a run gracefully (the API's
gracefully=trueoption), the Actor sends no new lookups, waits up to 10 seconds for the lookup already on its way so its rows are written too, keeps every row written (charged when it isokorno_data) and writes a short run summary. An abort that is not graceful (the API default) stops the run at once: rows already written are kept and charged, the lookup on its way gets no row and is not charged, and no run summary is written. Either way, keywords not looked up get no row and are not charged. Rows answered for later keywords while the run is narrowing down a rejected keyword are not written either and not charged (the run summary says so). - Restarts. If Apify moves or restarts a run (a migration, a reboot or a crash), the restarted
run waits about 20 to 25 seconds until the platform's count of charged rows has settled, then
continues after the last row written, so no keyword is charged twice. A keyword whose row was
written just before a crash can get a second row: join on
keywordand keep itsokorno_datarow. A freeinvalidorfailedrow can also appear twice after a restart; the copies are identical, keep either. - When the lookups stop instead. A crash or kill before the run has charged its first row
(with 20 or more keywords left to look up), a restart the run cannot verify (its saved place
RESUME_POSITIONis missing, changed or out of date, or two restarts came at once), a charged count that does not settle within two minutes, a saved place the run could not write, or a set of rows whose write or charge failed: the run then charges nothing more for the rows concerned, gives the remaining keywords freefailedrows, and its status message says why. A run metamorphed into this Actor from another Actor looks nothing up: start this Actor directly. Known limit: if you resurrect a run that ended before its last keyword (for example aborted or timed out) and that was restarted before it ended (a reboot, a migration or a metamorph), the resurrected run cannot verify its saved place when Apify kept the restart counts from before the end (as it did in our checks), so it looks nothing up and gives the keywords left freefailedrows; start a new run for those. A run that Apify moved before it had saved anything (no rows, nothing charged) waits about 60 seconds, then starts from the beginning. Please do not edit, delete or put back an older copy ofRESUME_POSITIONwhile a run may still be restarted: an older copy put back by hand can make a restart charge some of your keywords a second time, past your maximum charge, if Apify's count of charged rows lags by more than about 25 seconds; a deleted copy can do the same after Apify moves the run, if both that count and the run's dataset lag by more than about 60 seconds. We measured lags of about 5 to 6 seconds. - Safety stops. A run starts small: its first batches hold 20, 20, 40 and 80 keywords before
reaching 100. It stops looking up keywords, with free rows for the rest, after two failed batches
in a row, after 30 rejected requests, when more keywords come back without a usable answer (or
fail in a way that may have used credits) than the larger of 20 and 5% of the keywords sent, or
when 20 have done so before any row was charged, or after 200 keywords in all came back
unusable. A request that goes unanswered (a timeout or a
network error) before the first charge also ends the lookups, because whether it used credits is
not confirmed; a server error that the source answers, and that the balance shows was not
billed, does not. The run summary counts such keywords as
unpaid_lookups.
Data source, privacy and limits
- Source: Keywords Everywhere API, used with the provider's permission; not affiliated with Keywords Everywhere or Google.
The figures are Google Keyword Planner data (with
cli, blended with clickstream data). - Your keywords: they are sent to that provider for lookup and are not stored by us after the run.
There is no cache across runs; each run looks its keywords up fresh. Your keywords are
returned to you exactly as you entered them (
input_keyword), so the Actor does not filter them; please do not put personal data in a keyword list. - Personal data: the source returns search statistics only, no personal data.
- Per run: up to 10,000 keyword lines. Longer lists: split them over several runs.
- Speed: keywords are looked up up to 100 at a time (the first batches of a run hold 20, 20, 40 and 80), and each lookup follows a free balance read: one request to the provider at a time, at most one per second in all. In our live test one lookup request (1 to 3 keywords) was answered in about 0.2 seconds. A full 100-keyword request has not been timed yet, so 10,000 keywords (about 103 lookups and as many balance reads, so at least about 3.5 minutes) taking about 4 to 6 minutes is still an estimate.
- Markets: the seven countries above plus Global, with no language setting. Volume is counted
per market. The source does answer keywords in other languages (in our live test the French
keyword
chaussures de runninghad 70 searches a month in the United States and 10 in Canada), but whether every language spoken in a market is counted is not confirmed, so we do not claim it.
Provider
Provided by Quarrywise, a trade name of Picazzo Research & Development, Zinkstraat 24, Box C4687, 4823 AD Breda, the Netherlands. KvK 42060545, VAT NL005464235B85. Contact: hello@quarrywise.com or the Issues tab.