SFOLN

Catalogue / SEO & search

SEO Competitor Analysis – Traffic & Keywords

sfoln/seo-competitor-snapshot · SEO tools, Lead generation, Developer tools On request

One record per domain: organic traffic and keyword estimates, position buckets, top 20 keywords, top 10 competitors, brand vs non-brand share and the live tech stack. $150 per 1,000 domains; $45 per 1,000 when only the overview has data.

About

What it does

Get a one-row SEO snapshot of any domain: estimated organic traffic and its ad-equivalent value, ranking keyword count with position buckets, the top 20 keywords by traffic (position, volume, URL), the top 10 organic competitors by shared keywords, the website's technology stack by category, and derived scores — traffic per keyword, top-10 share, value per visit and brand vs non-brand traffic share. Built for agency pitches, competitor research, M&A and investor screening, and sales prospecting where you need the SEO picture of many domains in one table.

Price

Price per delivered record

EventPricePer 1,000Charged for
SEO competitor snapshot
seo-competitor-snapshot
$0.15$150 / 1,000Charged once per domain: organic traffic and keyword overview, position buckets, top 20 keywords by traffic, top 10 organic competitors, technology stack and derived scores.
SEO overview only
seo-overview-only
$0.045$45 / 1,000Charged instead of seo-competitor-snapshot when only the domain overview could be delivered, or when the domain has no ranking data but DataForSEO billed the overview lookup.

Apify free plan: up to 2 items per run. Paid plans have no per-run cap; set maxTotalChargeUsd to cap spend.

Run

Call it from code, an agent or the Console

This API is private on Apify for now. Email us and we will publish it for you, usually within two working days. The calls below work once it is public. contact@sfoln.com

curl · synchronous run, rows in the response
curl -X POST "https://api.apify.com/v2/actors/sfoln~seo-competitor-snapshot/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"domains":["apify.com"]}'
mcp.json · hosted Apify MCP server
{
  "mcpServers": {
    "apify": {
      "type": "http",
      "url": "https://mcp.apify.com?tools=sfoln/seo-competitor-snapshot"
    }
  }
}
asynchronous run · for large batches
POST https://api.apify.com/v2/actors/sfoln~seo-competitor-snapshot/runs?maxTotalChargeUsd=1
GET  https://api.apify.com/v2/actor-runs/{runId}            # until status is SUCCEEDED
GET  https://api.apify.com/v2/datasets/{defaultDatasetId}/items?format=json

Authenticate with an Apify API token. MCP clients can instead sign in with OAuth when prompted. Example prompt for an agent: Compare the organic traffic, top keywords and main SEO competitors of apify.com and zyte.com in the United States.

Input

Input fields

List domains. Each domain produces one dataset record with organic traffic, top keywords, competitors and technologies.

