# Backlink Scraper — Backlink Analysis, Audit & Anchor Text (`afanasenko/backlink-scraper`) Actor

Backlink scraper and backlink checker: get the backlinks of any domain or URL with anchor text, source page, dofollow or nofollow, first and last seen, spam score and domain rank. Backlink analysis for SEO audits and link building, with lost links and referring domains. CSV, JSON or Excel.

- **URL**: https://apify.com/afanasenko/backlink-scraper.md
- **Developed by:** [Andrey Afanasenko](https://apify.com/afanasenko) (community)
- **Categories:** SEO tools, Developer tools, Automation
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.90 / 1,000 backlinks

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

## Backlink Scraper — Backlink Analysis, Audit & Anchor Text

[![Apify Actor](https://apify.com/actor-badge?actor=afanasenko/backlink-scraper)](https://apify.com/afanasenko/backlink-scraper)

> **Get the backlinks of any website — every linking page, its anchor text, dofollow, dates, spam score and strength.**
> For SEO audits, link building and competitor research. Filter by dofollow, strength and spam before you pay, and switch to lost links or one link per referring domain in one click.

> **🆓 Free to start:** 5 domains a month on the free plan · the first 20 backlinks of each in full · the next 25 shown with their strength, dofollow and dates.

### 🎯 What it does

**You give** one or more domains (`example.com`), subdomains (`blog.example.com`) or pages (`https://example.com/pricing`), one per line.

**You get** one row per backlink: the linking page and its title, the anchor text and the words around it, which of your pages it points to, dofollow or not, when it was first and last seen, and how strong and how spammy it is. Every row also says how many backlinks the domain has in total.

**What you won't get** numbers from another SEO tool. Strength and spam scores are this index's own 0–100 scales, and totals can differ from other tools that crawl the web differently.

**Filters** narrow the list before anything is charged: dofollow only, a minimum strength of the linking site, a maximum spam score, live or lost links, and one link per referring domain or per anchor text.

### 📦 Output sample

Every backlink is one row. Here is what a row holds:

- **The link** — `sourceUrl`, `sourceTitle`, `sourceDomain`, `targetUrl`, `anchor`, `textBefore`, `textAfter`, `linkType`, `dofollow`, `relAttributes`, `linkLocation`, `linksFromPage`; `imageUrl` and `imageAlt` for image links.
- **When** — `firstSeen`, `lastSeen`, `previousSeen`, `isNew`, `isLost`.
- **How good it is** — `backlinkRank`, `sourcePageRank`, `sourceDomainRank`, `spamScore`, `isBroken`, `sourceKeywordsTop3`, `sourceKeywordsTop10`, `sourceKeywordsTop100`, `sourceExternalLinks`, `sourceInternalLinks`.
- **The linking site, your page and the row** — `sourceCountry`, `sourceLanguage`, `sourceTld`, `sourceIp`, `sourcePlatformTypes`; `targetStatusCode`, `targetRedirectUrl`, `targetSpamScore`, `isIndirect`, `indirectPath` when known; `target`, `totalBacklinks`, `position`, `rowStatus`, `note`, `scrapedAt`.

A real row for `mediakix.com`, with the defaults:

```json
{
  "target": "mediakix.com",
  "totalBacklinks": 27247,
  "position": 1,
  "sourceUrl": "https://www.calendar.com/blog/7-time-wasters-taking-away-from-your-productivity/",
  "sourceDomain": "www.calendar.com",
  "sourceTitle": "7 Time Wasters Taking Away From Your Productivity - Calendar",
  "targetUrl": "http://mediakix.com/2016/12/how-much-time-is-spent-on-social-media-lifetime/",
  "anchor": "study",
  "linkType": "anchor",
  "dofollow": true,
  "relAttributes": null,
  "linkLocation": "article",
  "textBefore": "According to a",
  "textAfter": "by influencer marketing agency Mediakix, the average person spends 40 minutes per day on YouTube...",
  "imageUrl": null,
  "imageAlt": null,
  "linksFromPage": 1,
  "firstSeen": "2023-07-28T23:40:00.000Z",
  "lastSeen": "2026-08-29T10:28:21.000Z",
  "previousSeen": "2026-04-13T21:29:48.000Z",
  "isNew": false,
  "isLost": false,
  "backlinkRank": 40,
  "sourcePageRank": 65,
  "sourceDomainRank": 61,
  "spamScore": 0,
  "isBroken": false,
  "sourceCountry": "US",
  "sourceLanguage": "en",
  "sourceTld": "com",
  "sourceIp": "172.67.75.35",
  "sourcePlatformTypes": ["unknown"],
  "sourceExternalLinks": 26,
  "sourceInternalLinks": 53,
  "sourceKeywordsTop3": 0,
  "sourceKeywordsTop10": 0,
  "sourceKeywordsTop100": 4,
  "targetStatusCode": null,
  "targetRedirectUrl": null,
  "targetSpamScore": null,
  "isIndirect": false,
  "indirectPath": null,
  "rowStatus": "ok",
  "note": null,
  "scrapedAt": "2026-10-05T19:20:00.000Z"
}
```

A value the index does not have is `null`, and every row carries every key. The three `target…` status columns are filled for some domains and empty for others.

**Views** — 2 ways to look at the same rows, in the **Storage → Dataset** tab:

| View | What each row is | Best for |
|---|---|---|
| **Backlinks** (default) | One backlink, trimmed to the link, its anchor, dofollow, strength, spam score and dates | Link building and competitor research |
| **Backlink audit** | The same rows, trimmed to dofollow, rel attributes, spam score, lost and broken flags and your page's status | Cleaning up a link profile |

The full per-field schema is published in [`.actor/dataset_schema.json`](.actor/dataset_schema.json) — that's also what AI agents see when they call the actor through Apify's MCP server.

### ⚡ Quick start

A minimal input that works on the **free plan**:

```json
{
  "targets": ["mediakix.com"]
}
```

Run it once and open the **Storage → Dataset** tab: you'll see the domain's strongest backlinks first. Add filters to narrow the list.

### 🧭 When to use it

- **Audit your own backlinks** — find spammy, lost and broken links before they hurt your rankings.
- **Study a competitor** — see who links to them, with which anchor text, and pitch the same sites.
- **Find link-building targets** — keep dofollow links from strong, clean sites with one link per referring domain.
- **Track link building work** — sort by newest to see which links a campaign earned, or by recently seen to watch them stick.
- **Check a domain before you buy it** — an expired or for-sale domain's backlinks show whether it is worth the price.

### 🛠 Input

The input form has two sections:

| Section | Purpose |
|---|---|
| 🎯 Which site | The domains or pages to check, and how many backlinks to return for each |
| 🔬 Filters | Which backlinks come back: live or lost, dofollow, strength, spam, grouping and order |

Highlights of the most useful fields:

- **`targets`** — one domain, subdomain or page URL per line. A home-page URL counts as the whole domain.
- **`maxBacklinksPerTarget`** — how many backlinks each domain returns, strongest first. Default 100, up to 20,000.
- **`backlinkMode`** — all backlinks, one per linking domain (a referring-domains list), or one per anchor text.
- **`linkStatus`** — live links, lost links, or both.
- **`dofollowOnly`**, **`minDomainRank`**, **`maxSpamScore`** — keep only links worth having.
- **`sortBy`** — strongest first, newest first, or recently seen first. It decides which backlinks a limit keeps.

### 💰 How much will scraping backlinks cost?

You pay per backlink delivered and per domain looked up, with Apify's **Pay Per Event** model:

| Event | Free | Bronze | Silver | Gold and up | Charged when |
|---|---|---|---|---|---|
| **Backlink** | $0.0045 | $0.0036 | $0.0032 | $0.0029 | A backlink lands in your dataset in full |
| **Domain lookup** | $0.05 | $0.04 | $0.035 | $0.031 | A domain or page is checked — also when it has no backlinks |

Filters work before you pay: a backlink they drop is never charged. A lookup that could not be completed is not charged either.

**Pricing math**

| You check | Plan | Approx cost |
|---|---|---|
| 1 domain × 100 backlinks (the default) | Bronze | $0.40 |
| 1 domain × 1,000 backlinks | Bronze | $3.64 |
| 10 domains × 100 backlinks | Bronze | $4.00 |
| 1 domain with no backlinks | Bronze | $0.04 |
| 5 domains on the free plan | Free | up to $0.70 of your free credit |

Set **Maximum cost per run** in the run options to cap any run; the actor stops exactly there and says so.

### 🆓 Free vs paid plan

| | Free plan | Paid plan |
|---|---|---|
| Domains per month | 5 | Unlimited |
| Backlinks per domain in full | 20 | Up to 20,000 |
| More backlinks shown locked | The next 25 — strength, dofollow and dates visible, the linking page hidden | — |
| Filters, lost links, grouping | ✓ | ✓ |

Upgrade to a paid plan to see every backlink in full and check as many domains as you like.

### 🧪 Filter recipes

Copy-paste inputs for the most common jobs:

**Link-building targets: one strong, clean dofollow link per site**

```json
{
  "targets": ["competitor.com"],
  "maxBacklinksPerTarget": 500,
  "backlinkMode": "onePerDomain",
  "dofollowOnly": true,
  "minDomainRank": 30,
  "maxSpamScore": 10
}
```

**Backlink audit: the spammiest links first in view**

```json
{
  "targets": ["example.com"],
  "maxBacklinksPerTarget": 1000,
  "linkStatus": "all"
}
```

Open the **Backlink audit** view and sort by `spamScore`.

**Lost links: what disappeared recently**

```json
{
  "targets": ["example.com"],
  "linkStatus": "lost",
  "sortBy": "recentlySeen"
}
```

### 📡 Live status & storage records

While the run is in progress, the actor exposes:

| Storage key | Type | What it holds |
|---|---|---|
| `status.html` | HTML page | Live progress, backlinks saved and cost so far. Open it from the run's Storage tab. |
| `RUN_SUMMARY` | JSON | Per domain: total backlinks in the index, backlinks delivered and shown locked; lookups, prices and the stop reason. |
| `USER_MESSAGE` | JSON | What happened and what to change — written on every run that returned no backlinks. |
| `FREE_LIMITS_APPLIED` | JSON | The free-plan limits that applied to this run. Empty on paid plans. |

These are stable, machine-readable surfaces — pull them through the Apify API for dashboards or post-processing.

### 🤖 Programmatic / API use

Run the actor from your own code or AI agent:

**REST API (start a run, poll for completion):**

```bash
curl -X POST "https://api.apify.com/v2/acts/afanasenko~backlink-scraper/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"targets": ["mediakix.com"], "maxBacklinksPerTarget": 100}'
```

**MCP / agentic clients (Claude, ChatGPT, Cursor, LangGraph, OpenAI Agents SDK, Mastra, …):**

The actor is automatically exposed as a tool through Apify's [MCP server](https://docs.apify.com/platform/integrations/mcp) at `mcp.apify.com`. Once your MCP client is connected to your Apify token, an LLM can run it with instructions like *"List the dofollow backlinks of competitor.com from sites with rank above 30"*.

### 💡 Tips & Best Practices

#### Getting maximum results

- Check a competitor's whole domain, not its home page: a home-page URL already counts as the domain.
- Use one link per referring domain to see how many sites link, not how many pages.
- Switch on lost links to find sites that linked before — they are often happy to link again.

#### Cost optimization

- Put filters in the input, not in your spreadsheet: a backlink a filter drops is never charged.
- Start with the default 100 per domain. Raise the limit only for the domains that matter.
- Remove typos before a big run: a domain with no backlinks still costs one lookup.

#### Performance

- A page of up to 1,000 backlinks comes back in about a second.
- Domains are checked one after another when a run has a cost limit, so a long list adds about a second per domain.
- 20,000 backlinks for one domain are 20 pages of 1,000 — about a second each.

#### Data quality

- Spot-check five links in a browser before you act on a big list.
- Read `spamScore` together with `sourceDomainRank`: a strong site with a high spam score is rare and worth a look.

### ❓ FAQ

**Q: How do I check the backlinks of a website?**
A: Put the domain in **Domains or URLs** and click **Start**. The dataset lists its backlinks, strongest first.

**Q: Is there a free backlink checker?**
A: Yes. The free plan checks 5 domains a month and shows the first 20 backlinks of each in full — see [Free vs paid plan](#-free-vs-paid-plan).

**Q: How do I find the referring domains of a site?**
A: Set **Backlinks to return** to *One per linking domain*. You get one row per site that links, with its strongest link.

**Q: What are the best backlink checker alternatives?**
A: Large SEO suites sell this data by monthly subscription. Here you pay per backlink, so a one-off audit costs cents and lands in a spreadsheet.

**Q: Is "domain rank" the same as Domain Rating or Domain Authority?**
A: No. It is this index's own 0–100 strength score. It ranks sites in a similar way, but the number will not match other tools.

**Q: Why did a domain with no backlinks cost a lookup?**
A: The check itself is the work, whether it finds links or not. A lookup that could not be completed is not charged.

**Q: Why do I see `null` in some columns?**
A: `null` means the index has no value for that link — for example no anchor on an image link. Every row carries every key, so a spreadsheet keeps its columns.

**Q: What do the locked rows on the free plan mean?**
A: They are real backlinks of the same domain. Their strength, dofollow and dates are shown; the linking page is hidden until you upgrade.

**Q: Can I check a single page instead of a whole domain?**
A: Yes — paste the full URL, for example `https://example.com/pricing`. You get only the links that point to that page.

**Q: How fast is it?**
A: About a second for a page of up to 1,000 backlinks, so a run of 10 domains with the defaults spends about 10 seconds on lookups.

**Q: What if a domain cannot be checked?**
A: The run retries, then moves on. The domain is named in the run's message and is not charged; run it again in a few minutes.

### 🔗 Other related actors (same author)

| You start with… | You want to find… | Use this actor |
|---|---|---|
| A domain or a page | Its backlinks, anchor text and referring domains | **This actor** |
| A company that links to you | The people to contact there, by job title | [LinkedIn People Search](https://apify.com/afanasenko/linkedin-people-search) |

Use this actor to find the sites; use LinkedIn People Search to find who runs them.

### 🛟 Support & feedback

- **Open an issue** in the actor's Issues tab — the fastest way to get a fix shipped.
- **Feature requests** go in the same tab; we read every one.
- **Ratings & reviews** on the [Apify Store page](https://apify.com/afanasenko/backlink-scraper) help other users find the actor.

### ⚖️ Is it legal to scrape backlinks?

Yes — a backlink is a public link on a public web page, and this actor reports only what anyone can see by visiting those pages. It does not log in anywhere or touch private content. Courts in the US have upheld collecting public web data (hiQ Labs v. LinkedIn); see Apify's guide on [whether web scraping is legal](https://blog.apify.com/is-web-scraping-legal/). Use the data in line with your local laws.

### 📋 Changelog

See [CHANGELOG.md](./CHANGELOG.md).

# Changelog

This Actor's version history is a separate document: https://apify.com/afanasenko/backlink-scraper/changelog.md

# Actor input Schema

## `targets` (type: `array`):

One address per line: a domain (example.com), a subdomain (blog.example.com) or a page (https://example.com/pricing). A home-page URL counts as the whole domain.

## `maxBacklinksPerTarget` (type: `integer`):

The most backlinks returned for each domain or URL, strongest first by default. Up to 20,000.

## `backlinkMode` (type: `string`):

All backlinks lists every linking page. One per linking domain keeps the strongest link from each site — a referring-domains list. One per anchor text keeps one link for each distinct anchor.

## `linkStatus` (type: `string`):

Live links are on the page today. Lost links were found before and have since disappeared.

## `dofollowOnly` (type: `boolean`):

Only links that pass ranking value — no nofollow, ugc or sponsored links.

## `minDomainRank` (type: `integer`):

Only links from sites at least this strong, on a 0–100 scale. Empty means any.

## `maxSpamScore` (type: `integer`):

Only links with a spam score at most this high, on a 0–100 scale. Empty means any.

## `sortBy` (type: `string`):

Which backlinks come first — and so which ones a limit keeps.

## `includeSubdomains` (type: `boolean`):

For a domain, also count links to its subdomains (blog.example.com, shop.example.com).

## Actor input object example

```json
{
  "maxBacklinksPerTarget": 100,
  "backlinkMode": "all",
  "linkStatus": "live",
  "dofollowOnly": false,
  "sortBy": "strongest",
  "includeSubdomains": true
}
```

# Actor output Schema

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

No description

## `audit` (type: `string`):

No description

## `liveStatus` (type: `string`):

No description

## `userMessage` (type: `string`):

What happened this run and what to change — written on every run that returned no backlinks, and on free-plan and first-paid runs.

## `runSummary` (type: `string`):

Per domain: total backlinks in the index, backlinks delivered and shown locked; lookups, prices and the stop reason.

## `freeLimitsApplied` (type: `string`):

Free-plan limits that affected this run. Empty on paid plans.

# 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("afanasenko/backlink-scraper").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("afanasenko/backlink-scraper").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 afanasenko/backlink-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,afanasenko/backlink-scraper"
        }
    }
}
```

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/mrjsNNnhbba9nrg6w/builds/2QS4WXzQ6xXOfvdeq/openapi.json
