---
title: "Check the links you send people to · Agent Wranglers"
url: https://agentwranglers.se/playbook/website/redirects-and-canonicals/check-outbound-links
updated: 2026-10-21
licence: "All rights reserved"
---

# Check the links you send people to

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers). Updated 2026-10-21.

- Level: Recommended
- Chapter: [Redirects and canonicals](https://agentwranglers.se/playbook/website/redirects-and-canonicals)
- Rule: Every week, fetch every link that points to another site, and alert when one fails twice in a row.
- How: Read the links from the built site or its machine-readable index, not from a hand-kept list. Drop the `#` part and fetch each address once, a few at a time. Send a user agent that names the check. Some sites answer `HEAD` with an error, so use `GET` and cancel the body. Retry once before you count a failure, because many failures last only a minute. Replace a dead link with the new address of the same text, or remove it. Run the check outside the deploy, because another site's outage must never block a release.
- Check: Point one link at an address that answers 404. The next run alerts with that address.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### JavaScript example

```js
async function isLinkAlive(url, attempts = 2) {
  for (let attempt = 1; attempt <= attempts; attempt++) {
    const res = await fetch(url, { headers: { 'user-agent': 'example-link-check' }, signal: AbortSignal.timeout(20_000) }).catch(() => null);
    await res?.body?.cancel();
    if (res?.ok) return true;
  }
  return false;
}
```

### Python example

```python
import urllib.request

def is_link_alive(url: str, attempts: int = 2) -> bool:
    request = urllib.request.Request(url, headers={"User-Agent": "example-link-check"})
    for _ in range(attempts):
        try:
            with urllib.request.urlopen(request, timeout=20) as response:
                return 200 <= response.status < 300
        except Exception:
            continue
    return False
```

## Related rules

- [Watch cited sources in code](https://agentwranglers.se/playbook/engineering/documentation/watch-cited-sources) in Engineering
- [Link only to final addresses](https://agentwranglers.se/playbook/website/redirects-and-canonicals/final-addresses) in Website

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), which requires credit with a link. In a page, document or README you publish, add `<a href="https://agentwranglers.se/playbook/website/redirects-and-canonicals/check-outbound-links">Agent Wranglers website playbook</a>`. In code you write, add a comment next to it with the same link.

- Previous: [Watch for broken old links](https://agentwranglers.se/playbook/website/redirects-and-canonicals/watch-not-found)
- Next: [Say who made each redirect](https://agentwranglers.se/playbook/website/redirects-and-canonicals/redirect-by)
- [Redirects and canonicals](https://agentwranglers.se/playbook/website/redirects-and-canonicals)