FieldTypeDefaultMeaning
domains *arrayrequiredDomains
Domains or website URLs (apify.com, https://www.apify.com/store), one per line. Paths are ignored; duplicates are removed. Accounts on the Apify free plan can process up to 2 domains per run.
locationstring"2840"Location
DataForSEO location code (2840 = United States, 2826 = United Kingdom, 2276 = Germany) or full location name (e.g. "United Kingdom"). Applies to traffic, keywords and competitors.
languageCodestring"en"Language code
Language code, e.g. en, de, fr, es.
excludeTopDomainsbooleantrueExclude top domains from competitors
Drop very large generic sites (Wikipedia, Amazon, YouTube…) from the competitor list.
brandTermsarray—Brand terms
Words that mark a keyword as branded (e.g. apify, crawlee). Default: the domain name without its suffix (apify.com → apify).
maxItemsinteger100Max domains
Safety cap on how many domains are processed in this run. Range 1–1000.
concurrencyinteger2Concurrency
Domains processed in parallel (1–4). After the overview, each domain runs 2 DataForSEO tasks in parallel, next to one homepage fetch for the tech stack. Range 1–4.
itemTimeoutSecsinteger600Per-domain timeout (seconds)
Time limit per domain (300–1800). A section that failed with a server error is retried only while one more request fits in it. Range 300–1800.
includeRawbooleanfalseInclude raw upstream response
Attach the unmodified DataForSEO results and the full technology list (versions, confidence, evidence) under `raw` (large output).
Example input
{
  "domains": [
    "apify.com"
  ]
}

Output

One record per input item

Records land in the run's dataset; a synchronous call returns them directly. Each has a status (ok is charged; everything else is free) and a charged flag. The run's OUTPUT record totals items and charges.

FieldTypeMeaning
inputstring | objectInput
The input item this record corresponds to.
statusstringStatus
ok (snapshotType full or overview-only, charged) | not_found (no ranking data; charged seo-overview-only only if DataForSEO billed the lookup) | error | skipped_invalid | skipped_budget | skipped_free_plan e.g. "ok"
chargedbooleanCharged
Whether this record incurred a pay-per-event charge.
chargedEventstringCharged event
Pay-per-event event charged for this record.
sourcestringSource
Upstream data source (dataforseo+website = DataForSEO Labs for traffic, keywords and competitors; the website and its DNS for technologies).
fetchedAtstringFetched at
ISO timestamp.
errorobjectError
code / message when status is not ok (or a partial failure).
warningsarrayWarnings
Non-fatal notes (partial data, stopped early, free-plan caps).
domainstring | nullDomain
Target domain (no scheme, no www).
hasRankingDataboolean | nullHas ranking data
DataForSEO has organic rankings for the domain in this location/language.
snapshotTypestring | nullSnapshot type
full (charged seo-competitor-snapshot) | overview-only (charged seo-overview-only: only the overview has data, or a section failed) | none.
locationCodeinteger | nullLocation code
DataForSEO location code used.
languageCodestring | nullLanguage
Language code used.
organicTrafficEstimatenumber | nullOrganic traffic (est.)
Estimated monthly organic visits (ETV).
organicKeywordsinteger | nullOrganic keywords
Keywords the domain ranks for in the top 100.
organicTrafficValueUsdnumber | nullTraffic value (USD)
Estimated monthly cost of the organic traffic as Google Ads clicks.
organicTop3integer | nullTop 3 keywords
Keywords in positions 1–3.
organicTop10integer | nullTop 10 keywords
Keywords in positions 1–10.
positionBucketsobject | nullPosition buckets
{ pos1, pos2_3, pos4_10, pos11_20, pos21_50, pos51_100 } keyword counts.
organicNewinteger | nullNew keywords
Keywords newly ranking since the last update.
organicUpinteger | nullKeywords up
Keywords that moved up.
organicDowninteger | nullKeywords down
Keywords that moved down.
organicLostinteger | nullKeywords lost
Keywords no longer ranking.
paidKeywordsinteger | nullPaid keywords
Keywords with Google Ads presence.
paidTrafficEstimatenumber | nullPaid traffic (est.)
Estimated monthly paid visits.
paidTrafficCostUsdnumber | nullPaid traffic cost (USD)
Estimated monthly Google Ads cost.
trafficPerKeywordnumber | nullTraffic per keyword
organicTrafficEstimate ÷ organicKeywords.
top10KeywordSharePctnumber | nullTop-10 share %
organicTop10 ÷ organicKeywords × 100.
trafficValuePerVisitUsdnumber | nullValue per visit (USD)
organicTrafficValueUsd ÷ organicTrafficEstimate.
brandTermsarrayBrand terms
Terms used to classify branded keywords (input or domain name).
brandKeywordCountinteger | nullBrand keywords
Branded keywords among topKeywords.
brandKeywordSharePctnumber | nullBrand keyword share %
Branded ÷ topKeywords × 100.
brandTrafficSharePctnumber | nullBrand traffic share %
Estimated traffic of branded keywords ÷ traffic of topKeywords × 100.
topKeywordsarrayTop keywords
Up to 20 keywords by estimated traffic { keyword, position, searchVolume, etv, url, cpc, keywordDifficulty, searchIntent, isBrand }.
topCompetitorsarrayTop competitors
Up to 10 organic competitors by shared keywords { domain, intersections, avgPosition, organicEtv, organicKeywords, sharedKeywordsEtv }.
technologiesobject | nullTechnologies
Technologies detected live on the homepage and in DNS, by category: { category: [names] } (a technology appears under each of its categories); null when the homepage could not be fetched.
technologyNamesarrayTechnology names
All detected technologies.
technologyCountinteger | nullTechnology count
Number of detected technologies.
cmsstring | nullCMS
Content management system detected on the homepage (WordPress, Webflow, …).
ecommercePlatformstring | nullE-commerce platform
Shopify, WooCommerce, Magento, … when detected.
analyticsarray | nullAnalytics
Analytics tools detected (Google Analytics, Hotjar, …).
techUrlstring | nullTech page
Final URL of the homepage the technologies were detected on; null when it could not be fetched.
sectionsobject | nullSections
{ overview, rankedKeywords, competitors, technologies }: ok | empty | error (failed; a DataForSEO request that failed without running is retried once; technologies never change the charge).
Example record
{
  "input": "apify.com",
  "domain": "apify.com",
  "hasRankingData": true,
  "snapshotType": "full",
  "locationCode": 2840,
  "languageCode": "en",
  "organicTrafficEstimate": 40000,
  "organicKeywords": 2000,
  "organicTrafficValueUsd": 80000,
  "organicTop3": 150,
  "organicTop10": 500,
  "positionBuckets": {
    "pos1": 50,
    "pos2_3": 100,
    "pos4_10": 350,
    "pos11_20": 500,
    "pos21_50": 600,
    "pos51_100": 400
  },
  "organicNew": 10,
  "organicUp": 20,
  "organicDown": 5,
  "organicLost": 3,
  "paidKeywords": 10,
  "paidTrafficEstimate": 100,
  "paidTrafficCostUsd": 500,
  "trafficPerKeyword": 20,
  "top10KeywordSharePct": 25,
  "trafficValuePerVisitUsd": 2,
  "brandTerms": [
    "apify"
  ],
  "brandKeywordCount": 2,
  "brandKeywordSharePct": 50,
  "brandTrafficSharePct": 54.5,
  "topKeywords": [
    {
      "keyword": "apify",
      "position": 1,
      "searchVolume": 50000,
      "etv": 5000,
      "url": "https://apify.com/",
      "cpc": 1.5,
      "keywordDifficulty": 40,
      "searchIntent": "navigational",
      "isBrand": true
    }
  ],
  "topCompetitors": [
    {
      "domain": "brightdata.com",
      "intersections": 500,
      "avgPosition": 12.35,
      "organicEtv": 30000,
      "organicKeywords": 5000,
      "sharedKeywordsEtv": 3000
    }
  ],
  "technologies": {
    "Web frameworks": [
      "Next.js"
    ],
    "JavaScript frameworks": [
      "React"
    ],
    "CDN": [
      "Cloudflare"
    ],
    "Tag managers": [
      "Google Tag Manager"
    ],
    "Webmail": [
      "Google Workspace"
    ],
    "Email": [
      "Google Workspace",
      "Sendgrid"
    ]
  },
  "technologyNames": [
    "Next.js",
    "React",
    "Cloudflare",
    "Google Tag Manager",
    "Google Workspace",
    "Sendgrid"
  ],
  "technologyCount": 6,
  "cms": null,
  "ecommercePlatform": null,
  "analytics": [],
  "techUrl": "https://apify.com/",
  "sections": {
    "overview": "ok",
    "rankedKeywords": "ok",
    "competitors": "ok",
    "technologies": "ok"
  },
  "status": "ok",
  "charged": true,
  "chargedEvent": "seo-competitor-snapshot",
  "source": "dataforseo+website",
  "fetchedAt": "2026-10-14T10:00:00.000Z"
}

FAQ

Questions

Where do the traffic and keyword numbers come from?
From DataForSEO's Labs database: monthly estimates modelled from Google rankings and search volumes for the chosen location and language. They are comparable across domains but are not Google Search Console or analytics data.
When do I pay the lower overview-only price?
When the domain has ranking data but ranked keywords and competitors are both empty, or one of them failed (a request that failed without running is retried once), you pay $0.045 instead of $0.15 and keep everything that loaded. The tech stack is detected from the website itself and never changes the price.

Machine-readable

This page for agents