Find dead links in your static site and point readers to archived copies.
Linkguard is a free GitHub Action. It checks the outbound links in a Jekyll, Hugo or folderblog repo and looks up Internet Archive Wayback Machine snapshots for links that no longer work. If you turn it on, it opens a pull request that swaps dead links for their archived copies.
Report-only by default. No account needed for lookups. No telemetry, and no Linkguard server.
Quick start
Save this as .github/workflows/linkguard.yml:
name: Linkguard
on:
schedule:
- cron: '17 6 * * 1' # weekly
workflow_dispatch:
permissions:
contents: read
jobs:
links:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: ninepointlabs/linkguard@v0.1.0
Results appear in the run's job summary, as warning annotations on the source lines of dead links, and as JSON and markdown report files. The repo has complete examples for Jekyll, Hugo and folderblog.
What it does
- Finds your content. Detects Jekyll, Hugo or folderblog from the repo layout, or you pass
site-typeor your ownpaths. - Extracts outbound links from markdown and HTML, skipping code blocks, comments, relative links and private addresses.
- Checks each link with retries, polite rate limits (one request per host at a time) and redirect following. Each link comes back as
ok,moved,deadorblocked. Bot-protected pages are reported as blocked, not dead. - Looks up Wayback snapshots for every checked link. Only 2xx captures count.
- Optionally opens a pull request (
open-pr: true) that replaces each dead link with itsweb.archive.orgcopy. It never pushes to your default branch.
Lookup-only mode vs snapshot mode
Lookup-only (default)
No secrets needed. Linkguard checks links and looks up existing Wayback snapshots. Dead links with a snapshot get an archived URL in the report. Nothing new is captured.
Snapshot mode
Add your own free Internet Archive S3-style keys as repository secrets. Linkguard then also asks Save Page Now to capture working links that have no recent snapshot, so a copy exists before they die. Captures count against your own account and are slow: a first run over 100 links can take 15 minutes or more.
- uses: ninepointlabs/linkguard@v0.1.0
with:
wayback-access-key: ${{ secrets.WAYBACK_ACCESS_KEY }}
wayback-secret-key: ${{ secrets.WAYBACK_SECRET_KEY }}
Free for up to 100 links per run
Each run checks the first 100 unique links, in file order. Anything beyond that is skipped, and the log says how many. You can lower the cap with max-links, but you can't raise it.
Honest limits
- A check is one request from a GitHub-hosted runner. Sites that block data-centre IPs or bots show up as
blocked, and a page can be up for people but down for the runner, or the other way round. - A link marked
deadafter retries can still be a temporary outage. Read the report before you merge a pull request. - The Internet Archive doesn't publish its rate limits. Lookups and captures can fail, and the availability API sometimes reports no snapshot for a page that has one.
- If the closest snapshot isn't a 2xx capture, the link is treated as having no usable snapshot, even when an older good one exists.
- Link extraction uses patterns, not a full parser. Unusual syntax can be missed, and templated links (Hugo shortcodes, Liquid variables) aren't resolved.
- Each scheduled run that finds replaceable dead links opens a new pull request. Merge or close the previous one.
Data and privacy
Data leaves the runner only as requests to the link targets themselves, link URLs sent to archive.org (never file contents), and GitHub API calls when open-pr is on. This page has no external fonts. This site uses a cookie-free, self-hosted GoatCounter that records page views without personal data.
Read more
Every input, output and setting is documented in the README. Source, issues and releases are on GitHub. MIT licensed.