# Competitor SERP Domain Share Analyzer (`junipr/competitor-serp-domain-share-analyzer`) Actor

Aggregate SERP result snapshots into competitor domain share, rank distribution, result-type ownership, and query coverage reports

- **URL**: https://apify.com/junipr/competitor-serp-domain-share-analyzer.md
- **Developed by:** [junipr](https://apify.com/junipr) (community)
- **Categories:** SEO tools, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $11.50 / 1,000 query snapshot analyzeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Competitor SERP Domain Share Analyzer

Turn query-linked search result evidence into a domain visibility table. The actor groups accepted results by domain, measures query coverage and rank distribution, distinguishes owned and named competitor domains, and writes evidence-backed reports for SEO and competitive research.

### What you get

Each dataset row represents one observed domain and includes:

- number of distinct queries where the domain appeared;
- number of ranking URLs accepted for that domain;
- average position plus top-three and top-ten counts;
- count of non-organic result features owned by the domain;
- `owned`, `competitor`, or `other` classification;
- optional intent grouping derived from supplied query labels;
- share of all accepted result records;
- source URL, scan time, issue code, evidence, and a recommended next step.

The actor also writes a Markdown summary, CSV export, issue JSON, evidence JSON, and run metadata to the default key-value store when `includeReport` is enabled.

### Input choices

Use `serpResults` for structured evidence. Each item may be a result record or a snapshot object with a `query` and `results` array. Result records can contain `position`, `url`, `domain`, `resultType`, and `sourceUrl`.

Use `serpHtmlInputs` or `htmlInputs` for captured HTML. Associate each object with a `query`; the parser accepts explicitly marked result cards and visible result links. You may also supply explicit public `startUrls`. Network requests are limited to the URLs you provide, validated against `allowedDomains`, and never expanded by following discovered links.

Important controls:

- `queries`: restrict analysis to selected queries.
- `ownedDomains`: classify domains you control.
- `competitorDomains`: classify named competitors separately from other domains.
- `groupByIntent`: enable grouping from supplied query context.
- `minOccurrences`: omit domains below a stated evidence count.
- `maxQueries`, `maxSnapshots`, `maxResultsPerQuery`, `maxDomains`: bound accepted evidence and output.
- `includeEvidence`: include or suppress evidence excerpts.
- `includeRawSnapshots`: opt in to capped raw HTML storage.
- `maxChargeUsd`: stop before a paid event would exceed your run budget.

### Example input

```json
{
  "serpResults": [
    {
      "query": "workflow software",
      "sourceUrl": "https://example.com/serp/workflow-software",
      "results": [
        { "position": 1, "url": "https://competitor.example/workflows", "resultType": "organic" },
        { "position": 2, "url": "https://junipr.io/workflows", "resultType": "featured_snippet" }
      ]
    },
    {
      "query": "workflow automation",
      "sourceUrl": "https://example.com/serp/workflow-automation",
      "results": [
        { "position": 1, "url": "https://competitor.example/automation", "resultType": "organic" }
      ]
    }
  ],
  "queries": ["workflow software", "workflow automation"],
  "ownedDomains": ["junipr.io"],
  "competitorDomains": ["competitor.example"],
  "groupByIntent": true,
  "minOccurrences": 1,
  "maxQueries": 10,
  "maxSnapshots": 10,
  "maxResultsPerQuery": 20,
  "maxDomains": 50,
  "includeReport": true,
  "maxChargeUsd": 35
}
```

### Example output

```json
{
  "recordType": "competitor_serp_domain_share_analyzer",
  "recordName": "competitor.example",
  "issueCode": "competitor_serp_domain_share_analyzer_competitor_share",
  "severity": "medium",
  "domain": "competitor.example",
  "queryCount": 2,
  "rankingUrlCount": 2,
  "avgPosition": 1,
  "topThreeCount": 2,
  "topTenCount": 2,
  "featureOwnershipCount": 0,
  "ownedVsCompetitor": "competitor",
  "intentGroup": "mixed",
  "visibilityShare": 66.667,
  "sourceUrl": "https://example.com/serp/workflow-software",
  "scannedAt": "2026-07-10T12:00:00.000Z"
}
```

### Evidence rules

The actor reports only accepted structured records or visible result cards. It does not invent rankings, domains, query volume, or market share from query text. Missing evidence produces a nonempty diagnostic row instead of a fabricated competitor table. Access-denied or challenge content is identified as blocked evidence and is not treated as a SERP.

For reproducible comparisons, capture the same query set, result depth, locale, device, and collection method on every run. The actor measures share within the supplied evidence; it is not a population-level traffic estimate.

### Pay-per-event pricing

Platform usage pass-through is off. Charges occur before paid output is written, and `maxChargeUsd` is enforced as a hard ceiling.

| Event | Price |
| --- | ---: |
| `actor-start` | $0.0350 |
| `query-snapshot-analyzed` | $0.0115 |
| `domain-result-analyzed` | $0.0115 |
| `competitor-share-signal-emitted` | $0.0115 |
| `executive-report-generated` | $0.4000 |

The default maximum charge is $35. Set a lower value for tightly bounded runs. Setting it to zero prevents paid processing and output.

### Practical uses

- compare owned visibility with named competitors across a stable keyword set;
- identify domains repeatedly occupying top-three positions;
- inventory URLs and result features associated with each competitor;
- segment competitor visibility by supplied intent group;
- export a dated domain-share table for recurring SEO reporting.

### Limits

HTML layouts vary, so structured `serpResults` are the most stable input. The actor does not perform broad web discovery, estimate search demand, or infer results that are absent from the evidence. Raw HTML is stored only when requested, and source fetching rejects non-public or non-HTTP targets.

# Actor input Schema

## `startUrls` (type: `array`):

Optional explicit public URLs; private and non-HTTP targets are rejected.

## `sitemapUrls` (type: `array`):

Optional permitted public sitemap URLs.

## `htmlInputs` (type: `array`):

Deterministic HTML objects with sourceId, sourceUrl, and query context.

## `allowedDomains` (type: `array`):

Optional hostname allowlist for network fetches.

## `maxPages` (type: `integer`):

Overall HTML target cap.

## `maxDepth` (type: `integer`):

Fixed at zero because discovered links are not crawled.

## `includeEvidence` (type: `boolean`):

Include source evidence excerpts in dataset rows.

## `includeRawSnapshots` (type: `boolean`):

Store capped raw HTML in key-value storage.

## `requestDelayMs` (type: `integer`):

Delay between permitted public fetches.

## `timeoutMs` (type: `integer`):

Per-request timeout in milliseconds.

## `userAgentMode` (type: `string`):

Standard or compatibility request header.

## `serpResults` (type: `array`):

Query-linked result records or snapshot objects containing results.

## `queries` (type: `array`):

Queries associated with supplied snapshots.

## `serpHtmlInputs` (type: `array`):

Captured query-linked SERP HTML objects.

## `ownedDomains` (type: `array`):

Domains classified as owned visibility.

## `competitorDomains` (type: `array`):

Domains classified as named competitors.

## `groupByIntent` (type: `boolean`):

Attach a deterministic dominant query-intent group.

## `minOccurrences` (type: `integer`):

Minimum accepted result occurrences for a domain row.

## `maxQueries` (type: `integer`):

Maximum distinct queries processed.

## `maxSnapshots` (type: `integer`):

Maximum supplied snapshots processed.

## `maxResultsPerQuery` (type: `integer`):

Maximum result records accepted per query.

## `maxDomains` (type: `integer`):

Maximum aggregated domain rows emitted.

## `maxChargeUsd` (type: `number`):

Maximum accepted PPE spend before paid output stops.

## `includeReport` (type: `boolean`):

Write Markdown, CSV, JSON evidence, and run metadata.

## Actor input object example

```json
{
  "startUrls": [],
  "sitemapUrls": [],
  "htmlInputs": [],
  "allowedDomains": [],
  "maxPages": 1,
  "maxDepth": 0,
  "includeEvidence": true,
  "includeRawSnapshots": false,
  "requestDelayMs": 250,
  "timeoutMs": 15000,
  "userAgentMode": "standard",
  "serpResults": [],
  "queries": [
    "workflow software"
  ],
  "serpHtmlInputs": [],
  "ownedDomains": [
    "junipr.io"
  ],
  "competitorDomains": [],
  "groupByIntent": true,
  "minOccurrences": 1,
  "maxQueries": 1,
  "maxSnapshots": 1,
  "maxResultsPerQuery": 10,
  "maxDomains": 25,
  "maxChargeUsd": 35,
  "includeReport": true
}
```

# Actor output Schema

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

No description

## `report` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("junipr/competitor-serp-domain-share-analyzer").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("junipr/competitor-serp-domain-share-analyzer").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 '{}' |
apify call junipr/competitor-serp-domain-share-analyzer --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,junipr/competitor-serp-domain-share-analyzer"
        }
    }
}
```

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/qGeb8iK6eD6MMH7eQ/builds/whMkXOsGRqa2Qtq5W/openapi.json
