# Keyword Research — Ideas, Difficulty & Search Intent (`saliga/keyword-research`) Actor

Keyword ideas, long-tail suggestions and related keywords from your seed keywords, with search volume, keyword difficulty, search intent, CPC and trend. Or check difficulty and intent for your own list. Up to 10 countries per run.

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

## Pricing

from $1.40 / 1,000 keyword results

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

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

## What's an Apify Actor?

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

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

## How to integrate an Actor?

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

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

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

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

# README

Turn a few seed keywords into hundreds of new ones, each with **search volume, keyword difficulty, search intent, CPC and trend**. Or paste your own keyword list and get difficulty and intent for every keyword. Up to 10 countries in one run, one row per keyword and country.

**$2 per 1,000 keywords** ($1.80, $1.60 and $1.40 on the Starter, Scale and Business plans), **plus $0.02 per lookup.** A lookup is one request to the keyword database: one page of up to 1,000 keyword ideas, one seed in the suggestions and related modes, or up to 700 of your keywords in the analyse mode. Keywords without data, keywords your filters drop, and failed lookups are free. No subscription, and platform usage is included. (Plus a tiny $0.00005 start fee per run.)

### What you get

- **Four ways to research.** *Keyword ideas*: the broadest list from up to 200 seeds at once, most relevant first. *Long-tail suggestions*: longer phrases that contain each seed. *Related searches*: Google's "related searches" around each seed, up to four levels deep. *Analyse my keywords*: difficulty, intent and volume for a list you already have.
- **Difficulty and intent on every row.** Keyword difficulty from 0 to 100 (with a plain label: very easy to very hard), the main search intent (informational, navigational, commercial, transactional) and any secondary intents.
- **Filter before you pay.** Minimum search volume, maximum difficulty and intent are applied at the source, so you only pay for keywords you want.
- **Trend already worked out.** 12 months of search volume per keyword, with the 3-month trend and peak month as columns. For year-on-year change and up to 48 months of history, use [Keyword Search Volume](https://apify.com/saliga/keyword-search-volume).
- **How strong the top 10 is.** The average number of referring domains of the pages ranking for each keyword, a quick check next to the difficulty score.
- **Many countries in one run.** Up to 10 countries, each in its own main language unless you choose one.
- **Bring keywords from anywhere.** Paste them, link a text, CSV or JSON file (a published Google Sheet works), or point to the dataset of another Actor.
- **Stops at your spending limit.** Set "Maximum cost per run" and the run never goes over it.

### Typical uses

- **Plan content.** Start from three topic words, filter to difficulty 30 or below with informational intent, and get a list of articles you can rank for.
- **Find buying keywords.** Filter by commercial and transactional intent and sort by CPC.
- **Score a list you already have.** Analyse a keyword export from any tool and add difficulty and intent to it.
- **Compare markets.** One seed list, several countries, one table.

### Input

```json
{
  "keywords": ["project management software"],
  "mode": "ideas",
  "countries": ["US", "GB"],
  "maxResults": 500,
  "maxKeywordDifficulty": 40,
  "intents": ["commercial", "transactional"]
}
```

| Field | Meaning |
|---|---|
| `keywords` | Seed keywords, or the keywords to analyse. Up to 80 characters and 10 words each. Duplicates are removed. |
| `mode` | `ideas` (default), `suggestions`, `related` or `overview` (analyse my keywords). |
| `countries` | Up to 10 countries: two-letter codes (`US`, `GB`, `TR`) or names. Default `US`. |
| `language` | Optional language code (`en`, `es`, `de`, …). Empty means each country's main language. |
| `maxResults` | Ideas, suggestions and related: keywords per country, up to 10,000. Default 300. |
| `maxSeeds` | How many of your keywords are used as seeds, up to 200. Default 20. |
| `depth` | Related searches only: 1 to 4 levels. Default 2. |
| `minSearchVolume`, `maxKeywordDifficulty`, `intents` | Filters. Dropped keywords are not charged. |
| `keywordsUrl`, `datasetId`, `keywordField` | Other ways to pass keywords, and the name of the column or field that holds them. |
| `maxKeywords` | Analyse mode: stop after this many keywords (up to 10,000). |

### Output

One row per keyword and country.

```json
{
  "keyword": "asana project management software",
  "country": "US",
  "language": "en",
  "searchVolume": 18100,
  "keywordDifficulty": 47,
  "difficultyLevel": "medium",
  "intent": "commercial",
  "otherIntents": [],
  "cpcUsd": 8.6,
  "competition": 0.12,
  "competitionLevel": "LOW",
  "lowTopOfPageBidUsd": 2.43,
  "highTopOfPageBidUsd": 28.68,
  "trend3mPct": 48.9,
  "trendDirection": "rising",
  "peakMonth": 9,
  "dataMonth": "2026-08",
  "monthlySearches": [{ "year": 2025, "month": 9, "searches": 49500 }, "…"],
  "avgReferringDomainsTop10": 64.8,
  "source": "ideas",
  "seed": null,
  "status": "ok",
  "charged": true
}
```

A real row from a run on 17 October 2026: ideas for `project management software` in the United States (293 keywords, one lookup, $0.61).

| Field | Meaning |
|---|---|
| `searchVolume` | Average monthly searches over the last 12 months |
| `keywordDifficulty`, `difficultyLevel` | How hard it is to reach the top 10, 0 to 100, from the backlink profiles of the pages ranking now. Labels: under 15 very easy, under 30 easy, under 50 medium, under 70 hard, 70+ very hard |
| `intent`, `otherIntents` | Main search intent, and any secondary intents |
| `cpcUsd`, `competition`, `competitionLevel` | Google Ads cost per click (USD) and advertiser competition (0 to 1, and `LOW` / `MEDIUM` / `HIGH`) |
| `lowTopOfPageBidUsd`, `highTopOfPageBidUsd` | Top-of-page bid range |
| `monthlySearches`, `trend3mPct`, `trendDirection`, `peakMonth`, `dataMonth` | Monthly series (oldest first) and the trend worked out from it. `trendDirection` is `rising` at +15 % or more over 3 months, `falling` at −15 % or less, otherwise `flat` |
| `avgBacklinksTop10`, `avgReferringDomainsTop10` | Average backlinks and referring domains of the pages in the top 10 |
| `wordCount`, `coreKeyword` | Words in the keyword; the main form when it is a close variant of another keyword |
| `source`, `seed`, `depth` | The mode, the seed a keyword came from (suggestions and related), and the related-search level |
| `status`, `note`, `charged` | `ok`, or why there is no figure. `charged` is `true` only on rows you paid for |
| `index` | Analyse mode: position of the keyword in your list (0-based) |

A run summary is saved as `SUMMARY` in the run's key-value store. Seeds or keywords that were not looked up are listed, uncharged, and saved in full as `NOT_LOOKED_UP`.

#### Rows with no keyword fee

| `status` | What happened |
|---|---|
| `no_data` | No figures for this phrase in this country (analyse mode), or no new keywords for a seed. The lookup fee for that request is still charged. |
| `invalid_keyword` | Over 80 characters, over 10 words, or a symbol that cannot be looked up. |
| `input_error` | A country the database does not cover, a language not available there, or an unknown intent. Nothing is guessed. |
| `spending_limit` | Your "Maximum cost per run" was reached. |
| `free_plan_limit` | Past the free-plan allowance (see below). |
| `skipped` | Five lookups in a row returned nothing, so the run stopped buying more. Check the seeds, country, language and filters. |
| `throttled`, `provider_error` | The data source was busy or unavailable. Run again later. |

### What it costs

| Run | Price (no discount) |
|---|---|
| 300 ideas from 5 seeds, 1 country | $0.62 |
| 1,000 ideas, 1 country | $2.02 |
| 1,000 ideas in each of 5 countries | $10.10 |
| 20 seeds × 50 long-tail suggestions | $2.40 |
| Analyse 5,000 of your keywords | $10.16 |

These assume every keyword has data and passes your filters. On a paid Apify plan the keyword fee is 10 %, 20 % or 30 % lower.

### Apify free plan

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

### Covered countries

Albania, Algeria, Angola, Argentina, Armenia, Australia, Austria, Azerbaijan, Bahrain, Bangladesh, Belgium, Bolivia, Bosnia and Herzegovina, Brazil, Bulgaria, Burkina Faso, Cambodia, Cameroon, Canada, Chile, Colombia, Costa Rica, Côte d'Ivoire, Croatia, Cyprus, Czechia, Denmark, Ecuador, Egypt, El Salvador, Estonia, Finland, France, Germany, Ghana, Greece, Guatemala, Hungary, India, Indonesia, Ireland, Israel, Italy, Japan, Jordan, Kazakhstan, Kenya, Latvia, Lithuania, Malaysia, Malta, Mexico, Moldova, Monaco, Morocco, Myanmar, Netherlands, New Zealand, Nicaragua, Nigeria, North Macedonia, Norway, Pakistan, Panama, Paraguay, Peru, Philippines, Poland, Portugal, Romania, Saudi Arabia, Senegal, Serbia, Singapore, Slovakia, Slovenia, South Africa, South Korea, Spain, Sri Lanka, Sweden, Switzerland, Thailand, Tunisia, Türkiye, Ukraine, United Arab Emirates, United Kingdom, United States, Uruguay, Venezuela, Vietnam.

Other countries come back as an uncharged `input_error` row. For Google Ads search volume in any country, use [Keyword Search Volume](https://apify.com/saliga/keyword-search-volume).

### Using it from an AI agent or code

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

### Next steps with your keywords

- **Exact Google Ads volume and up to 48 months of history:** send the keywords to [Keyword Search Volume](https://apify.com/saliga/keyword-search-volume) with `datasetId` set to this run's dataset.
- **Merge, dedupe and filter** the results of several runs: [Dataset Merge & Dedup Datasets](https://apify.com/saliga/dataset-merge-dedupe).
- **Call any API for each keyword:** [Bulk HTTP Requests](https://apify.com/saliga/bulk-http-requests).

### Good to know

- The figures come from a licensed SEO data provider's keyword database, built from Google Ads data and search results. You do not need a Google Ads, Semrush or Ahrefs account. Nothing is scraped from those tools.
- Search volumes are rounded and close variants can share one figure, as in Google Keyword Planner. Difficulty and intent are estimates.
- This Actor is not affiliated with, endorsed by or sponsored by Google. "Google" and "Google Ads" are trademarks of Google LLC.
- A run that is moved to another server, or resurrected, continues where it stopped. Nothing is looked up or charged twice.
- Pricing: one `keyword-result` charge per keyword row with data, one `lookup` charge per request the database answers, plus $0.00005 when a run starts.
- Code examples (curl, Python, Node.js, n8n) for this and the other Actors: [github.com/msalihk/apify-actor-examples](https://github.com/msalihk/apify-actor-examples).
- Questions or a missing feature: open an issue on the Actor page.

### FAQ

**Which mode should I use?** Start with *keyword ideas*: it gives the broadest list from all your seeds in one lookup. Use *long-tail suggestions* when you want phrases that contain your seed word for word, and *related searches* to explore around a topic.

**How is keyword difficulty worked out?** From the backlink profiles of the pages ranking in the top 10 now: the stronger they are, the higher the score.

**Can I get more than 1,000 ideas?** Yes, up to 10,000 per country. Each page of 1,000 is one lookup.

**Why did I get fewer keywords than I asked for?** The database had no more for those seeds, or your filters dropped the rest. You only pay for what is delivered, plus the lookups.

### More from this developer

- [Competitor Keywords](https://apify.com/saliga/competitor-keywords): every Google keyword a domain or page ranks for, and its organic competitors, $2 per 1,000 rows.
- [Domain SEO Overview](https://apify.com/saliga/domain-seo-overview): organic keywords, estimated traffic and top-10 rankings for thousands of domains, $5 per 1,000 domains.
- [Google SERP Rank Tracker](https://apify.com/saliga/serp-rank-tracker): Google positions for your keywords by country and device, with AI Overview checks, $2 per 1,000 result pages.
- [Google Trends API](https://apify.com/saliga/google-trends): interest over time, by region and related queries for hundreds of keywords, $6 per 1,000 queries.
- [Keyword Search Volume](https://apify.com/saliga/keyword-search-volume): Google Ads search volume, CPC and up to 48 months of trend for a keyword list, $2 per 1,000 keywords.
- [Sitemap Extractor](https://apify.com/saliga/sitemap-extractor): every URL a website lists in its sitemaps, with lastmod, images and hreflang, $0.25 per 1,000 URLs.
- [Broken Link Checker](https://apify.com/saliga/broken-link-checker): crawl a site and find broken links and images, with the pages they are on.
- [Tech Stack Detector](https://apify.com/saliga/tech-stack-detector): which CMS, ecommerce platform, analytics and hosting a website uses, $1.50 per 1,000 websites.
- [Website Screenshot + Change Detection](https://apify.com/saliga/website-screenshot-change-detection): screenshots of many URLs on desktop and mobile, with visual change detection between runs.
- [Dataset Merge & Dedup Datasets](https://apify.com/saliga/dataset-merge-dedupe): merge, dedupe and filter the results of several runs into one dataset.

# Actor input Schema

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

Seed keywords to grow into new ones, or (in "Analyse my keywords" mode) the keywords to check. Up to 80 characters and 10 words each.

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

Keyword ideas: the broadest list, from up to 200 seeds at once, most relevant first. Suggestions: longer phrases that contain each seed. Related: Google's "related searches" around each seed. Analyse my keywords: difficulty, intent, volume and CPC for your own list.

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

Up to 10 countries per run: two-letter codes (US, GB, DE, FR, TR) or names. Each country is looked up on its own. Covered countries are listed in the README.

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

Optional language code such as en, es, de or fr. Leave empty to use each country's main language (for example es for Mexico).

## `maxResults` (type: `integer`):

For ideas, suggestions and related: how many keywords to return per country (the most relevant or highest volume first). You pay per keyword returned.

## `maxSeeds` (type: `integer`):

For ideas, suggestions and related: how many of your keywords are used as seeds. Keyword ideas use up to 200 seeds in one lookup; suggestions and related are one lookup per seed.

## `depth` (type: `integer`):

Only for related searches: 1 is Google's related searches of the seed, each further level adds the related searches of those (up to 4).

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

Keep only keywords with at least this many searches a month. Filtered keywords are not charged.

## `maxKeywordDifficulty` (type: `integer`):

Keep only keywords at or below this difficulty (0-100). Leave empty for all.

## `intents` (type: `array`):

Keep only keywords with these main intents. Leave empty for all.

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

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

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

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

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

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

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

Only for "Analyse my keywords": stop after this many keywords. 0 means the maximum of 10,000.

## Actor input object example

```json
{
  "keywords": [
    "project management software"
  ],
  "mode": "ideas",
  "countries": [
    "US"
  ],
  "maxResults": 300,
  "maxSeeds": 20,
  "depth": 2,
  "minSearchVolume": 0,
  "keywordField": "keyword",
  "maxKeywords": 0
}
```

# Actor output Schema

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

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

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

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

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

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

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

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

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "keywords": [
        "project management software"
    ],
    "countries": [
        "US"
    ]
};

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

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

```

## MCP server setup

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

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/5yKuPQiGSlInf8lAD/builds/nQdc0tfc2BT0Ehqrf/openapi.json
