# Competitor Keywords Finder (`blueskyscraper/competitor-keywords-finder`) Actor

\[from $1.50/1K keywords] Find every keyword a competitor domain or URL ranks for on Google: position, ranking URL, search volume, CPC, keyword difficulty, search intent, estimated traffic, position change. Find competitors too. No subscription, no run fee.

- **URL**: https://apify.com/blueskyscraper/competitor-keywords-finder.md
- **Developed by:** [BlueskyScraper](https://apify.com/blueskyscraper) (community)
- **Categories:** SEO tools, Marketing, AI
- **Stats:** 4 total users, 3 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 keywords

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

**Competitor Keywords Finder** shows **what keywords a website ranks for on Google** — for any competitor domain or single page URL, in 94 countries. Every row is one **ranked keyword** of one domain with its **Google position**, the **ranking URL**, **search volume**, **CPC**, Google Ads **competition**, **keyword difficulty**, **search intent**, **estimated traffic (ETV)**, the **position change** since the previous check and the **SERP features** on that results page.

It is a **SEMrush alternative for competitor keyword research** without a subscription: put in one or many competitors, set the country, language and filters, and get one flat table. Optional add-ons **find the organic competitors** of a domain, pull **their** keywords in the same run, and add a **summary row per domain**. **$0.0015 per keyword on paid plans ($0.002 on the Apify Free plan). Keywords without search volume data are free. No fee per run, no login, no API key of your own.**

### What is Competitor Keywords Finder?

It is an **organic keywords API** and **competitor keyword research tool** in one Actor. You enter `ahrefs.com`, and it answers "which Google keywords bring this site its traffic?" — sorted by estimated traffic, search volume, position, CPC or keyword difficulty. Enter a page URL such as `https://ahrefs.com/keyword-generator`, and you get the keywords of that one page.

Search volume, CPC and competition are aggregated from Google Ads Keyword Planner and clickstream data via a licensed data provider; positions come from that provider's regular checks of Google results pages. Each row says when the results page was last checked (`serpCheckedAt`). You do not need an account with any SEO tool — the Actor handles the data access and bills you per keyword row.

What it is **not**: it does not crawl Google live for every keyword, it does not show rankings from the last hour, and keyword difficulty and estimated traffic are **model estimates**, the same kind every SEO tool shows, not numbers Google publishes.

### What data can Competitor Keywords Finder extract?

One row per domain and ranked keyword (`type = "keyword"`):

| Field | Example | Meaning |
|---|---|---|
| `domain` | `ahrefs.com` | Competitor domain or page URL you entered |
| `keyword` | `ai rewriter` | Keyword the domain ranks for |
| `position` | `1` | Google position among results of the same type (1 = first organic result) |
| `absolutePosition` | `1` | Position counting every element on the page (ads, snippets, boxes) |
| `resultType` | `organic` | organic, paid, featured_snippet, local_pack or ai_overview_reference |
| `rankingUrl` | `https://ahrefs.com/writing-tools/paragraph-rewriter` | Competitor page that ranks |
| `rankingTitle` | `Free AI Paragraph Rewriter` | Title shown on Google |
| `searchVolume` | `49500` | Average monthly Google searches in the chosen country |
| `cpc` | `2.6` | Average cost per click in Google Ads, USD |
| `competition`, `competitionLevel` | `0.28`, `LOW` | Google Ads competition |
| `keywordDifficulty` | `28` | 0 (easy) to 100 (hard) |
| `searchIntent` | `commercial` | informational, navigational, commercial or transactional |
| `estimatedTraffic` | `15950.57` | Estimated monthly visits from this keyword (ETV) |
| `estimatedTrafficCost` | `41471.49` | What that traffic would cost in Google Ads per month, USD |
| `previousPosition`, `positionChange` | `1`, `0` | Absolute position at the previous check and the change (positive = moved up) |
| `isNew`, `isUp`, `isDown`, `isLost` | `false` | Ranking movement flags |
| `serpFeatures` | `["organic", "product_considerations", "related_searches"]` | What else is on that Google page |
| `searchVolumeTrendYearly` | `-33` | Search volume change over the last year, % |
| `targetType` | `domain` | domain or page |
| `competitorOf` | `backlinko.com` | Filled when the row belongs to a competitor the Actor found |
| `location`, `language` | `United States`, `en` | Country and language used |
| `serpCheckedAt` | `2026-07-30 05:03:58 +00:00` | When the results page was last checked |
| `charged` | `true` | false = no search volume data, row is free |

Position, URL, volume, CPC, difficulty, intent and traffic sit **in one row**, so you can sort and filter the table without joining exports from three tools.

#### Competitor rows (add-on)

With **Find competitors of each domain** on, you also get one row per organic competitor (`type = "competitor"`): `domain`, `competitorOf`, `competitorRank`, `sharedKeywords`, `avgPosition` on the shared keywords, `sharedKeywordsTraffic`, the competitor's `totalKeywords`, `estimatedTraffic`, `estimatedTrafficCost`, `top3Keywords`, `top10Keywords`. Competitors are sorted by shared keywords; Google, YouTube, Wikipedia and other giant sites are left out.

#### Domain summary rows (add-on)

With **Add a summary row per domain** on, each domain gets one row (`type = "domainSummary"`): `organicKeywords`, `matchingKeywords`, `estimatedTraffic`, `estimatedTrafficCost`, `top1Keywords`, `top3Keywords`, `top10Keywords`, `pos11to20Keywords`, `pos21to100Keywords`, `newKeywords`, `upKeywords`, `downKeywords`, `lostKeywords`. The counts follow your filters and selected result types. It is off by default, so the default table has one row type only.

### How much does it cost to find competitor keywords?

| Event | Free plan | Starter (Bronze) | Scale (Silver) | Business (Gold) |
|---|---|---|---|---|
| 💰 Keyword (one ranked keyword row with search volume) | $0.002 | **$0.0015** | $0.0015 | $0.0015 |
| Competitor (add-on, one competitor found) | $0.002 | **$0.0015** | $0.0015 | $0.0015 |
| Domain summary (add-on, one row per domain) | $0.003 | **$0.0027** | $0.0024 | $0.0021 |
| Run start | $0 — no start fee | $0 | $0 | $0 |
| Keywords without search volume data, error rows | $0 | $0 | $0 | $0 |

On paid plans that is **$1.50 per 1,000 ranked keywords**, about **666 keywords per $1**. On the Apify Free plan it is $2 per 1,000, so the $5 of monthly free credit covers about 2,500 keywords. Platinum and Diamond plans pay the Business price.

Filters run **before** the limit, at the data source: keywords you filter out are never fetched and never billed. **Max keywords per domain** and **Max keyword rows per run** are hard ceilings on what you pay. The default run — 20 keywords of ahrefs.com — costs **$0.03** on paid plans ($0.04 on the Free plan) and finished in about 4 seconds in our test.

A built-in spend guard stops a run early when the domains return very few keywords for the requests they need (for example a long list of tiny sites that rank for almost nothing). The log and the run status say so; nothing extra is billed.

### How to find competitor keywords with Competitor Keywords Finder

1. Open the Actor and enter one or more **competitor domains or URLs**, one per line.
2. Set the **country** (name or two-letter code) and **language**.
3. Set **Max keywords per domain** and choose how to **sort** — estimated traffic is the default, so you get the keywords that bring the most visits first.
4. Optionally narrow the list: **min search volume**, **max Google position**, **max keyword difficulty**, **search intent**, **exclude brand keywords**, words to exclude or require.
5. Optionally switch on **Find competitors**, **Also pull keywords of found competitors** and **Add a summary row per domain**.
6. Press **Start**. Download the table as CSV, Excel or JSON, or read it through the API.

### ⬇️ Input

The prefilled input — one domain, United States, English, 20 keywords sorted by estimated traffic:

```json
{
  "domains": ["ahrefs.com"],
  "location": "United States",
  "language": "English",
  "maxKeywordsPerDomain": 20,
  "sortBy": "etv",
  "resultTypes": ["organic"]
}
```

#### Keyword gap: what several competitors rank for, without their brand names

```json
{
  "domains": ["backlinko.com", "semrush.com", "moz.com"],
  "location": "US",
  "maxKeywordsPerDomain": 500,
  "minSearchVolume": 100,
  "maxPosition": 10,
  "excludeBrandKeywords": true,
  "sortBy": "searchVolume"
}
```

All domains land in one table with a `domain` column — sort by `keyword` to see who ranks where.

#### Keywords of one page

```json
{
  "domains": ["https://ahrefs.com/keyword-generator"],
  "maxKeywordsPerDomain": 100,
  "resultTypes": ["organic", "ai_overview_reference"]
}
```

A URL with a path is analysed as a single page (`targetType = "page"`). In our test this page ranked for "keyword research" both as organic result #3 and as a reference inside the Google AI Overview.

#### Find competitors and pull their keywords in one run

```json
{
  "domains": ["backlinko.com"],
  "maxKeywordsPerDomain": 50,
  "findCompetitors": true,
  "maxCompetitors": 5,
  "analyzeCompetitorKeywords": true,
  "includeDomainSummary": true
}
```

#### Easy keywords with buying intent

```json
{
  "domains": ["backlinko.com"],
  "maxKeywordDifficulty": 30,
  "searchIntents": ["commercial", "transactional"],
  "includeWords": ["tool", "software", "best"],
  "sortBy": "keywordDifficulty"
}
```

| Field | Default | What it does |
|---|---|---|
| `domains` | `["ahrefs.com"]` | Domains or page URLs (up to 200 per run) |
| `location` | `United States` | Country name or two-letter code (94 countries) |
| `language` | `English` | Language name or code; falls back to the country's main language if not available |
| `maxKeywordsPerDomain` | `20` | Keywords per domain or URL (1–10,000) |
| `sortBy` | `etv` | etv, searchVolume, position, cpc, keywordDifficulty |
| `resultTypes` | `["organic"]` | organic, paid, featured_snippet, local_pack, ai_overview_reference |
| `minSearchVolume` | — | Minimum monthly searches |
| `maxPosition` | — | Worst position to keep (10 = page one) |
| `maxKeywordDifficulty` | — | Highest keyword difficulty to keep |
| `searchIntents` | — | informational, navigational, commercial, transactional |
| `excludeBrandKeywords` | `false` | Drop keywords containing the domain's own name |
| `excludeWords` / `includeWords` | — | Drop keywords with any of these words / keep only keywords with one of them |
| `includeLostKeywords` | `false` | Add keywords the domain no longer ranks for (`isLost = true`) |
| `findCompetitors` | `false` | ($) One row per organic competitor of each domain |
| `maxCompetitors` | `10` | Competitors per domain (1–100) |
| `analyzeCompetitorKeywords` | `false` | ($) Also return the keywords of every competitor found |
| `includeDomainSummary` | `false` | ($) One summary row per domain |
| `maxResults` | `10000` | Ceiling on keyword rows for the whole run |

### ⬆️ Output

Real rows from our test runs. A keyword row:

```json
{
  "type": "keyword",
  "domain": "ahrefs.com",
  "keyword": "ai rewriter",
  "position": 1,
  "absolutePosition": 1,
  "resultType": "organic",
  "rankingUrl": "https://ahrefs.com/writing-tools/paragraph-rewriter",
  "rankingTitle": "Free AI Paragraph Rewriter",
  "searchVolume": 49500,
  "cpc": 2.6,
  "competition": 0.28,
  "competitionLevel": "LOW",
  "keywordDifficulty": 28,
  "searchIntent": "commercial",
  "estimatedTraffic": 15950.57,
  "estimatedTrafficCost": 41471.49,
  "previousPosition": 1,
  "positionChange": 0,
  "isNew": false,
  "isUp": false,
  "isDown": false,
  "isLost": false,
  "serpFeatures": ["organic", "product_considerations", "related_searches"],
  "searchVolumeTrendYearly": -33,
  "targetType": "domain",
  "competitorOf": null,
  "location": "United States",
  "language": "en",
  "serpCheckedAt": "2026-07-30 05:03:58 +00:00",
  "charged": true,
  "scrapedAt": "2026-10-01T13:40:27.451Z"
}
```

A competitor row (add-on):

```json
{
  "type": "competitor",
  "domain": "semrush.com",
  "competitorOf": "backlinko.com",
  "competitorRank": 1,
  "sharedKeywords": 22106,
  "avgPosition": 14,
  "sharedKeywordsTraffic": 13795.57,
  "totalKeywords": 112633,
  "estimatedTraffic": 990830.61,
  "estimatedTrafficCost": 4181392.16,
  "top3Keywords": 15597,
  "top10Keywords": 44233,
  "location": "United States",
  "language": "en"
}
```

The Console shows four tabs: **Ranked keywords** (the main table), **Competitors**, **Domain summary** and **All fields**. With the add-ons off, every row is a keyword row.

#### Error rows

If an input cannot be used — something that is not a domain, an unknown country, a page URL in competitor discovery, or a domain with no ranked keywords for your country and filters — the Actor adds a free row:

```json
{ "type": "error", "input": "not a domain", "error": "Not a domain or URL (expected something like example.com or https://example.com/page). Not charged.", "scrapedAt": "2026-10-01T13:39:33.000Z" }
```

A small or new site can have very few keywords in the data source; then you get fewer rows or one free error row that says so. A run summary (requests, cache hits, rows, free rows) is saved in the key-value store as `SUMMARY`.

### Use cases for competitor keyword data

#### SEO content planning

Find the keywords that bring your competitors the most traffic, filter to `maxKeywordDifficulty` 30 and write the pages they rank with and you do not.

#### Keyword gap analysis

Put your domain and three competitors in one run. Sort by keyword: rows where competitors rank and your domain does not are your gap.

#### Paid search research

Add `paid` to result types to see which keywords a competitor buys Google Ads on, with CPC and competition in the same row.

#### Agency audits and pitches

One run per prospect: summary row plus top 100 keywords by traffic, exported to Google Sheets.

#### Rank monitoring of competitors

Schedule the run weekly; `isNew`, `isUp`, `isDown` and `positionChange` show what moved.

#### AI search visibility

Select `ai_overview_reference` to see for which keywords a domain is cited inside Google AI Overviews.

#### AI agents and LLM pipelines

An agent can call the Actor with one domain and get structured keyword rows back in seconds — for content briefs, competitor reports and SEO assistants.

### Integrations

Every run is available through the **Apify API**, and the Actor works with **n8n, Make, Zapier, Google Sheets, Airbyte, LangChain** and the **Apify MCP server**.

Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("lergassy/competitor-keywords-finder").call(run_input={
    "domains": ["backlinko.com", "semrush.com"],
    "location": "US",
    "maxKeywordsPerDomain": 200,
    "excludeBrandKeywords": True,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(row["domain"], row["keyword"], row["position"], row["searchVolume"])
```

JavaScript:

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

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('lergassy/competitor-keywords-finder').call({
    domains: ['ahrefs.com'],
    maxKeywordsPerDomain: 100,
    sortBy: 'searchVolume',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length);
```

### 🤖 For AI Agents & LLM Apps

Compact reference for agents calling this Actor through the Apify MCP server or the Apify API (`lergassy/competitor-keywords-finder`).

**Purpose:** one row = one Google keyword a domain or page URL ranks for, with position, ranking URL, search volume, CPC, competition, keyword difficulty, search intent and estimated traffic. Answers "what keywords does example.com rank for?", "which pages bring a competitor traffic?", "who are a domain's organic competitors?".

**Minimal input:**

```json
{ "domains": ["example.com"] }
```

**Output:** type, domain, keyword, position, absolutePosition, resultType, rankingUrl, rankingTitle, searchVolume, cpc, competition, competitionLevel, keywordDifficulty, searchIntent, estimatedTraffic, estimatedTrafficCost, previousPosition, positionChange, isNew, isUp, isDown, isLost, serpFeatures, searchVolumeTrendYearly, targetType, competitorOf, location, language, serpCheckedAt, charged, scrapedAt. Competitor rows (type = "competitor") and summary rows (type = "domainSummary") appear only when their add-ons are on.

**Behaviors an agent should know:**

- `maxKeywordsPerDomain` (default 20) caps rows and cost per domain; `maxResults` (default 10,000) caps the run.
- Use `minSearchVolume`, `maxPosition`, `maxKeywordDifficulty`, `searchIntents`, `excludeBrandKeywords`, `excludeWords`, `includeWords` instead of post-filtering; they apply before the limit and filtered keywords are not billed.
- A URL with a path is analysed as one page; competitor discovery works on whole domains only.
- Positions are from the data provider's latest check of each results page (`serpCheckedAt`), not a live search; difficulty and traffic are estimates.
- Billed on paid plans: $0.0015 per keyword row with search volume; $0.0015 per competitor; $0.0027 (Starter) to $0.0021 (Business) per summary row. On the Free plan: $0.002, $0.002 and $0.003. Rows with `charged = false`, error rows and run start are free.
- `serpFeatures` is the only array field; everything else is flat.

### ❓ FAQ

#### Is it legal to look up competitor keywords?

The Actor returns aggregated search statistics and public Google rankings — the same kind of data every SEO tool sells. It contains no personal data. Check your local law and the terms that apply to your use case; when in doubt, consult a lawyer.

#### Is this a SEMrush or Ahrefs alternative?

For the "organic keywords of a competitor" report, yes: domain or URL in, ranked keywords with position, volume, CPC, difficulty, intent and traffic out — billed per keyword, without a monthly subscription. It does not have backlink, site audit or rank tracking projects.

#### Where does the data come from?

Search volume, CPC and competition are aggregated from Google Ads Keyword Planner and clickstream data via a licensed data provider; rankings come from that provider's regular checks of Google results pages. The same request within 7 days is answered from a cache, so repeated runs return the same numbers.

#### How fresh are the positions?

Each row has `serpCheckedAt`: the date the provider last checked that results page. Popular keywords are checked more often than rare ones; expect days to weeks, not minutes.

#### Why did I get fewer keywords than I asked for?

The domain ranks for fewer keywords that match your country, language, result types and filters. Small or new sites can have only a handful of keywords in the data source. A domain with none gives one free error row.

#### Which countries and languages are supported?

94 Google countries — United States, United Kingdom, Germany, France, India, Indonesia, Australia, Brazil, Japan and more — each with its available languages. An unknown country gives a free error row with the full list of codes.

#### How much does a typical run cost?

On paid plans the default run (20 keywords) costs $0.03, 1,000 keywords cost $1.50, 10,000 keywords $15, and finding 10 competitors adds $0.015. On the Free plan the same cost $0.04, $2, $20 and $0.02. There is no start fee.

#### Can I use Competitor Keywords Finder with the Apify API?

Yes. Start runs, read datasets and schedule jobs with the Apify API, or the Python and JavaScript clients shown above.

#### Can I use it through an MCP server?

Yes. Add the Apify MCP server (`https://mcp.apify.com`) to Claude, Cursor or any MCP client and call `lergassy/competitor-keywords-finder` as a tool.

#### Can I integrate it with other apps?

Yes — n8n, Make, Zapier, Google Sheets, Airbyte, Slack and webhooks through Apify integrations.

#### Is each keyword one row?

Yes: one row per domain and keyword. When a page ranks for the same keyword in two result types (for example organic and AI Overview), each is its own row with its own `resultType` and position.

### Your feedback

Need another filter, another country or a different export? Open an issue on the **Issues** tab — we read every one. If the Actor saved you time, a review on the Store page helps other people find it.

### You might also like

| Actor | What it does |
|---|---|
| [Keyword Search Volume Checker](https://apify.com/blueskyscraper/keyword-search-volume-checker) | Search volume, CPC and competition for your own keyword list |
| [Keyword Suggestions Scraper](https://apify.com/lergassy/keyword-suggestions-scraper) | Keyword ideas from Google, YouTube, Amazon and Bing autocomplete |
| [Domain Intelligence Scraper](https://apify.com/lergassy/domain-intelligence-scraper) | Who runs a domain: DNS, WHOIS, hosting and more |
| [Wappalyzer Scraper](https://apify.com/lergassy/wappalyzer-scraper) | Technologies behind any website |
| [Google Trends Scraper](https://apify.com/lergassy/google-trends-scraper) | Interest over time and related queries for your keywords |

**Also known as:** competitor keyword research tool, ranked keywords API, organic keywords API, what keywords does a website rank for, SEMrush alternative, Ahrefs organic keywords alternative, domain keyword checker, website keyword finder, keyword gap tool, competitor SEO analysis, SERP competitors finder, organic competitors finder.

# Actor input Schema

## `domains` (type: `array`):

Enter one competitor per line: a domain (<b>example.com</b>) for every keyword the site ranks for, or a page URL (<b>https://example.com/blog/post</b>) for the keywords of that one page. Several domains in one run are compared in one table.

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

Enter the Google country as a name or two-letter code: United States, US, GB, DE, IN, ID, AU… 94 countries are available; an unknown one gives a free error row with the full list.

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

Enter the search language as a name or code (English / en, German / de, Spanish / es…). If the language is not available for the country, the country's main language is used and the log says so.

## `maxKeywordsPerDomain` (type: `integer`):

Set how many ranked keywords to return for each domain or URL (1–10,000). Keywords come sorted by the order below, so a low number gives the most valuable ones first.

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

Choose which keywords come first. Sorting happens before the limit, so it decides which keywords you get.

## `resultTypes` (type: `array`):

Pick which Google result types count as a ranking. Organic only is the classic SEO view; add Paid to see the keywords a competitor buys ads on.

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

Keep only keywords with at least this many monthly Google searches, e.g. <b>100</b>.

## `maxPosition` (type: `integer`):

Keep only keywords where the competitor ranks at this position or better, e.g. <b>10</b> for page one.

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

Keep only keywords with keyword difficulty (0–100) at or below this number, e.g. <b>30</b> for easier keywords.

## `searchIntents` (type: `array`):

Keep only keywords with these search intents. Empty = all intents.

## `excludeBrandKeywords` (type: `boolean`):

Switch on to drop keywords that contain the competitor's own name (for example <b>ahrefs</b> for ahrefs.com), so you see only the keywords you could win.

## `excludeWords` (type: `array`):

Add words; keywords containing any of them are dropped before the limit and never billed.

## `includeWords` (type: `array`):

Add words to keep only keywords that contain at least one of them, e.g. <b>pricing</b>, <b>alternative</b>, <b>vs</b>.

## `includeLostKeywords` (type: `boolean`):

Switch on to add keywords the domain ranked for earlier but has since lost (marked <b>isLost = true</b>). Off = current rankings only.

## `findCompetitors` (type: `boolean`):

Switch on to add one row per organic competitor of every domain you entered: shared keywords, average position, competitor traffic. Billed per competitor found.

## `maxCompetitors` (type: `integer`):

Set how many competitors to return per domain when competitor discovery is on (sorted by shared keywords; Google, YouTube, Wikipedia and other giant sites are left out).

## `analyzeCompetitorKeywords` (type: `boolean`):

Switch on together with competitor discovery to get the ranked keywords of every competitor found, with the same limit and filters as your own domains. Each competitor's keywords are billed like any other keyword row.

## `includeDomainSummary` (type: `boolean`):

Switch on to add one row per domain with its organic keyword count, estimated organic traffic, traffic value, position distribution (top 3, top 10, 11–20, 21–100) and new / lost keywords. Counts follow your filters and result types. Adds a second row type to the dataset.

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

Set a hard ceiling on keyword rows for the whole run, across all domains and competitors. The run stops when it is reached.

## Actor input object example

```json
{
  "domains": [
    "ahrefs.com"
  ],
  "location": "United States",
  "language": "English",
  "maxKeywordsPerDomain": 20,
  "sortBy": "etv",
  "resultTypes": [
    "organic"
  ],
  "excludeBrandKeywords": false,
  "includeLostKeywords": false,
  "findCompetitors": false,
  "maxCompetitors": 10,
  "analyzeCompetitorKeywords": false,
  "includeDomainSummary": false,
  "maxResults": 10000
}
```

# Actor output Schema

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

One row per domain and ranked keyword: keyword, Google position, ranking URL, search volume, CPC, keyword difficulty, search intent, estimated traffic, position change.

# 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 = {
    "domains": [
        "ahrefs.com"
    ],
    "location": "United States",
    "language": "English",
    "maxKeywordsPerDomain": 20,
    "sortBy": "etv",
    "resultTypes": [
        "organic"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("blueskyscraper/competitor-keywords-finder").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 = {
    "domains": ["ahrefs.com"],
    "location": "United States",
    "language": "English",
    "maxKeywordsPerDomain": 20,
    "sortBy": "etv",
    "resultTypes": ["organic"],
}

# Run the Actor and wait for it to finish
run = client.actor("blueskyscraper/competitor-keywords-finder").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 '{
  "domains": [
    "ahrefs.com"
  ],
  "location": "United States",
  "language": "English",
  "maxKeywordsPerDomain": 20,
  "sortBy": "etv",
  "resultTypes": [
    "organic"
  ]
}' |
apify call blueskyscraper/competitor-keywords-finder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,blueskyscraper/competitor-keywords-finder"
        }
    }
}
```

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/e0HAExzdpAWQWs79D/builds/5iaTFlZhRnZfvp52I/openapi.json
