# Backlink Checker & Monitor (`datapulsehq/backlink-checker`) Actor

Backlink checker with an API for any website worldwide: backlinks, referring domains and anchor texts of a domain or page, with the rank of each linking page and domain, dofollow status and first and last seen dates. Monitor mode reports new and lost backlinks between runs.

- **URL**: https://apify.com/datapulsehq/backlink-checker.md
- **Developed by:** [Data Pulse](https://apify.com/datapulsehq) (community)
- **Categories:** SEO tools
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 result rows

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?

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 Checker & Monitor

Get the backlink profile of a domain, subdomain or single page: summary counts, the list of backlinks with anchor text and the rank of the linking page and domain, the referring domains and the most used anchors. In monitor mode the Actor compares each run with the previous one and outputs only the links that are new or lost.

Typical uses are checking the links of a competitor or a prospect, auditing your own link profile, finding broken or nofollow links, and getting a weekly list of new and lost links for a client site.

### What you get

For every target there is one summary row: domain rank (0 to 100), number of backlinks, referring domains, referring pages, broken backlinks and pages, spam risk values, and counts per link type, link attribute, referring TLD, country and position on the page.

Optional lists, each up to the limit you set:

- Backlinks, strongest first, with the source URL and domain, target URL, anchor text, dofollow or nofollow, link type (text, image, redirect, canonical), where on the page the link sits, link score, source page score and source domain score (all on the same 0 to 100 rank scale), spam risk, and first, previous and last seen dates.
- Referring domains, strongest first, with the domain rank, number of backlinks from it, spam risk and first seen date.
- Anchors, most used first, with the number of backlinks, referring domains and pages.

The domain rank comes from the link graph of the data source. It is a link-based rank: a page ranks higher when more pages, and stronger pages, link to it. It is not the metric of any SEO tool vendor, so numbers will not match other tools. The link, source page and source domain scores use the same scale.

The text around a link on the source page is not included.

### Monitor mode

With `monitor` on, the Actor keeps a baseline of the backlinks and referring domains lists for each target and settings in a named key-value store in your account. The first run saves the baseline and outputs the full lists with `change: "baseline"`. Later runs output only the changes.

A row with `change` set to `new` is a link that is in the current list but was not in the baseline. `firstSeenAfterBaseline` is true when the data source first saw the link after the baseline was saved. When it is false, the link existed before but was not in the baseline, usually because it moved into the top of a list that was cut at your limit.

A row with `change` set to `lost` is a link that was in the baseline and is no longer in the current list. Lost rows are built from the baseline, so they carry fewer fields.

Lost links are detected only when the full list fits under the row limit. If a target has more backlinks than `maxBacklinks`, or more referring domains than `maxReferringDomains`, the Actor reports no lost links for that list. It reports only links that are new to the top N, where N is your limit, and sets `lostDetection` to `skipped_list_truncated` in the run summary. On large sites this is the normal case. crawlee.dev, for example, has about 590,000 entries in its backlinks list, so a monitor run with `maxBacklinks: 20` compares only its 20 strongest links and cannot see links that disappear. The list totals are in the run summary (`total` for each list). To get lost links, set the limit above that total, up to 10,000.

The baseline moves forward after each run. If the maximum charge per run stops the Actor before all changes are delivered, the baseline for that list is kept, so the next run reports the same changes again. Changing any list setting starts a new baseline. Anchors are not compared and are delivered in full.

### Input

| Field | Default | Notes |
|---|---|---|
| `targets` | example | Up to 100 domains, subdomains or page URLs. A value with a path is checked as that page only. Duplicates are dropped, invalid entries are listed in the summary and not charged. Without this field the Actor runs a small example (apify.com, 10 backlinks). |
| `maxBacklinks` | 100 | Backlinks per target, up to 10,000. 0 skips the list. |
| `maxReferringDomains` | 0 | Referring domains per target, up to 10,000. |
| `maxAnchors` | 0 | Anchors per target, up to 1,000. |
| `backlinkMode` | `as_is` | `as_is` (every backlink), `one_per_domain` (one link from each referring domain) or `one_per_anchor` (one link for each anchor text; `Web scraping` and `web scraping` count as two anchors). |
| `dofollowOnly` | false | Only backlinks without a nofollow attribute. |
| `includeSubdomains` | true | For a domain target, include links to its subdomains. |
| `monitor` | false | Output only new and lost links compared with the previous monitor run. |
| `useCache` | true | Reuse results from earlier runs with the same target and settings. Ignored in monitor mode. |
| `cacheTtlDays` | 7 | Maximum age of cached results, 1 to 30 days. |
| `pushSummaryToDataset` | false | Append the run summary to the dataset. |

Example:

```json
{
    "targets": ["apify.com", "https://crawlee.dev/"],
    "maxBacklinks": 500,
    "maxReferringDomains": 200,
    "dofollowOnly": true
}
```

An empty `targets` list, or a list with only invalid entries, is invalid input. Invalid input ends the run as SUCCEEDED with a clear error message and no charge ($0).

### Output

All rows go to one dataset. `type` is `targetSummary`, `backlink`, `referringDomain` or `anchor`, and the dataset has a table view for each.

A backlink row:

```json
{
    "type": "backlink",
    "target": "apify.com",
    "sourceUrl": "https://crawlee.dev/",
    "sourceDomain": "crawlee.dev",
    "sourceTld": "dev",
    "sourceCountry": "US",
    "sourcePageTitle": "Crawlee · Build reliable crawlers. Fast.",
    "sourcePageLanguage": "en",
    "sourcePlatformTypes": ["unknown"],
    "targetUrl": "https://console.apify.com/actors/...",
    "targetDomain": "console.apify.com",
    "targetStatusCode": null,
    "anchor": "Run on",
    "linkType": "anchor",
    "dofollow": true,
    "attributes": [],
    "location": "section",
    "isBroken": false,
    "imageUrl": null,
    "linkScore": 81,
    "sourcePageScore": 92,
    "sourceDomainScore": 77,
    "linkSpamRisk": 0,
    "firstSeen": "2023-12-01T23:45:00.000Z",
    "previousSeen": "2026-08-07T15:01:33.000Z",
    "lastSeen": "2026-10-06T17:24:45.000Z",
    "flaggedNew": false,
    "flaggedLost": false,
    "source": "live",
    "fetchedAt": "2026-10-22T07:43:41.000Z"
}
```

`flaggedNew` and `flaggedLost` are the data source's own flags for links found or lost since its previous crawl of the source page. They are independent of monitor mode. `location` is the part of the page the link sits in (`main`, `article`, `footer`, `nav` and so on), or null when unknown.

A target without any known backlinks gets a summary row with `hasData: false` and no lists. Only the $0.05 per target is charged for it.

### Run summary

Every run saves a `SUMMARY` record in the default key-value store: valid, invalid and duplicate targets, per target the number of rows fetched and the list totals, whether each list was complete, new and lost counts and the lost detection status in monitor mode, cache hits, charged events and the run status. If the input has nothing the Actor can use (no valid targets, every target rejected by the data source, or a maximum charge per run too low for one target), the run ends as succeeded with an empty dataset, nothing is charged, and the status message says what was wrong and how to fix it; the summary status is then `invalid_input`.

### Pricing

Pay per event:

- $0.05 per target, charged after its summary lookup succeeds, also when the target has no known backlinks. Invalid targets and failed lookups are free.
- $0.035 per list page, one live request of up to 1,000 rows of backlinks, referring domains or anchors. Not charged for cached results.
- $0.002 per delivered row of backlinks, referring domains or anchors ($2 per 1,000 rows), fresh or from the cache. In monitor mode, each new or lost link.
- $0.0002 per compared row in monitor mode: a fetched link that matches the baseline and is not delivered.

Examples:

- 1 target, summary only (`maxBacklinks: 0`): $0.05.
- 1 target with 100 backlinks: $0.05 plus $0.035 plus $0.20, $0.285 in total.
- 10 targets with 100 backlinks each: $2.85.
- 1 target with 1,000 backlinks, 1,000 referring domains and 100 anchors: $0.05 plus 3 pages at $0.035 plus 2,100 rows ($4.20), $4.355 in total.
- Monitor run for 1 target with 1,000 backlinks tracked, 6 new and 6 lost: $0.05 plus $0.035 plus 994 compared rows ($0.1988) plus 12 rows ($0.024), $0.3078 in total.

If you set a maximum charge per run, the Actor requests only as many rows as that limit can pay for and stops cleanly when it is reached. Skipped targets are listed in the summary.

### Run time and limits

Each list page is one request, so a target with 10,000 backlinks takes 10 requests. Requests to the data source are rate limited per account. The Actor spaces its requests, waits and retries when a limit is hit, and records the waiting time in the summary.

### Apify free plan limit

Users on the Apify free plan get up to 20 dataset rows per run, counting the summary row of each target and the backlink, referring domain and anchor rows. Targets are handled in the order you list them, and targets left over are named under `freePlanLimit.skipped` in the run summary. In monitor mode a list cut short by the limit is not saved as the baseline. The run still finishes as succeeded, and its status message says that the free plan limit was reached.

This limit was set by the developer of this Actor, not by Apify. The link data is paid per request, and runs by free plan users bring the developer no revenue. Any paid Apify plan removes the limit, and nothing else about the run changes.

### Notes

- The link index is crawled continuously. New links can take days or weeks to appear and lost links to disappear, so monitor runs once a week or less often give the clearest results.
- Only live backlinks are listed. Internal links of the target are excluded.
- If a run is migrated in the middle of a target, that target's rows can be delivered twice. Targets that were finished before the migration are not repeated.
- Page targets must match the URL that is linked to. `https://example.com/page` and `https://example.com/page/` are different pages.

### API

```bash
curl -X POST "https://api.apify.com/v2/acts/datapulsehq~backlink-checker/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"targets": ["apify.com"], "maxBacklinks": 50}'
```

This Actor is an independent tool. It is not affiliated with, endorsed by, or sponsored by any search engine or SEO software vendor, and its rank and spam risk values are not the metrics of any such vendor. All trademarks belong to their respective owners.

# Actor input Schema

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

Domains, subdomains or page URLs, up to 100. A value with a path (https://example.com/blog/post) is checked as that page only. Without this field the Actor runs a small example.

## `maxBacklinks` (type: `integer`):

Backlinks with the highest link score come first. 0 skips the list. Up to 10,000. Users on the Apify free plan get at most 20 rows per run in total.

## `maxReferringDomains` (type: `integer`):

Referring domains with the highest domain rank come first. 0 skips the list. Up to 10,000.

## `maxAnchors` (type: `integer`):

Anchor texts with the most backlinks come first. 0 skips the list. Up to 1,000.

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

How the backlinks list is grouped.

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

Return only backlinks without a nofollow attribute. Applies to the backlinks list.

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

For a domain target, also count links to its subdomains.

## `monitor` (type: `boolean`):

Compare the backlinks and referring domains lists with the previous monitor run for the same target and settings, and output only new and lost links. The first run saves the baseline and outputs the full lists.

## `useCache` (type: `boolean`):

Reuse results for the same target and settings from earlier runs. Ignored in monitor mode.

## `cacheTtlDays` (type: `integer`):

Maximum age of cached results.

## `pushSummaryToDataset` (type: `boolean`):

Append the run summary as the last dataset row. It is always saved as SUMMARY in the key-value store.

## Actor input object example

```json
{
  "targets": [
    "apify.com"
  ],
  "maxBacklinks": 100,
  "maxReferringDomains": 0,
  "maxAnchors": 0,
  "backlinkMode": "as_is",
  "dofollowOnly": false,
  "includeSubdomains": true,
  "monitor": false,
  "useCache": true,
  "cacheTtlDays": 7,
  "pushSummaryToDataset": false
}
```

# Actor output Schema

## `backlinks` (type: `string`):

No description

## `summaries` (type: `string`):

No description

## `summary` (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 = {
    "targets": [
        "apify.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("datapulsehq/backlink-checker").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 = { "targets": ["apify.com"] }

# Run the Actor and wait for it to finish
run = client.actor("datapulsehq/backlink-checker").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 '{
  "targets": [
    "apify.com"
  ]
}' |
apify call datapulsehq/backlink-checker --silent --output-dataset

```

## MCP server setup

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

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/VlW4SHJm5WZa6EqtZ/builds/uFYZwOVtwnqQJAgbt/openapi.json
