Skip to content
SEO Uptr
SEO UptrGet $100 free

Recipe

Lost backlinks monitor: snapshot, diff, notify

People ask how to notice dead links before rankings do. The answer is boring and reliable: save the list every week and compare it with the last one.

What you are building

A cron job that runs once a week. It stores the list of your referring domains as a dated file, compares it with the previous file, and posts the difference somewhere a human will see it. That is the whole system.

We pull domains, not URLs. There is a reason. A domain-level list is small, stable and cheap, so a diff of two files stays readable, while URL-level lists churn with every redesign and bury the real losses under noise. When you need page detail for one lost domain, ask for backlinks on demand and pay 2 credits for that one lookup.

Run it twice by hand. The first run has no previous file, and the second proves the diff works. Check the output against a link you know you removed.

The recipe

01

Pick the cadence

Weekly. Our index refreshes about monthly, so daily runs return the same file most days. The weekly run catches the refresh within seven days whenever it lands.

02

Take the snapshot

Call refdomains with per=1000 and write the sorted JSON to a dated file. One call, 2 credits, whatever the row count up to 1,000 rows.

03

Diff against last week

Compare the two files with diff or jq. Lines that only exist in the old file are your lost domains.

04

Gate the alert

Count the lost lines. Below your SEV2 line, write a log entry. Above it, send the message. The severity table has starting values.

05

Check the response status

If the status is 402, credit ran out. If 401, the key is wrong. Alert on both, or your monitor will fail in silence.

The script

Bash, curl, jq. Replace the webhook with your own.

bash
#!/usr/bin/env bash
set -euo pipefail
KEY="sk_live_..."
DOM="yourdomain.com"
DIR="$HOME/linkwatch/$DOM"; mkdir -p "$DIR"
NEW="$DIR/$(date +%F).json"

code=$(curl -s -o "$NEW.raw" -w '%{http_code}' \
  "https://seouptr.com/api.php?action=refdomains&q=$DOM&per=1000&key=$KEY")
[ "$code" = 200 ] || { echo "api returned $code" >&2; exit 1; }
jq -e '.ok' "$NEW.raw" >/dev/null
jq -S . "$NEW.raw" > "$NEW" && rm "$NEW.raw"

PREV=$(ls "$DIR"/*.json | grep -v "$NEW" | tail -1 || true)
[ -n "$PREV" ] && diff <(cat "$PREV") <(cat "$NEW") > "$DIR/last.diff" || true
Absence is not an alert

A domain missing from this month's index may have been dropped from our crawl, not removed by the linking site. Confirm the important ones by hand before you write to anyone. We do not claim a diff proves a link is gone.

What it costs (hypothetical portfolio)

Example: 20 client sites, one run per week, 4 runs a month. Prices from the per-call rates.
StepCredits per runRuns a monthCredits a month
refdomains for 20 sites404160
bulk_dr for all 20 together144
backlinks lookup on 3 flagged domains6424
Total188 credits, about $0.019

Edge cases

Do I need a Search Console export too?
Search Console shows links Google reports to you, a different list from ours. Use both if you can. Ours is useful because it needs no site verification, so you can watch client sites, vendors and competitors the same way with one script.
What if my domain has more than 1,000 referring domains?
Page through with page and per. Each call is billed once for up to 1,000 rows, and deep pagination is capped at 50,000 rows. A site with 5,000 referring domains takes five calls, ten credits, or $0.001.
Can I check old backlinks that were de-indexed?
We can only show what is in our own index at the last refresh. If a link was in last month's snapshot and is not in this one, treat it as a lead to verify, not a verdict. See the traffic runbook.