# SEO Competitor Analysis – Traffic & Keywords (`sfoln/seo-competitor-snapshot`)

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.

- Family: SEO & search
- Categories: SEO tools, Lead generation, Developer tools
- Availability: on request (private on Apify). Email contact@sfoln.com with subject "Access request: SEO Competitor Analysis – Traffic & Keywords (sfoln/seo-competitor-snapshot)" before calling; calls fail until it is public.
- JSON: https://www.sfoln.com/actors/seo-competitor-snapshot.json
- MCP: https://mcp.apify.com?tools=sfoln/seo-competitor-snapshot
- REST (sync): POST https://api.apify.com/v2/actors/sfoln~seo-competitor-snapshot/run-sync-get-dataset-items
- REST (async): POST https://api.apify.com/v2/actors/sfoln~seo-competitor-snapshot/runs

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 per delivered record

| Event | Price | Per 1,000 | Charged for |
| --- | --- | --- | --- |
| SEO competitor snapshot (`seo-competitor-snapshot`) | $0.15 | $150 / 1,000 | Charged 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,000 | Charged 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. |

Pay-per-event, USD, billed by Apify; no platform usage charge. Only records with status `ok` are charged. Cap a run with `maxTotalChargeUsd`. Apify free plan: up to 2 per run.

## Run

```bash
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 client configuration:

```json
{
  "mcpServers": {
    "apify": {
      "type": "http",
      "url": "https://mcp.apify.com?tools=sfoln/seo-competitor-snapshot"
    }
  }
}
```

Example prompt: Compare the organic traffic, top keywords and main SEO competitors of apify.com and zyte.com in the United States.

## Input

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

| Field | Type | Default | Meaning |
| --- | --- | --- | --- |
| `domains` (required) | array | — | Domains: 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. |
| `location` | string | `"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. |
| `languageCode` | string | `"en"` | Language code: Language code, e.g. en, de, fr, es. |
| `excludeTopDomains` | boolean | `true` | Exclude top domains from competitors: Drop very large generic sites (Wikipedia, Amazon, YouTube…) from the competitor list. |
| `brandTerms` | array | — | Brand terms: Words that mark a keyword as branded (e.g. apify, crawlee). Default: the domain name without its suffix (apify.com → apify). |
| `maxItems` | integer | `100` | Max domains: Safety cap on how many domains are processed in this run. |
| `concurrency` | integer | `2` | Concurrency: 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. |
| `itemTimeoutSecs` | integer | `600` | Per-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. |
| `includeRaw` | boolean | `false` | Include raw upstream response: Attach the unmodified DataForSEO results and the full technology list (versions, confidence, evidence) under `raw` (large output). |

Example input:

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

## Output

One record per input item with `status` (`ok` is charged; `not_found`, `error`, `skipped_*` are free) and `charged`. The run stores an `OUTPUT` summary record.

