An internal link audit turns a large, difficult-to-review website into a practical list of URLs, destinations, status codes, anchor text, redirects, and coverage gaps. This checklist explains how to extract internal links at scale, identify broken and poorly connected paths, compare crawl data with known URLs to find orphan candidates, and prioritize fixes without losing the context behind each finding.
Overview
An internal link audit is more than a broken-link report. It is an analysis of how pages connect to one another and how reliably those connections resolve. A useful audit should answer questions such as:
- Which pages contain links that return client or server errors?
- Which links resolve through one or more redirects?
- Which destinations receive many links, and which receive very few?
- Are important pages linked with descriptive, consistent anchor text?
- Which known URLs are not discovered through the site’s internal navigation?
- Are duplicate URL forms splitting link signals or creating unnecessary crawl paths?
Start by defining the audit boundary. Record the primary hostname, whether subdomains are included, which protocols count as internal, and whether query parameters, fragments, language folders, and trailing slashes should be normalized. Also decide whether the crawl will inspect only the initial HTML response or render JavaScript. A simple HTML crawl is often faster and easier to reproduce; a rendered crawl may be necessary when navigation links are added by client-side code.
For each extracted link, preserve the source page and the original value before transforming it. A practical link-level data model includes:
- Source URL: the page containing the link.
- Raw href: the exact attribute value found in the document.
- Resolved URL: the absolute URL after resolving relative paths.
- Normalized destination: the comparison form used for grouping.
- Anchor text: visible text, including whether it is empty or image-based.
- HTTP result: status code, final URL, content type, and request error if applicable.
- Context: location such as navigation, main content, footer, or related-content block.
- Crawl metadata: crawl timestamp, depth, rendering mode, and parser version.
Keeping both raw and processed values makes the audit easier to debug. If a URL appears incorrect after normalization, you can return to the original markup instead of guessing what the crawler changed.
For implementation options, a scripted crawler can use ordinary HTTP requests and an HTML parser for mostly server-rendered sites. A browser automation tool is more appropriate when links appear only after scripts run, menus require interaction, or content is loaded dynamically. The same principles apply in Python, Node.js, or a no-code crawler: fetch responsibly, respect access controls, set clear limits, and retain enough metadata to reproduce findings. Related workflows are covered in this Python web scraping guide and the guide to scraping JavaScript-rendered websites with Playwright.
Checklist by scenario
1. Before crawling
- Define the hostname and URL patterns in scope.
- Choose whether to follow or exclude query strings, fragments, and files such as PDFs.
- Set a crawl rate, timeout, retry limit, and maximum page count.
- Record the user agent and crawl date so future runs can be compared.
- Prepare a seed list from the homepage, XML sitemaps, navigation, CMS exports, or other trusted URL inventories.
- Decide whether links in canonical elements, structured data, scripts, and feeds belong in separate datasets rather than the primary internal-link report.
If the project includes non-HTML assets, keep them distinguishable from pages. A PDF, image, or API endpoint may be a valid destination but should not be evaluated with the same content and navigation rules as an HTML document. For structured-data URLs, see the guide to extracting JSON-LD, Microdata, and RDFa.
2. Finding broken internal links
- Extract links from every crawled page and resolve them against the source page’s base URL.
- Separate internal destinations from external URLs, mail links, telephone links, fragments, and unsupported schemes.
- Request each unique destination once where possible, then associate the result with all source pages.
- Group failures by status code and request error.
- Open a sample of findings manually, especially when the server response conflicts with what a browser displays.
Use the status code as a diagnostic field rather than an automatic verdict. A 404 or 410 generally deserves review because the requested resource was not found or is no longer available. A 500-level response indicates a server-side failure and may be temporary. A 3xx response identifies a redirect and should be reviewed for unnecessary chains, outdated destinations, or links that could point directly to the final URL. Timeouts, DNS failures, TLS errors, and blocked requests should be reported separately from confirmed HTTP responses. The API response debugging guide provides a useful model for retaining headers, status details, and error context.
3. Auditing redirects and duplicate destinations
- Store both the requested URL and the final URL after following redirects.
- Count redirect hops and flag chains for review.
- Compare links pointing to different URL forms that resolve to the same destination.
- Group variations caused by protocol, hostname, case, trailing slashes, default files, and selected query parameters.
- Do not normalize away meaningful parameters without documenting the rule.
Duplicate destination analysis helps distinguish genuine duplicate links from harmless URL variations. Treat URL normalization as a project decision, not a universal formula. For example, a tracking parameter may be ignored for content grouping but retained in a separate field for analytics and implementation review.
4. Reviewing anchor text and link placement
- List anchor text by destination, source page, and page section.
- Flag empty anchors, generic labels such as “click here,” and image links without useful alternative text for manual review.
- Check whether the wording accurately describes the destination.
- Compare navigation links with contextual links in the main content rather than treating every link as equivalent.
- Look for important pages that have many links from boilerplate areas but few relevant contextual references.
Anchor-text analysis should support editorial decisions, not encourage repetitive wording. The goal is clarity for people and a dependable description of the destination.
5. Running an orphan page audit
A crawler can find pages reachable from its seed URLs; it cannot prove that every existing page has been discovered. To identify orphan candidates, compare the crawl’s discovered URL set with additional inventories such as XML sitemaps, a CMS export, analytics landing-page data, server logs, or a manually maintained content list. A URL present in an inventory but absent from the crawl is a candidate for investigation, not automatically an orphan.
- Normalize the inventories using the same documented rules.
- Match URLs while preserving the original spelling and source inventory.
- Check whether the missing URL is intentionally excluded, redirected, blocked, unpublished, or accessible only after a form or application state.
- For valid pages, add a relevant internal path from an existing page, hub, category, or navigation element.
- Re-crawl after changes and confirm that the page is now discoverable through the intended route.
What to double-check
Before publishing an audit report, validate the crawler and the interpretation of its output.
| Area | Check | Why it matters |
|---|---|---|
| URL resolution | Resolve relative, root-relative, protocol-relative, and base-tag URLs correctly. | A parsing error can create false broken links or miss valid destinations. |
| Fragments | Store fragments separately and avoid treating every fragment variation as a new page. | Fragments usually identify a location within a document rather than a separate resource. |
| Redirects | Record every hop, the final URL, and any request limit reached. | A final success can conceal an avoidable chain or an incomplete crawl. |
| Rendering | Compare raw HTML and rendered output when navigation is script-generated. | Different collection modes can produce different link inventories. |
| Access errors | Separate blocked, timed-out, and failed requests from confirmed status codes. | Uncertainty should not be labeled as a broken page. |
| Scope | Check subdomains, alternate protocols, staging hosts, and redirected hostnames. | Scope mistakes can inflate the report or hide relevant links. |
Export at least two views: a row-level link file for investigation and a destination summary for prioritization. Recommended fields include source URL, destination URL, raw href, anchor text, status code, final URL, redirect hops, content type, crawl depth, link location, and error message. A clean, normalized pipeline makes recurring audits more reliable; the web scraping data pipeline guide covers comparable principles for validation and storage.
Common mistakes
- Calling every 3xx link broken: redirects need review, but they are not the same as unavailable resources.
- Using only the homepage as a seed: disconnected sections and orphan candidates may never enter the crawl.
- Confusing a crawl gap with an orphan: a page may be missing because of scope, rendering, access, or normalization rules.
- Discarding raw href values: without the original value, it is harder to diagnose malformed markup or parser behavior.
- Counting links without grouping destinations: URL variants can make one destination appear to be several.
- Ignoring page context: a footer link and a relevant in-content recommendation serve different navigation purposes.
- Retrying indefinitely: uncontrolled retries distort results and place unnecessary load on the site.
- Fixing links without a second crawl: an implementation change is not complete until the intended path is verified.
When to revisit
Run a focused internal link audit after a migration, redesign, URL-structure change, navigation update, or large content release. It is also useful before seasonal planning cycles, when a new content hub is launched, or when internal-link reports show declining coverage or unexpected error growth.
For recurring audits, preserve the same export fields and normalization rules so results can be compared over time. Review the crawler when workflows or tools change, especially after moving from raw HTML collection to browser rendering or changing redirect and parameter handling. Recheck the site’s URL inventory when sitemaps, CMS systems, analytics collection, or publishing processes change.
A practical closing checklist is:
- Confirm the crawl scope and seed sources.
- Run the crawl and save raw results.
- Resolve and normalize URLs with documented rules.
- Group broken responses, redirects, duplicate destinations, and access errors.
- Review anchor text and link location for priority pages.
- Compare discovered URLs with independent inventories for orphan candidates.
- Fix the highest-value issues and record the change.
- Re-crawl the affected paths and archive the updated report.
Used this way, an internal link audit becomes a repeatable technical SEO and web data workflow rather than a one-time list of errors. The process reveals not only what is failing, but also how people and crawlers move through the site and where the navigation structure needs clearer connections.