SkillAgentSearch skills...

Linkinator

Broken link checker that crawls websites and validates links. Find broken links, dead links, and invalid URLs in websites, documentation, and local files. Perfect for SEO audits and CI/CD.

Install / Use

/learn @JustinBeckwith/Linkinator

README

🐿 linkinator - Broken Link Checker

A super simple site crawler and broken link checker for websites, documentation, and local files.

linkinator

npm version codecov Checked with Biome semantic-release

Linkinator is a powerful broken link checker that crawls websites and validates all links automatically. Whether you're checking a live website, local HTML files, or markdown documentation, this link checker tool will find broken links, dead links, and invalid URLs quickly and efficiently.

This link validator is perfect for SEO audits, quality assurance, continuous integration, and maintaining healthy websites. The linkinator broken link checker provides both an API and CLI for crawling websites and validating links. It's got a ton of sweet features:

  • 🔥 Easily perform scans on remote sites or local files
  • 🔥 Scan any element that includes links, not just <a href>
  • 🔥 Supports redirects, absolute links, relative links, all the things
  • 🔥 Configure specific regex patterns to skip
  • 🔥 Scan markdown files without transpilation

Installation

Node.js / npm

npm install linkinator

Standalone Binaries (no Node.js required)

Don't have Node.js installed? No problem! Browse all releases at github.com/JustinBeckwith/linkinator/releases.

These binaries are completely standalone - no runtime dependencies needed. Just download, make executable (Linux/macOS), and run!

Docker Usage

Run linkinator using Docker with the same commands as the CLI. The image is available on GitHub Container Registry at ghcr.io/justinbeckwith/linkinator.

Basic Usage:

docker run ghcr.io/justinbeckwith/linkinator LOCATION [ --arguments ]

For reproducible builds, pin to a specific version:

docker run ghcr.io/justinbeckwith/linkinator:3.4.0 LOCATION [ --arguments ]

Examples: Check a live website:

docker run ghcr.io/justinbeckwith/linkinator https://jbeckwith.com

Check local files in your current directory (mount your directory as a volume):

docker run -v "$(pwd)":/usr/src/app -w /usr/src/app ghcr.io/justinbeckwith/linkinator . --recurse

This command mounts your current directory ($(pwd)) to /usr/src/app inside the container and sets it as the working directory. Then, linkinator scans the . directory within the container, recursively.

Command Usage

You can use this as a library, or as a CLI. Let's see the CLI!

