Competitor Keywords & Keyword Gap — Semrush/Ahrefs Alternative
Pricing
from $3.00 / 1,000 gap keywords
Competitor Keywords & Keyword Gap — Semrush/Ahrefs Alternative
Find the Google keywords your competitors rank for and you don't: one row per keyword with every competitor's position side by side, an opportunity score and quick wins. Also lists any site's ranked keywords and its organic competitors. 88 countries, pay per row.
Pricing
from $3.00 / 1,000 gap keywords
Rating
0.0
(0)
Developer
Muhamed Didovic
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Features
Share

Find the Google keywords your competitors rank for and you don't. Compare your site with up to five competitors and get one row per keyword with every competitor's position side by side, an opportunity score from 0 to 100, and a quick-win flag for keywords where you sit on page two and a competitor holds the top three.
The same actor also lists every keyword any site ranks for, finds your organic competitors, and tracks your live Google position for a keyword list with the change since your last run. 88 countries, no Semrush or Ahrefs subscription, and you pay per row.
Why use this actor?
- One row per keyword, not one per pair. With three competitors you get one row for "check backlinks", showing
{ "semrush.com": 2, "ahrefs.com": 1 }next to your own position. You don't have to join three exports yourself. - Sorted by what is worth doing. Every gap row carries an
opportunityScorebuilt from search volume, keyword difficulty, CPC and how many competitors already rank. The best opportunities come first. - Quick wins called out. Keywords where you rank 11-20 and a competitor ranks 1-3 are flagged with
isQuickWin, and listed first if you want. - Brand terms left out. "semrush login" is not a keyword moz.com can win. Keywords containing any compared site's name are dropped, and the log tells you how many.
- No competitor list needed. Leave it empty and the three sites that share the most keywords with yours are picked for you. YouTube, Reddit and other giants that share keywords with everyone are skipped.
- A rank tracker you schedule. Track mode checks live Google results for your keywords and compares each run with the previous one:
up,down,new,lost, and a flag when Google starts ranking a different page of yours. Your competitors' positions come from the same results at no extra cost, along with whether an AI Overview appears and whether it cites you. - Pay for rows you get. Filters run before the data is fetched, and the row limit is also what we request, so rows you filtered out are never billed.
Overview
This actor is for SEO teams, agencies, content strategists and founders who want competitor keyword data without a monthly SEO-suite seat. Gap, rankings and competitors modes read Google organic ranking data from DataForSEO Labs for the country and language you choose. Track mode reads live Google results at the moment of the run.
It writes to one dataset with a type on every row:
type | Produced by | One row per |
|---|---|---|
gap | Keyword gap mode | keyword where a competitor beats you |
ranking | Rankings mode | keyword a site ranks for |
competitor | Competitors mode | competing site |
tracking | Track mode | keyword checked in live Google results |
overview | Gap, rankings and competitors modes | site looked up (keyword counts, traffic, traffic value) |
The Console shows a separate table view for each type.
Supported inputs
The actor works from domains, not URLs. Anything around the domain is removed, so https://www.moz.com/blog?ref=x becomes moz.com. Subdomains are kept as given: blog.hubspot.com is analysed as that subdomain.
| Mode | domain | competitorDomains |
|---|---|---|
| Keyword gap | your site | 0-5 competitors (empty = top 3 picked for you) |
| Rankings | first site | up to 24 more sites |
| Competitors | your site | not used |
| Track | your site | up to 10 sites whose positions are read off the same results |
Track mode also needs keywords: the searches to check, up to 1,000 per run.
Not supported: single-page (URL-level) analysis, paid search (ads) keywords, and countries without Google ranking data (the Country list only shows the 88 that have it).
Use cases
| Who | What they do with it |
|---|---|
| Content teams | Turn missing gap keywords into the next quarter's article plan |
| SEO agencies | Run a gap for a prospect against their three biggest rivals for a sales deck |
| In-house SEO | Work through isQuickWin rows: pages already on page two that need a push |
| Founders | See which sites Google treats as your real competitors, which are not always the ones you expect |
| PPC teams | Find high-CPC keywords competitors get for free through organic rankings |
| Data teams | Feed rankings for a portfolio of sites into a dashboard or warehouse |
| Site owners | Schedule track mode weekly and get a rank report with what moved since last week |
| Content teams | See which keywords show an AI Overview and whether it cites you |
How it works

