GitHub Packages · MIT · Node ≥ 18

orphan-beacon

Find the pages in your built static site that nothing links to, and measure how many clicks every page is from the homepage.

Find orphan pages in your built static site and measure click depth from the homepage: pages with no internal inbound links, unreachable clusters, nofollow-only or noindex-only links, pages too deep, dead ends. Text/JSON/SARIF/Markdown, allowlist with expiry, GitHub Action. Zero deps.

  1. 1 Point the @mrlouiswright scope at GitHub Packages in .npmrc

    @mrlouiswright:registry=https://npm.pkg.github.com
  2. 2 Install

    npm i -D @mrlouiswright/orphan-beacon
Installing from GitHub Packages needs a token

Published to GitHub Packages, not npmjs.com. GitHub Packages needs a GitHub token with read:packages to install, even for public packages: add //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN} to .npmrc or run npm login --registry=https://npm.pkg.github.com.

~/project — zsh
$ npx orphan-beacon test/fixtures/badorphan-beacon — /workspace/orphan-beacon/test/fixtures/bad13 page(s); 2 orphan(s); deepest page 5 click(s) from / HIGH     island-a.html /island-a.html cannot be reached from / (linked only from /island-b.html) [orphan-unreachable]         ↳ fix: Connect this cluster of pages to the main navigation or a hub page.HIGH     island-b.html /island-b.html cannot be reached from / (linked only from /island-a.html) [orphan-unreachable]         ↳ fix: Connect this cluster of pages to the main navigation or a hub page.HIGH     orphan.html /orphan.html has no internal links pointing to it [orphan-page]         ↳ fix: Link to it from a relevant page, hub or navigation, or noindex/remove it if it should not be found.MEDIUM   d.html /d.html is 4 clicks from / (max 3) [orphan-too-deep]         ↳ fix: Link to it from a higher-level page (category hub, related posts, footer).MEDIUM   dead.html /dead.html is 5 clicks from / (max 3) [orphan-too-deep]
Sample output from the orphan-beacon README.

Why it exists

Search engines discover and weigh pages through internal links. A page that only exists in the sitemap, a blog series that only links to itself, or a product buried six clicks deep gets crawled rarely and ranks poorly. orphan-beacon builds the internal link graph from your built HTML, walks it from the homepage like a crawler, and reports orphans, unreachable clusters and deep pages with the file, severity and a concrete fix.

CLI, library and GitHub Action. Node.js 18+, zero runtime dependencies. Works on any static build output (Astro, Next.js “output: 'export'”, Eleventy, Hugo, Jekyll, Docusaurus, VitePress, plain HTML) and runs offline: point it at the folder your build writes. By Louis Wright.

Features

Orphans

indexable pages with no internal inbound links (noindex pages and pages canonicalised elsewhere are skipped).

Reachability

pages that are linked, but only from a cluster that the homepage cannot reach; pages linked only with rel=nofollow/ugc/sponsored; pages linked only from noindex pages; pages only reachable via javascript:/onclick navigation.

Click depth

breadth-first shortest path from the homepage (or --start) following crawlable links; pages deeper than --max-depth (default 3).

Link equity hints

pages with a single inbound link (info) and dead-end pages with no outgoing internal links.

Usage

# Example

 npx orphan-beacon dist

# Example

 npx orphan-beacon dist --max-depth 4 --fail-on medium

# Example

 npx orphan-beacon public --ignore "/landing/**,/campaign-*"

# Example

 npx orphan-beacon out --clean-urls --format json > link-graph.json

CI / GitHub Action

permissions:
  contents: read
  security-events: write   # only needed for the SARIF upload
jobs:
  orphan-beacon:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
        with: { persist-credentials: false }
      - run: npm ci && npm run build   # produce the static site first
      - uses: MrLouisWright/orphan-beacon@v1
        with:
          path: dist
          fail-on: high
          sarif: orphan-beacon.sarif
      - uses: github/codeql-action/upload-sarif@v3
        if: always()
        with: { sarif_file: orphan-beacon.sarif }

Options & flags

FlagDescription
Site
--base-url <url>Public URL of the site, e.g. https://example.com (default: inferred from canonical/og:url)
--include <globs>Only check these pages (file or URL path globs, comma-separated)
--exclude <globs>Skip these pages
--clean-urlsPages are served without .html (about.html -> /about)
Checks
--max-depth <n>Report pages more than n clicks from the homepage (default 3)
--start <path>Entry page for click depth (default /)
--ignore <globs>Pages that are fine without inbound links (landing pages, campaign pages)
--no-single-linkDo not report pages with only one inbound link
Common
-c, --config <file>JSON config (default: .orphan-beacon.json or "orphanBeacon" in package.json)
-f, --format <fmt>text (default) | json | sarif | markdown
--json <file>Also write a JSON report
--sarif <file>Also write SARIF 2.1.0
--markdown <file>Also write Markdown (e.g. for a job summary)
--fail-on <sev>critical | high | medium | low | info | none (default: high)
--list-rulesPrint rules and default severities
--no-fixesHide fix suggestions in text output
--no-colorDisable colours

Full reference, config file format and API in the README.

Support this project

Support open-source security tools

I build free, open-source tools that help developers ship safer websites. Every coffee helps keep them maintained, documented and free for everyone.

Buy me a coffee (opens Stripe in a new tab)

Secure checkout by Stripe

Portrait of Louis Wright

About the author

Louis Wright

Cyber security researcher and software engineer based in the UK.

More tools by Louis Wright

58 tools

Sentinels security scanners & CI gates · 20