$ linkinator LOCATIONS [ --arguments ]

  Positional arguments

    LOCATIONS
      Required. Either the URLs or the paths on disk to check for broken links.
      Supports multiple paths, and globs.

  Flags

    --concurrency
          The number of connections to make simultaneously. Defaults to 100.

    --config
        Path to the config file to use. Looks for `linkinator.config.json` by default.

    --directory-listing
        Include an automatic directory index file when linking to a directory.
        Defaults to 'false'.

    --clean-urls
        Enable clean URLs (extensionless links). When enabled, links like '/about'
        will automatically resolve to '/about.html' if the file exists.
        Mimics behavior of modern static hosting platforms like Vercel.
        Defaults to 'false'.

    --format, -f
        Return the data in CSV or JSON format.
    
    --header, -h
      List of additional headers to be include in the request. use key:value notation.
        
    --help
        Show this command.

    --markdown
        Automatically parse and scan markdown if scanning from a location on disk.

    --recurse, -r
        Recursively follow links on the same root domain.

    --check-css
        Extract and check URLs found in CSS properties (inline styles, <style> tags, and external CSS files).
        This includes url() functions, @import statements, and other CSS URL references.
        Defaults to false.

    --check-fragments
        Validate fragment identifiers (URL anchors like #section-name) exist on the target HTML page.
        Invalid fragments will be marked as broken. Only checks server-rendered HTML (not JavaScript-added fragments).
        Defaults to false.

    --redirects
        Control how redirects are handled. Options are 'allow' (default, follows redirects),
        'warn' (follows but emits warnings), or 'error' (treats redirects as broken).

    --require-https
        Enforce HTTPS links. Options are 'off' (default, accepts both HTTP and HTTPS),
        'warn' (accepts both but emits warnings for HTTP), or 'error' (treats HTTP links as broken).

    --allow-insecure-certs
        Allow invalid or self-signed SSL certificates. Useful for local development with
        untrusted certificates. Defaults to false.

    --retry,
        Automatically retry requests that return HTTP 429 responses and include
        a 'retry-after' header. Defaults to false.

    --retry-errors,
        Automatically retry requests that return 5xx or unknown response.

    --retry-errors-count,
        How many times should an error be retried?

    --retry-errors-jitter,
        Random jitter applied to error retry.

    --server-root
        When scanning a locally directory, customize the location on disk
        where the server is started.  Defaults to the path passed in [LOCATION].

    --skip, -s
        List of urls in regexy form to not include in the check. Can be repeated multiple times.

    --status-code
        Control how specific HTTP status codes are handled. Format: "CODE:ACTION"
        where CODE is a numeric status code (e.g., 403) or pattern (e.g., 4xx, 5xx)
        and ACTION is one of: ok (success), warn (success with warning),
        skip (ignore link), or error (force failure).
        Can be repeated multiple times. Example: --status-code "403:warn" --status-code "5xx:skip"

    --timeout
        Request timeout in ms.  Defaults to 0 (no timeout).

    --url-rewrite-search
        Pattern to search for in urls.  Must be used with --url-rewrite-replace.

    --url-rewrite-replace
        Expression used to replace search content.  Must be used with --url-rewrite-search.
        Example: --url-rewrite-search "https://example\.com" --url-rewrite-replace "http://localhost:3000"

    --user-agent
        The user agent passed in all HTTP requests. Defaults to 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36'

    --verbosity
        Override the default verbosity for this command. Available options are
        'debug', 'info', 'warning', 'error', and 'none'.  Defaults to 'warning'.

Command Examples

You can run a shallow scan of a website for busted links:

npx linkinator https://jbeckwith.com

That was fun. What about local files? The linkinator will stand up a static web server for yinz:

npx linkinator ./docs

But that only gets the top level of links. Lets go deeper and do a full recursive scan!

npx linkinator ./docs --recurse

Aw, snap. I didn't want that to check those links. Let's skip em:

npx linkinator ./docs --skip www.googleapis.com

Need to skip multiple patterns? Just use --skip multiple times:

npx linkinator ./docs --skip www.googleapis.com --skip example.com --skip github.com

The --skip parameter will accept any regex! You can do more complex matching, or even tell it to only scan links with a given domain:

npx linkinator http://jbeckwith.com --skip '^(?!http://jbeckwith.com)'

Maybe you're going to pipe the output to another program. Use the --format option to get JSON or CSV!

npx linkinator ./docs --format CSV

Let's make sure the README.md in our repo doesn't have any busted links:

npx linkinator ./README.md --markdown

You know what, we better check all of the markdown files!

npx linkinator "**/*.md" --markdown

Need to check a static site with clean URLs (extensionless links)?

npx linkinator ./dist --recurse --clean-urls

🌰 Strict Link Checking

Like a diligent squirrel inspecting every acorn before storing it for winter, you can configure linkinator to be extremely picky about your links. Here's how to go full squirrel:

npx linkinator . --recurse --check-css --check-fragments --redirects error --require-https error
  • Scurries through your entire site recursively
  • Sniffs out broken fragment identifiers (like #section-name)
  • Gets angry at any redirects (a suspicious acorn is a bad acorn!)
  • Only accepts HTTPS acorns (HTTP is a rotten nut!)

Configuration file

You can pass options directly to the linkinator CLI, or you can define a config file. By default, linkinator will look for a linkinator.config.json file in the current working directory.

All options are optional. It should look like this:

{
  "concurrency": 100,
  "config": "string",
  "recurse": true,
  "skip": "www.googleapis.com",
  "format": "json",
  "silent": true,
  "verbosity": "error",
  "timeout": 0,
  "markdown": true,
  "checkCss": true,
  "checkFragments": true,
  "serverRoot": "./",
  "directoryListing": true,
  "cleanUrls": true,
  "redirects": "allow",
  "requireHttps": "off",
  "allowInsecureCerts": false,
  "retry": true,
  "retryErrors": true,
  "retryErrorsCount": 3,
  "retryErrorsJitter": 5,
  "urlRewriteSearch": "https://example

Related Skills

View on GitHub
GitHub Stars1.2k
CategoryDevelopment
Updated1d ago
Forks99

Languages

TypeScript

Security Score

100/100

Audited on Mar 27, 2026

No findings