The documentation audit: a checklist for finding what's broken before your users do
Every six months, your docs accumulate broken links, outdated screenshots, and pages that answer questions nobody asks anymore. A systematic audit process to find and fix what's broken.
Your users are doing your documentation audit for you right now. Every time someone hits a 404, follows a code example that no longer works, or searches for something and gets zero results, they’ve found a failure in your docs — and they’re silently blaming your product for it.
The fix isn’t a rewrite. It’s a structured audit, done on a schedule, that catches the decay before it reaches production users. Here’s the exact process we use and recommend.
Why docs decay faster than you think
Documentation has a half-life. A page written six months ago is already aging. A page written two years ago is actively dangerous.
The forces that erode docs:
- Code changes without doc changes. Parameters get renamed, endpoints get deprecated, return shapes change. The code moves; the docs don’t.
- UI redesigns. Screenshots from the previous design system are now lies. The button isn’t there. The modal looks nothing like that.
- Feature evolution. The original feature was simple. Now it has three modes, an enterprise tier, and two gotchas. The original page covers none of it.
- Orphaned pages. Features get sunset. The docs stay. Users find them, try to use them, and wonder why nothing works.
A biannual audit — six months maximum between passes — is the minimum cadence to stay ahead of it.
The full audit checklist
Work through this list sequentially. Items near the top are cheap to run and high-yield. Items near the bottom are slower but catch the things automated tools can’t.
1. Run a broken link scan
❌ Manually clicking through to check links. ✅ Automated crawl with a dedicated tool.
# Using broken-link-checker (npm)
npx broken-link-checker https://docs.yoursite.com --recursive --ordered
# Using lychee (fast Rust CLI, handles auth headers)
lychee --recursive --no-progress "https://docs.yoursite.com"
Alternatively, run linkchecker as part of CI so broken links block deploys:
pip install linkchecker
linkchecker https://docs.yoursite.com --check-extern
Focus first on 4xx errors (page genuinely gone) before 5xx (might be transient). Every 404 in your own docs is a page you should either recreate or redirect.
2. Check internal cross-links against your actual sitemap
Broken links to external sites are embarrassing. Broken links to your own pages are worse — they signal that nobody is maintaining this.
# Extract all internal hrefs and check against your sitemap
curl -s https://docs.yoursite.com/sitemap.xml \
| grep -oP '(?<=<loc>)[^<]+' \
| sort > sitemap_urls.txt
# Then diff against what your crawler found as live pages
Every URL in your docs that isn’t in your sitemap needs either a redirect or a replacement link.
3. Audit code examples against your current codebase
❌ Assuming code examples still work because nobody complained. ✅ Mechanically verifying them against the live API.
The most common culprit: SDK method signatures that changed. The docs still say client.connect({ token: "..." }) but the current SDK expects client.init({ apiKey: "..." }).
# For repos using grep-based checks:
# Extract all code blocks from MDX/MD files and check identifiers against source
grep -r "client\." docs/ --include="*.mdx" | grep -v "node_modules"
# Then cross-reference with your actual SDK exports
grep -r "export function\|export const\|export class" src/ --include="*.ts"
Any function, method, or parameter name in your docs that doesn’t match what grep finds in your codebase is a candidate for an outdated example.
4. Check screenshot staleness
Screenshots have the shortest half-life of any docs content. They go stale the moment a designer changes a color, a button gets renamed, or a modal gets restructured.
The audit approach:
- Find every image in your docs:
find docs/ -name "*.png" -o -name "*.jpg" -o -name "*.gif" | sort - Check
git log --follow -- path/to/image.pngfor each one. If the last commit touching an image is older than the last major UI release, it’s stale. - Compare key screenshots against the live product. Start with the top 10 most-visited pages — screenshot staleness on a page nobody reads doesn’t matter.
❌ Updating screenshots manually and leaving the process ad hoc. ✅ Annotating screenshot files with a version tag in a comment or frontmatter field so you can query which ones were last updated before a given release.
If you use a component-based docs platform, consider replacing screenshots of your own UI with live embeds or code-driven renders. A screenshot can’t drift if it isn’t a screenshot.
5. Pull your search analytics for zero-result queries
Your site search is a direct line to what your users need but can’t find. Every zero-result query is a potential missing page.
# In Algolia:
# Dashboard → Analytics → No Results Queries → Export CSV
# In Elasticsearch / OpenSearch:
GET /search-logs/_search
{
"query": { "term": { "result_count": 0 } },
"aggs": { "top_queries": { "terms": { "field": "query.keyword", "size": 50 } } }
}
Sort zero-result queries by frequency. The top 10 are your highest-priority coverage gaps. For each one, ask:
- Does a page on this topic exist but have different terminology? If so, add synonyms to your search config or add the query term to the page content.
- Does no page exist? That’s a content gap — add it to the backlog with the query frequency as a priority signal.
❌ Ignoring search analytics because “users can just browse.” ✅ Reviewing zero-result queries monthly, actioning the top items on a quarterly basis.
6. Cross-reference your docs coverage against your actual feature set
Your codebase is the ground truth for what your product can do. Your docs should reflect all of it. The gap between them is coverage debt.
# For an API product — compare endpoint documentation against your router
# Example for an Express app:
grep -r "router\.\(get\|post\|put\|patch\|delete\)" src/ --include="*.ts" \
| grep -oP '(?<=router\.\w{2,6}\(')[^'\"]+'
# Compare that list against what's documented in docs/api/
ls docs/api/
For a UI product, the same logic applies to features: enumerate features from your code or product changelog and compare against your docs sitemap. Every feature that shipped more than a sprint ago and has no docs page is a gap.
7. Check page-level analytics for high-traffic pages with high exit rates
High exit rate on a high-traffic page means one of three things:
- Users found what they needed immediately (good).
- The page didn’t answer their question and they left (bad).
- The page was confusing and they gave up (bad).
Pull your top 20 pages by pageviews. For each one above 40% exit rate, do a manual read:
- Does the page answer the question implied by its title?
- Are there obvious gaps — “see the next step” with a broken link, or a code block with an error you can reproduce?
- Is the content still accurate given recent product changes?
❌ Treating high traffic as a signal of quality. ✅ Treating high traffic as a reason to prioritize accuracy — your busiest pages are where errors cause the most damage.
8. Scan for pages that reference deprecated or removed features
Products deprecate. Docs don’t always follow.
# Build a list of deprecated identifiers from your changelog or codebase
# Then search for them in your docs
cat deprecated_identifiers.txt | while read term; do
grep -rl "$term" docs/ --include="*.mdx" && echo "Found: $term"
done
Every hit is either a page that needs updating or a page that should be removed entirely. Leaving deprecated feature docs live without a clear deprecation notice is worse than removing them — users follow them and file support tickets wondering why they don’t work.
9. Audit your “Getting Started” path end-to-end
This one requires a human. Spin up a clean environment — no local config, no pre-installed dependencies — and follow your own Getting Started guide exactly as written. Note every step where:
- You had to infer something not written down.
- A command failed or produced unexpected output.
- A screenshot didn’t match what you saw.
- You finished a step but didn’t know how to proceed to the next.
This is the audit most teams skip because it feels slow. It’s also the one that catches the most severe issues. A broken Getting Started flow is actively harming every new user.
10. Review pages older than 12 months with no edits
# Find MDX files not touched in 12+ months
find docs/ -name "*.mdx" -not -newer "$(date -v-12m +%Y-%m-%d)" 2>/dev/null \
|| find docs/ -name "*.mdx" -not -newer "$(date -d '12 months ago' +%Y-%m-%d)"
Every page on that list is a candidate for review. Some will still be accurate — timeless conceptual content doesn’t need frequent updates. Others will be dangerously out of date. The git age alone doesn’t tell you which is which, but it tells you where to look.
What to do with the findings
A completed audit produces a list of issues. Don’t try to fix everything in one sprint. Triage by:
- Severity — broken Getting Started path outranks a stale screenshot on a rarely-visited page.
- Traffic — a broken link on your most-visited page is higher priority than the same issue on a page with 3 monthly views.
- Effort — quick wins (update a command, fix a link, remove a deprecated page) should ship before multi-day rewrites.
Build an audit board — a simple Notion table or GitHub Project works — with columns for Issue, Page URL, Severity (P1/P2/P3), Effort (hours), and Assignee. Work through it like a bug backlog.
The structural fix: prevent rot, don’t just clean it up
An audit catches what’s already broken. The structural problem is that documentation drift is continuous — the same decay you cleaned up this quarter will return next quarter unless something changes upstream.
Teams that keep docs clean long-term usually do two things differently:
- They wire docs changes into the code review process. The PR template has a docs section. The reviewer actually checks it. The merge gate doesn’t open without a docs update on any PR that changes a public interface.
- They use a platform that automates the sync. GitDocAI’s auto-sync watches your GitHub repo and proposes documentation updates whenever code changes — so instead of discovering six months later that your
/refundsendpoint grew areasonparameter with no docs, you get a pending change in your dashboard the day it merged.
The audit cadence drops from “every six months” to “monthly” when your platform is actively flagging drift in real time. The audit still matters — automated tools won’t catch every issue in this list — but it becomes cleanup work instead of damage control.
Running the audit on a schedule
The worst audit is the one that never happens because it isn’t scheduled. Put a recurring task on your engineering calendar:
- Monthly: pull search analytics, review zero-result queries, action top 5.
- Quarterly: run broken link scan, check screenshot staleness on top 20 pages.
- Biannually: full checklist above, including the manual Getting Started run-through.
Name someone responsible. Without an owner, the audit becomes a “someone should do this” item that lives in the backlog forever.
Your docs are either building trust with every user who reads them or quietly eroding it. There’s no neutral state — a page that used to be accurate and now isn’t is worse than no page at all, because it actively misleads.
Run the audit. Fix what’s broken. Then put something in place to reduce the rate of future drift. GitDocAI is built to handle the continuous sync side of that problem — connect your repo and the platform starts watching for drift immediately.