# Ahrefs Website Stats Scraper (`automation-lab/ahrefs-domain-seo-snapshot`) Actor

Export public Ahrefs website stats: Domain Rating, linking sites, organic traffic/value, country and keyword samples, and available traffic/referring-domain histories. Supply domains or AhrefsTop URLs for recurring SEO benchmarking.

- **URL**: https://apify.com/automation-lab/ahrefs-domain-seo-snapshot.md
- **Developed by:** [Automation Lab](https://apify.com/automation-lab) (community)
- **Categories:** SEO tools, Developer tools
- **Stats:** 3 total users, 2 monthly users, 66.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.89 / 1,000 domain snapshots

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

## Ahrefs Website Stats Scraper

Export **ahrefs website stats** for recurring domain SEO benchmarking. Supply domains or public Ahrefs website detail URLs and get one structured snapshot per domain, including Domain Rating, linking websites, organic search traffic/value, public country and keyword samples, and available monthly histories.

This independent Actor reads the free AhrefsTop website surface. It does not access paid Ahrefs tools, detailed backlink edges, Keyword Explorer, accounts or AI visibility records. Ahrefs currently redirects its `/websites/domain` surface to `ahrefstop.com`.

### Who is it for?

SEO analysts can compare authority and search-traffic estimates across a portfolio. Agencies can refresh public competitor benchmarks. Data engineers can join source-specific historical observations to their own domain records.

### Why use it?

A snapshot keeps metrics and their public samples together in one row. Bulk inputs are normalized and deduplicated before collection. History dates are preserved separately from the scrape timestamp so a rerun is not confused with a new source observation. Partial failures are explicit, not successful empty exports.

### Ahrefs website stats included

| Field | Meaning |
|---|---|
| `domain`, `sourceUrl` | Normalized domain and canonical public source |
| `domainRating` | Ahrefs Domain Rating, nullable |
| `organicTraffic`, `trafficValue` | Latest chart estimate of monthly organic traffic and value in USD |
| `snapshotDate` | Date of the latest public traffic chart observation |
| `linkingWebsites`, `linkingWebsitesDisplay` | Rounded public summary count and its original compact text |
| `topCountries` | Public country sample with traffic, previous traffic and source share |
| `topKeywords` | Public keyword sample with volume, traffic and position |
| `trafficHistory` | Available monthly organic traffic and USD value points |
| `referringDomainsHistory` | Available monthly referring-domain points |
| `title`, `description`, `scrapedAt` | Page metadata and UTC collection time |

Missing optional metrics are null; unavailable samples are empty arrays. Public samples are not complete country or ranked keyword exports. On the tested pages, each sample contained five rows; source coverage can change. Historical referring-domain and traffic dates need not be identical. Compact displayed counts are expanded but remain rounded.

### Getting started

1. Enter bare domains such as `google.com` and `ahrefs.com`.
2. Optionally add canonical Ahrefs website detail URLs.
3. Set `maxItems` to the number of distinct domains to attempt.
4. Run the Actor and inspect its status and completeness summary.
5. Export the default dataset as JSON, CSV, Excel or XML using Apify.

```json
{"domains":["google.com","ahrefs.com"],"maxItems":10}
```

### Input parameters

| Parameter | Behavior |
|---|---|
| `domains` | Bare public DNS domains; no website paths or arbitrary URLs |
| `startUrls` | Public `https://ahrefs.com/websites/domain` or `https://ahrefstop.com/websites/domain` URLs |
| `maxItems` | Global distinct-domain attempt limit, default 10, range 1–100 |

At least one target is required in either list. Domains precede URL targets. Normalization lowercases domains, removes a trailing dot and converts IDNs to ASCII. Duplicates across both lists are removed before the limit. Combined inputs may contain at most 1,000 entries. Zero/unlimited limits are unsupported.

Category URLs, nested routes, query strings, fragments, credentials, ports, IP addresses and private hostnames are rejected. A URL such as `https://google.com` is not an Ahrefs detail URL; enter `google.com` in `domains` instead. Nested keyword/country/history entries have no separate collection limit: all included public records in the fetched snapshot are retained. Only `url` is read from request-list objects: `method`, `headers`, `payload` and `userData` are ignored and never forwarded. Every source lookup is a GET.

### Output example

This excerpt is from a current local public `google.com` snapshot. Arrays below are shortened for readability; the dataset retains the full public samples and histories.

```json
{
  "domain":"google.com",
  "sourceUrl":"https://ahrefstop.com/websites/google.com",
  "domainRating":99,
  "organicTraffic":2388313231,
  "trafficValue":620192131,
  "snapshotDate":"2026-10-01",
  "linkingWebsites":16300000,
  "linkingWebsitesDisplay":"16.3M",
  "trafficHistory":[{"date":"2026-10-01","organicTraffic":2388313231,"trafficValue":620192131}]
}
```

### How much does it cost to export Ahrefs domain snapshots?

Pricing is pay per event: a one-time start fee plus one domain snapshot event per useful saved row. Public keyword, country and history entries are included in that snapshot and have no separate event charge. Invalid, duplicate and failed domains do not generate a snapshot event. A validated run that later fails can still incur the start fee and charges for already saved useful snapshots.

The one-time start fee is **$0.00005 per run**. Snapshot prices depend on your aggregate monthly Apify Store spend tier, not this Actor's private run volume:

| Tier | Per domain snapshot |
|---|---:|
| FREE | $0.0036294 |
| BRONZE | $0.003156 |
| SILVER | $0.0024617 |
| GOLD / PLATINUM / DIAMOND | $0.0018936 |

BRONZE examples: one snapshot is approximately **$0.003206**, ten are **$0.03161**, and 100 are **$0.31565**, including one start fee. These are estimates for useful snapshots, not guaranteed invoices; use the applicable Store tier and run charge limit. Source traffic-value fields are not Actor prices.

### Limits and failures

The source provides estimates, not your analytics or guaranteed current totals. Available history length varies by domain. Domains outside the public index may fail to return a recognized snapshot; this Actor does not fabricate zero metrics for them.

Requests run sequentially. Network errors, 429 and temporary server errors receive at most three attempts with bounded backoff. Permanent errors and unrecognized pages fail without blind challenge retries. There is no automatic residential proxy, browser or captcha fallback and no customer credential requirement.

The `OUTPUT` key-value record reports attempted, saved and failed counts plus failure reasons. Any failed selected domain makes the run fail; saved rows remain partial. Check status and summary before using an export as a complete benchmark. Timeout/abort can leave partial data without a final summary.

### Comparing historical observations

Join traffic histories on `date` and `domain`, not array position across different domains. Keep referring-domain observations in their own dated series. The Google, Ahrefs and Wikipedia local controls each supplied 137 traffic/value months and 136 referring-domain months; these counts are observations, not a guarantee for other domains. Source revisions can change previously reported estimates. Save exports with their collection timestamps to distinguish a revised source estimate from a new month.

### Integrations

Use Apify schedules to refresh a fixed domain list and compare `snapshotDate`, not just `scrapedAt`. Send complete exports to a warehouse, spreadsheet, Make or Zapier workflow. Store raw histories outside a language-model context and compute changes in your own data pipeline. Scheduling does not create new source observations.

### API usage

Use your Apify token in an Authorization header; never place it in a shared input or public URL.

```bash
curl -X POST 'https://api.apify.com/v2/acts/automation-lab~ahrefs-domain-seo-snapshot/runs' \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"domains":["google.com","ahrefs.com"],"maxItems":2}'
```

JavaScript:

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/ahrefs-domain-seo-snapshot').call({ domains: ['google.com'], maxItems: 1 });
if (run.status !== 'SUCCEEDED') throw new Error(`Incomplete run: ${run.id}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems({ limit: 10 });
console.log(items);
```

Python:

```python
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/ahrefs-domain-seo-snapshot').call(run_input={'domains':['google.com'], 'maxItems':1})
if run['status'] != 'SUCCEEDED':
    raise RuntimeError(f"Incomplete run: {run['id']}")
print(client.dataset(run['defaultDatasetId']).list_items(limit=10).items)
```

### MCP setup

Claude Code setup — select this stable Actor subset:

```bash
claude mcp add --transport http apify 'https://mcp.apify.com?tools=automation-lab/ahrefs-domain-seo-snapshot'
```

Claude Desktop, Cursor, and VS Code clients with remote HTTP MCP support can use the equivalent endpoint configuration (adapt the transport wrapper to the client's supported version):

```json
{"mcpServers":{"apify":{"url":"https://mcp.apify.com?tools=automation-lab/ahrefs-domain-seo-snapshot"}}}
```

Example prompt: “Fetch public Ahrefs domain snapshots for google.com and ahrefs.com, then compare their traffic observation dates and Domain Ratings.”

Discover actual tool names and input schemas with scoped `tools/list`. Selection also includes run/data tools; discovery alone is not execution permission. Start an authorized run once and retain its run and storage IDs. `call-actor` waits at most 45 seconds; if nonterminal, follow that same run using bounded 2/4/8-second backoff capped at 10 seconds and a 120-second total deadline. Configure the client timeout above server wait plus transport margin. At the deadline report pending and the run ID; never restart merely to poll or recover a client timeout.

After success, read bounded untransformed dataset pages of 20 rows with explicit offset and needed fields. Example consumer budget: at most 100 source rows and 64 KiB serialized UTF-8 content admitted to model context, whichever comes first. Enforce byte limits host-side; omit/summarize oversized rows with disclosure. If your client cannot intercept oversized responses, do not claim a hard byte guarantee. Report returned rows, source continuation offset and partial/truncated status when incomplete. Full exports belong in storage or downstream processing. These are consumer context limits, not Actor collection limits. No numeric token savings are promised.

### Legality and privacy

Use public data responsibly and comply with source terms and applicable law. This tool is independent and not affiliated with Ahrefs. Estimates and proprietary source metrics remain subject to their owners' rights; this Actor grants no source-data license. No account credentials or private datasets are collected.

Failed operations send sanitized diagnostic input, exceptions and actor/build/run IDs to our private GlitchTip service for repair. Secret fields and URL queries are removed; reports are retained for 30 days. No AI provider processes runtime input or output. Actor datasets and summaries use your Apify storage retention settings; delete them through Console or the API when no longer needed. There is no cross-run cache. Contact us through the Actor's Apify Store issue channel for support.

### FAQ and troubleshooting

**Does this replace a paid Ahrefs account?** No. It exports only public website snapshots, not paid Keyword Explorer or backlink records.

**Why is the source AhrefsTop?** Ahrefs redirects its public website statistics pages to that canonical host. Both accepted URL forms resolve to the same source-specific workflow.

**Why do estimates look stale?** The scrape time records collection, while `snapshotDate` records the latest available chart month. Rerunning cannot force an upstream refresh.

**Why did my run fail with some data?** At least one selected domain did not produce a recognized snapshot. Inspect `OUTPUT` and treat the dataset as partial. Correct invalid inputs or retry later for a transient source failure.

**Can I get every keyword or country?** No. Only the source's public samples are included.

### Related Actors

For Google-ranked domain keywords from a different source, see [Competitor Domain Keywords Scraper](https://apify.com/automation-lab/competitor-domain-keywords-scraper). It is complementary, not an equivalent Ahrefs authority/history source. For a different traffic-estimation source, see [Similarweb Traffic Intelligence Scraper](https://apify.com/automation-lab/similarweb-traffic-intelligence-scraper).

# Changelog

This Actor's version history is a separate document: https://apify.com/automation-lab/ahrefs-domain-seo-snapshot/changelog.md

# Actor input Schema

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

Bare public DNS domains, for example google.com. Domains are lowercased, IDNs converted to ASCII, and duplicates removed across both input lists. Paths, IPs and private hostnames are rejected. Combined input maximum: 1,000 entries.

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

Canonical https://ahrefs.com/websites/domain or https://ahrefstop.com/websites/domain URLs. Combined with domains, in that order. No categories, subroutes, paid tools, queries, fragments or arbitrary website URLs. At least one target in either list is required. Only the url property is used: request-list method, headers, payload and userData metadata are ignored, never forwarded to the source; every source lookup is a GET.

## `maxItems` (type: `integer`):

Global limit on distinct domains attempted, after normalization and deduplication across both lists. Default 10, range 1–100; zero/unlimited is unsupported. Each snapshot includes all available public countries, keywords and histories without a separate nested-record limit. Failures are reported and make the run fail; already saved rows remain partial.

## Actor input object example

```json
{
  "domains": [
    "google.com",
    "ahrefs.com"
  ],
  "maxItems": 10
}
```

# Actor output Schema

## `dataset` (type: `string`):

Public metrics, countries, keywords and histories.

## `summary` (type: `string`):

Attempted, saved and failed domain counts.

# 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": [
        "google.com",
        "ahrefs.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/ahrefs-domain-seo-snapshot").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": [
        "google.com",
        "ahrefs.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/ahrefs-domain-seo-snapshot").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": [
    "google.com",
    "ahrefs.com"
  ]
}' |
apify call automation-lab/ahrefs-domain-seo-snapshot --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/ahrefs-domain-seo-snapshot"
        }
    }
}
```

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/cTQiihhdfelEwaXPP/builds/XYoBdDzrzLtevnQ7o/openapi.json
