# SEO Competitors & Keyword Gap Finder (`plainrows/seo-competitors-keyword-gap`) Actor

Find the organic Google competitors of any website and the keywords they rank for that it misses (keyword gap): shared keywords, positions, traffic, volume, CPC, difficulty. 94 countries. Semrush and Ahrefs alternative. $0.002 per competitor or keyword, plus a $0.012 fee per domain with results.

- **URL**: https://apify.com/plainrows/seo-competitors-keyword-gap.md
- **Developed by:** [PlainRows](https://apify.com/plainrows) (community)
- **Categories:** SEO tools, Marketing, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.60 / 1,000 competitor or gap 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

## SEO Competitors & Keyword Gap Finder

For any list of websites, find **who they really compete with on Google** (the sites ranking on the most keywords shared with them) and the **keywords those competitors rank for that the website misses**: the keyword gap, with search volume, CPC, difficulty, intent, the competitor's position, ranking URL and estimated traffic. 94 countries.

Built on a commercial SEO data provider: **no scraping of SEO tools, no accounts, no subscriptions**. You pay $0.002 per competitor or gap keyword returned, plus a $0.012 fee per domain with results. Domains without data are free.

### Typical uses

- Competitor research: the 10 (up to 100) organic competitors of your site or a client's, with shared keywords, average position and traffic.
- Content planning: the keywords your top competitors get traffic from and you don't rank for at all, best traffic first.
- SEO audits and agency pitches for many prospects in one run (up to 100 domains).
- Feed spreadsheets, n8n / Make workflows or AI agents with clean JSON, one row per competitor or keyword.

### What you get

Two kinds of rows, both billed as one result. The `type` field tells them apart.

**Competitor rows** (`type: "competitor"`)

| Field | Description |
|---|---|
| `domain` | The website analysed (lowercase, without `www.`) |
| `rank` | 1 = the competitor sharing the most ranking keywords |
| `competitorDomain` | The competing website |
| `commonKeywords` | Keywords both sites rank for in Google's top 100 |
| `competitorAvgPosition` | The competitor's average position on those shared keywords |
| `competitorOrganicTraffic`, `competitorOrganicKeywords` | The competitor's estimated monthly organic visits and ranking keywords (all keywords) |
| `competitorTrafficOnCommonKeywords`, `domainTrafficOnCommonKeywords` | Estimated monthly visits each site gets from the shared keywords |

**Keyword gap rows** (`type: "gap-keyword"`)

| Field | Description |
|---|---|
| `keyword` | A keyword the competitor ranks for (top 100) and the domain does not |
| `competitorDomain`, `competitorPosition`, `competitorUrl` | Who ranks, where, with which page |
| `competitorTraffic` | Estimated monthly visits the competitor gets from this keyword |
| `searchVolume`, `cpc`, `keywordDifficulty`, `searchIntent` | Keyword metrics |

Every row also has `country`, `languageCode`, `observedAt` (UTC) and `found`. A domain without enough Google data gets one free row with `found: false`. Missing values are `null`, never guessed. The **Output** tab has a **Competitors** view and a **Keyword gap** view.

### Input

```json
{
  "domains": ["plausible.io", "https://www.example.com/blog/"],
  "country": "US",
  "maxCompetitors": 10,
  "keywordGap": true,
  "gapCompetitors": 3,
  "maxGapKeywords": 100
}
```

- **domains**: domains or full URLs, up to 100 per run. URLs are reduced to their domain; subdomains other than `www` are kept. Duplicates are removed for free.
- **country** / **languageCode**: one of 94 countries; the language defaults to the country's main language.
- **maxCompetitors**: 5 to 100 competitors per domain (default 10).
- **keywordGap**: also return the keyword gap (default on). **gapCompetitors**: gap from the first 1 to 5 competitors (default 3). **maxGapKeywords**: 20 to 1,000 gap keywords per domain (default 100), split between those competitors. A keyword ranked by several competitors is returned once.
- **excludeTopDomains**: leave out giant sites that rank for everything (Wikipedia, Amazon, YouTube...). Default on.

### Output example

Real rows from DataForSEO data fetched on 2026-10-18 (US):

```json
[
  {
    "domain": "plausible.io",
    "type": "competitor",
    "found": true,
    "rank": 1,
    "competitorDomain": "semrush.com",
    "commonKeywords": 600,
    "competitorAvgPosition": 8.3,
    "competitorOrganicTraffic": 978907,
    "competitorOrganicKeywords": 98888,
    "competitorTrafficOnCommonKeywords": 1165,
    "domainTrafficOnCommonKeywords": 290,
    "country": "US",
    "languageCode": "en",
    "observedAt": "2026-10-18T08:40:00.000Z",
    "schemaVersion": "1.0"
  },
  {
    "domain": "plausible.io",
    "type": "gap-keyword",
    "found": true,
    "rank": 4,
    "keyword": "semrush",
    "competitorDomain": "semrush.com",
    "competitorPosition": 1,
    "competitorUrl": "https://www.semrush.com/",
    "competitorTraffic": 21960.2,
    "searchVolume": 90500,
    "cpc": 2.76,
    "keywordDifficulty": 63,
    "searchIntent": "informational",
    "country": "US",
    "languageCode": "en",
    "observedAt": "2026-10-18T08:40:00.000Z",
    "schemaVersion": "1.0"
  }
]
```

### Pricing

Pay per result, no subscription. See the **Pricing** tab for current prices:

- **Competitor or gap keyword**: $0.002 per row (FREE and BRONZE), $0.0018 (SILVER), $0.0016 (GOLD and above);
- **Domain analysed**: a $0.012 fee per domain that returns at least one row, at about what the data source charges us for the competitor lookup.

Example: one domain with the defaults (10 competitors + 100 gap keywords) costs 110 x $0.002 + $0.012 = $0.232 on the FREE tier.

Domains without data, duplicates and invalid entries are never billed. Input mistakes cost nothing. The run never spends more than the maximum cost you set: it returns fewer rows, then stops, before reaching it. The keyword gap is not asked for competitors that rank for fewer than 20 keywords outside the shared ones. Lists where most domains have no data stop early with a clear warning; the remaining domains are not looked up and not charged.

**Free Apify plan:** each run analyses 1 domain with up to 10 competitors and 20 gap keywords from 1 competitor, so you can check the output. A paid Apify plan removes these limits.

### Use it from code, automations or AI agents

**API (one call, results returned directly):**

```bash
curl -X POST "https://api.apify.com/v2/acts/plainrows~seo-competitors-keyword-gap/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"domains": ["plausible.io"], "country": "US", "maxCompetitors": 10, "keywordGap": true}'
```

**n8n, Make, Zapier:** use the Apify integration and pick `plainrows/seo-competitors-keyword-gap` as the Actor.

**AI agents (MCP):** add `https://mcp.apify.com?tools=plainrows/seo-competitors-keyword-gap` to Claude, Cursor or any MCP client.

### What this is not

- Competitors are **organic Google search competitors** (sites ranking on the same keywords), not business competitors from a directory.
- Traffic figures are estimates of Google organic search traffic, not analytics data.
- Not affiliated with Google, Semrush or Ahrefs.

### Run summary

Each run stores a summary in the key-value store (`OUTPUT`): domains submitted and analysed, rows billed, domains without data, gap requests skipped, duplicates removed, invalid entries with the reason, and anything skipped because of the free-plan or budget limit or an early stop.

### FAQ

**How do I find my SEO competitors?**
Enter your domain, pick the country and run. You get the sites that rank on the most of your keywords, with how many keywords you share and how well they rank.

**What is a keyword gap?**
The keywords a competitor ranks for in Google's top 100 and your site does not rank for at all. Sorted by the traffic they bring the competitor, they are your best content opportunities.

**Do I need a Semrush or Ahrefs account?**
No. The data comes from a commercial SEO data provider; you pay per result, with no subscription.

### More PlainRows tools

Same pay-per-result pricing, same clean JSON, built to chain together in n8n, Make, Zapier or AI agents.

- **SEO and keywords:** [Keyword Search Volume, CPC & Difficulty](https://apify.com/plainrows/keyword-search-volume) · [Keyword Planner Alternative (Bulk Search Volume & CPC)](https://apify.com/plainrows/keyword-planner-alternative) · [Keyword Ideas Generator](https://apify.com/plainrows/keyword-ideas-generator) · [Google Autocomplete & People Also Ask](https://apify.com/plainrows/google-autocomplete-questions) · [Google Trends Explorer](https://apify.com/plainrows/google-trends-explorer) · [Website Organic Traffic & Top Keywords](https://apify.com/plainrows/domain-seo-overview) · [Bulk Domain Authority Checker](https://apify.com/plainrows/domain-authority-checker) · [Backlink Checker](https://apify.com/plainrows/backlink-checker) · [Broken Link Checker](https://apify.com/plainrows/broken-link-checker) · [AI Search Visibility Tracker (ChatGPT, Gemini, AI Mode)](https://apify.com/plainrows/ai-search-brand-visibility) · [Google Maps Rank Tracker (Geo-Grid Local SEO)](https://apify.com/plainrows/google-maps-rank-tracker)
- **Leads and companies:** [Google Maps Scraper](https://apify.com/plainrows/google-maps-businesses) · [Google Maps Email Extractor](https://apify.com/plainrows/google-maps-email-extractor) · [Google Maps Businesses Without Website](https://apify.com/plainrows/google-maps-no-website-leads) · [Website Technology Checker](https://apify.com/plainrows/website-tech-stack) · [Website Email Extractor](https://apify.com/plainrows/website-email-extractor) · [Contact Details Scraper (Emails, Phones, Socials)](https://apify.com/plainrows/contact-details-scraper) · [ATS Jobs Scraper (Workday, Greenhouse, Lever, Ashby)](https://apify.com/plainrows/ats-job-postings) · [Workday Jobs Scraper](https://apify.com/plainrows/workday-jobs-scraper) · [Greenhouse Jobs Scraper](https://apify.com/plainrows/greenhouse-jobs-scraper) · [Lever Jobs Scraper](https://apify.com/plainrows/lever-jobs-scraper) · [Ashby Jobs Scraper](https://apify.com/plainrows/ashby-jobs-scraper) · [Google Jobs Scraper](https://apify.com/plainrows/google-jobs-scraper) · [Google Ads Scraper (Transparency Center)](https://apify.com/plainrows/google-ads-transparency) · [Company Registry Lookup (SIRENE, LEI, Brreg)](https://apify.com/plainrows/company-registry-lookup) · [Public Tenders Search (EU TED & UK)](https://apify.com/plainrows/public-tenders-search)
- **E-commerce and travel:** [Amazon Product Search Scraper](https://apify.com/plainrows/amazon-product-search) · [Amazon Best Sellers Scraper](https://apify.com/plainrows/amazon-bestsellers-scraper) · [Amazon Reviews Scraper](https://apify.com/plainrows/amazon-reviews-scraper) · [Google Shopping Prices Scraper](https://apify.com/plainrows/google-shopping-prices) · [Google Hotels Prices Scraper](https://apify.com/plainrows/google-hotels-prices) · [Google Hotels Scraper](https://apify.com/plainrows/google-hotels-scraper) · [Tripadvisor Reviews Scraper](https://apify.com/plainrows/tripadvisor-reviews) · [Trustpilot Reviews Scraper](https://apify.com/plainrows/trustpilot-reviews)
- **Marketplaces and classifieds:** [AliExpress Scraper](https://apify.com/plainrows/aliexpress-scraper) · [Kleinanzeigen Scraper (Germany)](https://apify.com/plainrows/kleinanzeigen-scraper) · [AutoScout24 Scraper (Cars, Europe)](https://apify.com/plainrows/autoscout24-scraper) · [Kijiji Scraper (Canada)](https://apify.com/plainrows/kijiji-scraper) · [Marktplaats Scraper (Netherlands)](https://apify.com/plainrows/marktplaats-scraper) · [Property Finder Scraper (UAE)](https://apify.com/plainrows/propertyfinder-scraper) · [Redfin Scraper (US Homes for Sale)](https://apify.com/plainrows/redfin-scraper) · [Otomoto Scraper (Polish Car Listings)](https://apify.com/plainrows/otomoto-scraper) · [Otodom Scraper (Poland Property)](https://apify.com/plainrows/otodom-scraper) · [Imovirtual Scraper (Portugal Property)](https://apify.com/plainrows/imovirtual-scraper) · [Standvirtual Scraper (Portugal Cars)](https://apify.com/plainrows/standvirtual-scraper) · [Blocket Scraper (Sweden)](https://apify.com/plainrows/blocket-scraper) · [FINN.no Scraper (Norway)](https://apify.com/plainrows/finn-scraper) · [coches.net Scraper (Spain Cars)](https://apify.com/plainrows/coches-net-scraper) · [2dehands Scraper (Belgium)](https://apify.com/plainrows/2dehands-scraper)
- **Content and media:** [Google News Scraper](https://apify.com/plainrows/google-news-scraper) · [YouTube Search Scraper](https://apify.com/plainrows/youtube-search-scraper) · [YouTube Comments Scraper](https://apify.com/plainrows/youtube-comments-scraper) · [Google Images Scraper](https://apify.com/plainrows/google-images-scraper) · [Website Screenshot API](https://apify.com/plainrows/website-screenshot) · [Google Maps Reviews Scraper](https://apify.com/plainrows/google-maps-reviews) · [Google Reviews Scraper](https://apify.com/plainrows/google-reviews-scraper) · [App Store & Google Play Reviews Scraper](https://apify.com/plainrows/app-reviews-scraper) · [Google Play Reviews Scraper](https://apify.com/plainrows/google-play-reviews-scraper) · [App Store Reviews Scraper](https://apify.com/plainrows/app-store-reviews-scraper)

### Support

Found a bug or need a field? Open an issue on this page. Issues are read and answered.

### Support

Found a bug or need a field? Open an issue on this page. Issues are read and answered.

# Actor input Schema

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

One website per line: example.com, https://www.example.com/page or blog.example.com. Up to 100 per run. URLs are reduced to their domain (subdomains other than www are kept). Duplicates are removed for free.

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

Country whose Google search data you want.

## `languageCode` (type: `string`):

Language code, e.g. "en", "fr" or "zh-TW". Leave empty to use the country's main language (for example German for Switzerland, French for Belgium). Only languages offered by the data source for that country work; others stop the run with a clear message and no charge.

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

How many organic competitors to return per domain (sites ranking on the most keywords shared with it), 5 to 100. Each competitor returned is billed; see Pricing.

## `keywordGap` (type: `boolean`):

Also return the keywords your first competitors rank for in Google's top 100 and the domain does not (best traffic first). Each keyword returned is billed; see Pricing.

## `gapCompetitors` (type: `integer`):

Keyword gap from the first 1 to 5 competitors. Competitors with fewer than 20 keywords outside the shared ones are skipped (nothing paid). A keyword found at several competitors is returned once.

## `maxGapKeywords` (type: `integer`):

Most gap keywords returned per domain, 20 to 1,000, split between the competitors used for the gap.

## `excludeTopDomains` (type: `boolean`):

Leave out sites that rank for everything (Wikipedia, Amazon, YouTube, Google...) so the list shows real competitors.

## Actor input object example

```json
{
  "domains": [
    "plausible.io"
  ],
  "country": "US",
  "maxCompetitors": 10,
  "keywordGap": true,
  "gapCompetitors": 3,
  "maxGapKeywords": 100,
  "excludeTopDomains": true
}
```

# Actor output Schema

## `competitors` (type: `string`):

No description

## `gap` (type: `string`):

No description

## `summary` (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 = {
    "domains": [
        "plausible.io"
    ],
    "country": "US"
};

// Run the Actor and wait for it to finish
const run = await client.actor("plainrows/seo-competitors-keyword-gap").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": ["plausible.io"],
    "country": "US",
}

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

```

## MCP server setup

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

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/lqxP0WoYxOICo0BJb/builds/qnfX3jgOu8FzLNAkW/openapi.json
