How to fix broken outbound links
Your audit came back with a heading that says outbound links are broken and a list of other people's URLs underneath it. The site is old, the list is long, and the advice attached to it is to update or remove every one. Before you spend an afternoon on that, the question worth asking is not how many there are. It is how many of those rows are a statement about somebody else's page, and how many are a statement about our crawler.
The limits first. Docket checks a capped sample of your outbound links, not all of them, and asks each one once. It records a status number and nothing else. And it will not pretend to be a browser to get a friendlier answer out of a host that dislikes crawlers.
The report already splits the list. Read the split first
The check is registered as "Broken outbound links", which is narrower than what it does. One function reads the sampled links and emits findings under several ids, at two severities, because they are not the same problem and do not have the same fix:
| Finding | Severity | What it means |
|---|---|---|
links.broken_external | LOW | The request finished and the answer was a failure that is not a refusal. The only one that accuses somebody else's page of being gone. |
links.unverified_external | NOTICE | The host declined to answer an automated request. Reported as a fact about the crawl. |
links.broken_own_subdomain | LOW | The dead host is one of yours — not an outbound link, but a service of yours that is down or gone. |
links.doubled_scheme | LOW | The href carries the scheme twice, so the host is the word "https". A typo, not a destination that moved. |
If your report shows the second row, that part of the list needs no work from you. Its own fix text says so: "Open a couple in a browser if you want certainty; nothing here needs fixing on the strength of this check." It carries a tool-limit flag that keeps it out of the score projection and out of your task list, and its impact is zero. It exists to name what Docket could not find out, not to give you a job.
What Docket counts as broken
The crawler collects the http and https anchors that point off
your site, takes a capped sample of the ones it met first, and asks each with a
HEAD request. Any answer that is not a success is then confirmed with a
GET before it counts. That second request exists because the first one lies:
plenty of servers, and most firewalls, answer HEAD with a failure while
GET is fine. Google's own support domain did exactly that — 404 to
HEAD, 200 to GET — and articles on this site link to it,
so every one of those links was once reported to us as dead.
After that confirmation, a link is called broken when its status is 400 or
above, or zero, and it is not on the refusal list below. The wording is the source's:
"Checked … of the site's outbound links (a sample — not every outbound link on the site)
and … failed", with the fix "Update or remove each dead link. If the destination
moved, link to its new home."
A refusal is not a defect
Stated flatly, because it is the centre of this page: a site that refuses an automated request is not a dead site. A status code in the client-error range describes what happened to this request. It is not a property of the resource.
RFC 9110 (June 2022, read 15 September 2026) is explicit about
several of them. 403 means the server "understood the request but refuses to
fulfill it" (section 15.5.4). 400 is for "something that is perceived to be a client
error" (section 15.5.1) — a rejection of the request, saying nothing about whether the page exists.
402 is "reserved for future use" (section 15.5.3), which is about as far from "this page
is gone" as a status code gets. 429 is not in that document at all; it is
RFC 6585 (April 2012, read 15 September 2026), section 4, and it means
the client "has sent too many requests in a given amount of time". The full refusal list for a
third-party host is 400, 401, 402, 403,
405, 406, 429, 451 and 503.
Every one of them goes to the unverified finding, with an example.
Two details in that rule are not obvious from the outside. 400 and
402 count as refusals only for third-party links: the same list is read
by the checks that look at your own server, and there a 400 about your own URL is
your defect and keeps reporting as one. And a status outside the range the protocol defines is
treated as a refusal too. RFC 9110 says all valid status codes lie between 100
and 599, and that implementations "often use three-digit integer values outside of
that range" for their own purposes. A large professional network answers with such a code, and
the control probes recorded in the check's source on 3 September 2026 show one of its pages
answering that code to a browser as well — which settles that the number describes the request,
not the page.
That is deliberately more cautious than the specification's own advice, which tells a client receiving an invalid status code to process the response as if it were a server error. Doing that would put every one of those links in your broken list.
The things that leave the list entirely
Some links are not moved to the unverified finding but dropped from the count altogether, because they are not outbound links in the first place.
- Share buttons. A tweet or share widget points at your own page,
wrapped in someone else's intent URL. The bare share endpoints — no parameters, unquestionably
live, the ones every share button on the web points at — answer
404to our fetcher and200to a browser, measured with control probes on 3 September 2026 and recorded in the check's source. On one crawled site, most of the reported broken outbound links were a single share widget repeated on every page. You can neither fix that host's answer nor drop the button without dropping sharing, so the widget is excluded rather than reported. - Share images. The
og:imagea page declares is fetched in the same pass, because it is the same kind of request, and read separately — a dead share image is a different defect with different advice. - Your own subdomains. A link to a host of yours is not outbound. If it is dead it is still reported, under a title that says what it actually is.
- A scheme written twice. An href carrying the protocol twice resolves to a URL whose host is the word "https". No such host exists, so it fails the way a dead destination does — and the old advice, to find where the page had moved, sent readers hunting for a file that had never moved. It reports as a typo now, with the address the href meant.
That share list is maintained by hand, host by host and path by path, so a widget nobody has added to it still lands in your broken list. The exclusions cover the cases that have been measured, not the case nobody has met yet.
What the check cannot tell you
- It is a sample, and not a random one. It is the outbound links the crawler met first, up to a cap, deduplicated. If your site asks crawlers to go slowly, the sample shrinks again to whatever the remaining time budget affords. The finding prints the number it checked and calls it a sample, which is the number to read it against.
- Only the status number survives. A timeout, a DNS failure, a TLS failure or a host that closed the connection all arrive at this check as zero, and zero counts as broken. The fetcher can tell a deliberately closed connection from a broken network, and the checks that read your own pages use that — this one never sees it, because what is stored per outbound link is an integer.
- It asks once. A host having a bad minute is a dead link in your report.
- It reads the HTML it was served. Links a script writes into the page afterwards are not in the sample: the crawler's browser pass exists for finding internal pages and keeps only the internal links it sees.
- It will not pose as a browser. Spoofing one would get a different answer from the one the site really serves an automated client, which is a different kind of lie.
- A redirecting link is not in the list. The fetcher walks the redirect chain and records the status at the end of it, so an outbound link that still redirects to a live page answers as a success and never appears here. Redirects on your own site are a separate job, with a separate page about the findings that report them.
So does a dead outbound link cost you anything?
Docket says the modest thing, at LOW severity: "Dead outbound links are a small quality signal and a direct annoyance for visitors." That is the whole claim, and the second half of it is the real one. Somebody reading your page clicked a reference you offered and got nothing.
You will read elsewhere that a broken outbound link leaks, wastes or bleeds authority out of the page. We can point to no primary documentation for that claim, so this page does not make it. An unsourced mechanism is not a reason to do anything; a reader hitting a dead reference is.
What to do with the list you have
Work the accusatory finding only, and open a handful of its URLs in a browser first — a minute's work that tells you whether the rows are real. Where the destination moved, link to where it went. Where it is gone for good, replace the reference or remove it; a sentence that cited something should either cite something else or stop citing. Leave the unverified list alone: those hosts declined to talk to an automated client, which large platforms do routinely, and the pages are very probably fine.
Own-subdomain breakages are a different afternoon — that is your service, down or retired, and the fix is at the host rather than in your copy. A doubled scheme is a moment's edit: delete the duplicate protocol, then confirm the repaired address loads, because Docket has not requested it. Every check Docket ships is listed in what Docket checks.
Common questions
Is a 403 or 429 a broken link?
No. A 403 means the server understood the request and refused it, and a 429 means it thinks you are asking too often. Neither says the page is missing. Docket files 401, 403, 405, 406, 429, 451 and 503 — and 400 and 402 when the host is not yours — under links.unverified_external at NOTICE, with a note that they were neither reported as broken nor counted as working.
Why does my report list a link that works fine in my browser?
Because the host answered our crawler differently from the way it answers you. That is common on large social platforms, which refuse automated requests as policy. If the row is in the unverified finding, that is exactly what it is telling you. If it is in the broken finding, open it: Docket confirms every failed HEAD with a GET before counting it, but it still only asked once.
Does Docket check every outbound link on my site?
No. It checks a capped sample of the outbound links the crawler met first, and the sample shrinks further if your site asks crawlers to slow down. The finding prints how many it checked and calls it a sample in its own text.
Do broken outbound links lose me PageRank?
This page does not make that claim, because we can point to no primary documentation for it. Docket reports dead outbound links at LOW severity and describes them as a small quality signal and a direct annoyance for visitors. The visitor is the reason to fix them.
What does a status code of zero mean in a link check?
It is Docket's own marker for a request that never completed — a timeout, a DNS failure, a TLS failure, or a connection the host closed. Those count as broken, because a connection that never completes is a statement about reachability. It is also the one place where a refusal can land in the broken list, so a row with no status is worth opening by hand.