| Field | Type | Meaning |
| --- | --- | --- |
| `input` | string | object | Input: The input item this record corresponds to. |
| `status` | string | Status: 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 |
| `charged` | boolean | Charged: Whether this record incurred a pay-per-event charge. |
| `chargedEvent` | string | Charged event: Pay-per-event event charged for this record. |
| `source` | string | Source: Upstream data source (dataforseo+website = DataForSEO Labs for traffic, keywords and competitors; the website and its DNS for technologies). |
| `fetchedAt` | string | Fetched at: ISO timestamp. |
| `error` | object | Error: code / message when status is not ok (or a partial failure). |
| `warnings` | array | Warnings: Non-fatal notes (partial data, stopped early, free-plan caps). |
| `domain` | string | null | Domain: Target domain (no scheme, no www). |
| `hasRankingData` | boolean | null | Has ranking data: DataForSEO has organic rankings for the domain in this location/language. |
| `snapshotType` | string | null | Snapshot type: full (charged seo-competitor-snapshot) \| overview-only (charged seo-overview-only: only the overview has data, or a section failed) \| none. |
| `locationCode` | integer | null | Location code: DataForSEO location code used. |
| `languageCode` | string | null | Language: Language code used. |
| `organicTrafficEstimate` | number | null | Organic traffic (est.): Estimated monthly organic visits (ETV). |
| `organicKeywords` | integer | null | Organic keywords: Keywords the domain ranks for in the top 100. |
| `organicTrafficValueUsd` | number | null | Traffic value (USD): Estimated monthly cost of the organic traffic as Google Ads clicks. |
| `organicTop3` | integer | null | Top 3 keywords: Keywords in positions 1–3. |
| `organicTop10` | integer | null | Top 10 keywords: Keywords in positions 1–10. |
| `positionBuckets` | object | null | Position buckets: { pos1, pos2_3, pos4_10, pos11_20, pos21_50, pos51_100 } keyword counts. |
| `organicNew` | integer | null | New keywords: Keywords newly ranking since the last update. |
| `organicUp` | integer | null | Keywords up: Keywords that moved up. |
| `organicDown` | integer | null | Keywords down: Keywords that moved down. |
| `organicLost` | integer | null | Keywords lost: Keywords no longer ranking. |
| `paidKeywords` | integer | null | Paid keywords: Keywords with Google Ads presence. |
| `paidTrafficEstimate` | number | null | Paid traffic (est.): Estimated monthly paid visits. |
| `paidTrafficCostUsd` | number | null | Paid traffic cost (USD): Estimated monthly Google Ads cost. |
| `trafficPerKeyword` | number | null | Traffic per keyword: organicTrafficEstimate ÷ organicKeywords. |
| `top10KeywordSharePct` | number | null | Top-10 share %: organicTop10 ÷ organicKeywords × 100. |
| `trafficValuePerVisitUsd` | number | null | Value per visit (USD): organicTrafficValueUsd ÷ organicTrafficEstimate. |
| `brandTerms` | array | Brand terms: Terms used to classify branded keywords (input or domain name). |
| `brandKeywordCount` | integer | null | Brand keywords: Branded keywords among topKeywords. |
| `brandKeywordSharePct` | number | null | Brand keyword share %: Branded ÷ topKeywords × 100. |
| `brandTrafficSharePct` | number | null | Brand traffic share %: Estimated traffic of branded keywords ÷ traffic of topKeywords × 100. |
| `topKeywords` | array | Top keywords: Up to 20 keywords by estimated traffic { keyword, position, searchVolume, etv, url, cpc, keywordDifficulty, searchIntent, isBrand }. |
| `topCompetitors` | array | Top competitors: Up to 10 organic competitors by shared keywords { domain, intersections, avgPosition, organicEtv, organicKeywords, sharedKeywordsEtv }. |
| `technologies` | object | null | Technologies: 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. |
| `technologyNames` | array | Technology names: All detected technologies. |
| `technologyCount` | integer | null | Technology count: Number of detected technologies. |
| `cms` | string | null | CMS: Content management system detected on the homepage (WordPress, Webflow, …). |
| `ecommercePlatform` | string | null | E-commerce platform: Shopify, WooCommerce, Magento, … when detected. |
| `analytics` | array | null | Analytics: Analytics tools detected (Google Analytics, Hotjar, …). |
| `techUrl` | string | null | Tech page: Final URL of the homepage the technologies were detected on; null when it could not be fetched. |
| `sections` | object | null | Sections: { 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:

```json
{
  "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

**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.


## Related

- [Website Traffic Checker – SEO Overview](https://www.sfoln.com/actors/domain-seo-overview.md) (`sfoln/domain-seo-overview`)
- [Ranked Keywords Checker for Any Domain](https://www.sfoln.com/actors/ranked-keywords.md) (`sfoln/ranked-keywords`)
- [Competitor Domains Finder (SEO)](https://www.sfoln.com/actors/competitor-domains.md) (`sfoln/competitor-domains`)
- [Website Audit – SEO, Security, SSL & DNS](https://www.sfoln.com/actors/website-audit.md) (`sfoln/website-audit`)
- [Tech Stack Detector – Website Technologies](https://www.sfoln.com/actors/tech-stack-detector.md) (`sfoln/tech-stack-detector`)

Publisher: SFOLN LLC, contact@sfoln.com. Catalogue: https://www.sfoln.com/catalog.json. Agent guide: https://www.sfoln.com/agents.md.