- You give a domain, an optional competitor list, a country and a row limit.
- The actor checks your spending limit and trims the request to what it can pay for, before anything is fetched.
- It looks up each site's ranking footprint (the
overviewrow). - For a gap, it fetches what each competitor ranks for that you don't, and what you both rank for, filtered by volume and the competitor's position.
- It merges everything into one row per keyword, drops brand terms and keywords you already lead on, scores the rest and saves them best first.
Track mode skips steps 3-5. It checks each keyword in live Google results to the depth you pick, finds your site and your competitors on that page, compares with the positions saved from your last run, and saves the new positions for next time.
Input configuration
| Field | Type | Default | What it does |
|---|---|---|---|
mode | string | gap | gap, rankings, competitors or track |
domain | string | required | The site to analyse, e.g. moz.com |
competitorDomains | array | [] | Gap: up to 5 competitors. Rankings: up to 24 extra sites. Track: up to 10 sites to read positions for |
keywords | array | [] | Track only: the searches to check, up to 1,000 |
trackDepth | integer | 30 | Track only: how many Google results to check, 10, 20, 30, 50 or 100 (others round up). Billed per 10 |
device | string | desktop | Track only: desktop or mobile |
trackingName | string | empty | Track only: keeps a separate history for a second keyword list on the same site |
country | string | us | Two-letter country code with Google ranking data |
language | string | auto | Leave empty for the country's main language |
maxKeywords | integer | 500 | Rows per site (rankings), gap rows (gap, at least 50) or competitors (max 100). 1-3,000 |
minSearchVolume | integer | 0 | Skip keywords with fewer monthly searches |
maxCompetitorPosition | integer | 20 | Gap only: a competitor must rank at or above this position |
excludeBrandTerms | boolean | true | Drop keywords containing a compared site's name |
includeQuickWins | boolean | true | Gap only: list quick wins first |
Keyword gap against named competitors
{"mode": "gap","domain": "moz.com","competitorDomains": ["semrush.com", "ahrefs.com"],"country": "us","maxKeywords": 500,"maxCompetitorPosition": 10}
Keyword gap, competitors picked for you
{ "mode": "gap", "domain": "moz.com", "minSearchVolume": 100 }
Track your positions weekly (schedule this)
{"mode": "track","domain": "moz.com","keywords": ["seo tools", "domain authority checker", "link explorer"],"competitorDomains": ["semrush.com", "ahrefs.com"],"trackDepth": 30,"country": "us"}
Rankings for several sites
{"mode": "rankings","domain": "backlinko.com","competitorDomains": ["neilpatel.com"],"maxKeywords": 1000,"minSearchVolume": 100}
Find competitors in the UK
{ "mode": "competitors", "domain": "moz.com", "country": "gb", "maxKeywords": 25 }
Output overview
A gap row has your position (null when you are not in the top 100), the best competitor's position and page, every competitor's position in competitorPositions, how many of them rank, the keyword's volume, CPC, difficulty and intent, and the score and quick-win flag. gapType is missing when you don't rank at all and behind when you rank below a competitor.
A ranking row has the site's position, ranking URL and page title, the change since the last check, estimated monthly traffic and what that traffic would cost in ads, the keyword's metrics, and the SERP features shown for the keyword.
A competitor row has how many keywords the competitor shares with your site, that overlap as a share of your keywords, its average position on them, and its own total keywords and traffic.
A tracking row has your organic position (null when you are not in the results checked), the position counting AI Overviews and other blocks above it, the ranking page, the previous run's position, the change and its direction, urlChanged when Google now ranks a different page of yours, every competitor's position on the same results, the SERP features shown, and whether an AI Overview appears and cites you.
An overview row per site gives total ranked keywords, top-3, top-10 and page-two counts, estimated traffic, traffic value, and keywords gained and lost.
Output samples
Real rows from runs on 2026-10-28, US market. Trimmed where marked.
Gap row (moz.com vs semrush.com and ahrefs.com)
{"type": "gap","keyword": "check backlinks","gapType": "behind","opportunityScore": 73,"isQuickWin": true,"yourDomain": "moz.com","yourPosition": 14,"yourUrl": "https://moz.com/link-explorer","bestCompetitor": "ahrefs.com","bestCompetitorPosition": 1,"bestCompetitorUrl": "https://ahrefs.com/backlink-checker","competitorsRanking": 2,"competitorsChecked": 2,"competitorPositions": { "semrush.com": 2, "ahrefs.com": 1 },"searchVolume": 90500,"cpc": 7.17,"keywordDifficulty": 51,"searchIntent": "informational","competitionLevel": "LOW","trendYearlyPct": 812,"country": "us","language": "en"}
Ranking row (backlinko.com, trimmed)
{"type": "ranking","domain": "backlinko.com","keyword": "reddit popularity","position": 2,"url": "https://backlinko.com/reddit-users","title": "Reddit User and Growth Stats (Updated)","previousPosition": 4,"positionChange": "up","estimatedTraffic": 14661}
Competitor row (moz.com, UK, trimmed)
{"type": "competitor","domain": "moz.com","competitor": "semrush.com","sharedKeywords": 3112,"overlapPct": 57.2,"avgPositionOnShared": 10.6,"trafficOnShared": 30514,"competitorTotalKeywords": 23290,"competitorTotalTraffic": 400289}
Tracking row (moz.com, "seo tools", 2026-10-30, trimmed)
{"type": "tracking","domain": "moz.com","keyword": "seo tools","position": 3,"absolutePosition": 5,"url": "https://moz.com/free-seo-tools","previousPosition": null,"change": null,"positionChange": null,"competitorPositions": { "semrush.com": 12, "ahrefs.com": 8 },"serpFeatures": ["ai_overview", "people_also_ask", "product_considerations", "paid", "related_searches"],"hasAiOverview": true,"citedInAiOverview": false,"depth": 30,"device": "desktop","checkedAt": "2026-10-30T17:07:23.315Z"}
This was the first check, so there was nothing to compare with. From the next run on, previousPosition, change (places gained, negative for a drop) and positionChange are filled.
Overview row (moz.com, trimmed)
{ "type": "overview", "domain": "moz.com", "rankedKeywords": 22778, "top10Keywords": 7249, "estimatedTraffic": 261386 }
Key output fields
Gap: keyword, gapType, opportunityScore, isQuickWin, yourPosition, yourUrl, bestCompetitor, bestCompetitorPosition, bestCompetitorUrl, competitorPositions, competitorsRanking, competitorsChecked
Rankings: domain, keyword, position, url, title, previousPosition, positionChange, estimatedTraffic, trafficValueUsd, serpFeatures, isFeaturedSnippet
Competitors: competitor, sharedKeywords, overlapPct, avgPositionOnShared, trafficOnShared, competitorTotalKeywords, competitorTotalTraffic, competitorTrafficValueUsd
Keyword metrics (gap and rankings): searchVolume, cpc, keywordDifficulty, searchIntent, competitionLevel, trendYearlyPct
Tracking: keyword, position, absolutePosition, url, title, previousPosition, change, positionChange (up|down|same|new|lost), previousCheckedAt, urlChanged, competitorPositions, serpFeatures, hasAiOverview, citedInAiOverview, isFeaturedSnippet, depth, device, checkedAt, googleUrl
Overview: rankedKeywords, top3Keywords, top10Keywords, page2Keywords, estimatedTraffic, trafficValueUsd, newKeywords, lostKeywords
Every row: type, country, language
Pricing
Pay per event, no subscription:
| Event | Price | When |
|---|---|---|
| Run start | $0.02 | once per run |
| Site lookup | $0.02 | per site looked up (yours plus each competitor) |
| Ranked keyword | $0.002 | per ranking row |
| Gap keyword | $0.003 | per gap row |
| Competitor | $0.005 | per competitor row |
| Rank check | $0.005 | track mode: per keyword, for each 10 results checked |
overview rows are included in the site lookup. A gap of moz.com against two competitors returning 500 keywords costs $0.02 + 3 × $0.02 + 500 × $0.003 = $1.58. 1,000 ranked keywords for one site cost $2.04. Tracking 100 keywords to the top 30 costs $0.02 + 100 × 3 × $0.005 = $1.52 per run; to the top 10, $0.52.
If your maximum cost per run can't cover everything you asked for, the actor fetches only the rows it can bill and says so in the log. If it can't cover even one row (50 rows for a keyword gap), it stops before charging anything.
Free Apify plan: 100 rows per run, one site in rankings mode, one competitor in a gap, 10 keywords to the top 10 with one competitor in track mode, 5 runs per 24 hours. Prices are the same.
FAQ
What does "missing" vs "behind" mean?
missing: at least one competitor ranks and you are not in the top 100. behind: you rank, but at least one competitor ranks higher. Keywords where you beat every competitor are left out, because they are not a gap.
How is the opportunity score calculated?
Search volume (log scale) counts for 40%, ease (100 minus difficulty) for 25%, the share of compared competitors that rank for 20%, and CPC for 15%. The result is rounded to 0-100. It is a sorting aid, not a forecast.
Where does the data come from?
From DataForSEO Labs, which tracks Google's top 100 organic results for a large keyword database in each country. Positions and traffic are estimates from that database, refreshed every few weeks, and will differ somewhat from what Semrush or Ahrefs show.
Why did my competitor list come back different from what I expected?
When you leave competitorDomains empty, competitors are picked by how many keywords they share with you in the chosen country. That is Google's view of your competition, and it can include publishers and tools you don't sell against. Name competitors yourself to compare with specific sites.
Why are some keywords with my brand missing?
excludeBrandTerms (on by default) drops keywords containing the name of any compared site, such as "moz pro" or "ahrefs pricing". Turn it off to keep them.
Can I analyse a single page instead of a whole domain?
No. The actor works at domain or subdomain level.
Does it cover paid search (Google Ads) keywords?
No, organic results only.
How does track mode know my last positions?
Each run saves the positions it found in a key-value store named competitor-keywords-rank-history in your own Apify account. The next run with the same site, country, language, device and trackingName reads it and fills the change fields. Nothing is kept on our side. Deleting that store starts the history over.
Why did my position jump when nothing changed on my site?
A track run is one snapshot of live Google results, and Google reshuffles them during the day and between data centres. A single check can be several places off from the next one. Look at the trend over several scheduled runs rather than one move.
Why is url empty on some tracking rows?
Google sometimes returns a result as a redirect without its page address. The site is still recognised, so position is correct, but the page is only filled in when it can be read reliably.
Why did a site come back with no rows?
There is no ranking data for it in the chosen country and language. Its overview row will have null counts, and the run's status message names it. Try the country where the site's audience is.
Support
Found a bug or want a feature? Open an issue on the Issues tab.
Additional services
Need a scheduled weekly gap report, a different export shape, or this data joined with your own? I build custom versions. Open an issue or message me through Apify.
Explore more scrapers
- Keyword Search Volume, CPC & Difficulty: Google and Bing volume, CPC and difficulty for up to 1,000 keywords per run. Size the gap keywords you found here.
- Ahrefs Scraper: Domain Rating, backlinks, referring domains and organic traffic.
- Semrush Scraper: authority score, traffic, backlinks and top sites for a domain.
- Similarweb Scraper: traffic, rank, visits and audience for a list of domains.
- SEO Intelligence Suite: DR, traffic, AI-search visibility and Google presence in one call.
Full list at apify.com/memo23.
🤖 For AI Agents & LLM Apps
Compact reference for agents calling memo23/competitor-keywords through the Apify MCP server or the Apify API.
Purpose: Google organic competitor research: keyword gap (one row per keyword, every competitor's position side by side), ranked keywords per site, organic competitors, and live rank tracking for a keyword list with the change since the last run.
Minimal input (tested):
{ "mode": "gap", "domain": "moz.com", "competitorDomains": ["semrush.com"], "maxKeywords": 50 }
Output: rows tagged by type. gap: keyword, gapType (missing|behind), opportunityScore, isQuickWin, yourPosition, bestCompetitor, bestCompetitorPosition, competitorPositions {domain: position|null}, searchVolume, cpc, keywordDifficulty, searchIntent. ranking: domain, keyword, position, url, positionChange, estimatedTraffic, trafficValueUsd, searchVolume. competitor: competitor, sharedKeywords, overlapPct, avgPositionOnShared. overview: one per site, rankedKeywords, top10Keywords, estimatedTraffic. tracking: keyword, position|null, url, previousPosition, change, positionChange (up|down|same|new|lost), competitorPositions, hasAiOverview, citedInAiOverview.
Behaviors an agent should know:
- Always set
maxKeywords. Gap and ranking rows are billed per row ($0.003 / $0.002), plus $0.02 per run and $0.02 per site. - Empty
competitorDomainsin gap mode picks the top 3 competitors itself, which adds 3 site lookups. - Gap rows come sorted best first: quick wins first (unless
includeQuickWinsis false), then byopportunityScore. - Positions are Google top-100 only;
yourPosition: nullmeans not in the top 100. - A site with no data still costs its lookup and returns an
overviewrow with null counts. - The run stops at the caller's maximum cost and fetches only what it can bill.
- Track mode (
{"mode":"track","domain":"moz.com","keywords":["seo tools"],"trackDepth":10}) costs $0.005 per keyword per 10 results checked. Change fields are null on the first run for a setup.
⚠️ Disclaimer
This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Semrush Holdings, Inc., Ahrefs Pte. Ltd., Google LLC or DataForSEO. All trademarks mentioned are the property of their respective owners. Semrush and Ahrefs are named only to describe what kind of tool this is an alternative to.
The data comes from a licensed third-party SEO data provider and covers public Google search results only. It contains no personal data and nothing from behind any login. Rankings, traffic and volumes are estimates. Users are responsible for using the output in line with applicable law and their own contractual obligations.
SEO Keywords
competitor keywords, keyword gap analysis, keyword gap tool, competitor keyword research, ranked keywords api, domain keywords, organic keywords checker, semrush alternative, ahrefs alternative, spyfu alternative, content gap analysis, seo competitor analysis, find seo competitors, quick win keywords, keyword opportunities, google rankings export, seo agency reporting, content strategy keywords, rank tracker, serp position checker, keyword rank tracking, dataforseo labs, Apify seo actor