Check for broken links on a webpage
Scans a webpage for broken links and reports working vs broken URLs.
/plugin marketplace add DataflightSolutions/claude-plugins/plugin install playwright@dataflight-claude-pluginsScan a webpage for broken links. Tests all anchor tags with HTTP/HTTPS hrefs and reports working vs broken links.
Execute these steps in order. Stop and report errors if any step fails.
If user provided a URL argument, use it directly.
If no URL provided, detect running dev servers:
cd ${CLAUDE_PLUGIN_ROOT} && node -e "require('./lib/helpers').detectDevServers().then(s => console.log(JSON.stringify(s)))"
Decision tree:
Write a script to /tmp/playwright-check-links.js:
const { chromium } = require('playwright');
const TARGET_URL = '<detected-or-provided-url>';
(async () => {
console.log('Checking links on:', TARGET_URL);
console.log('');
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
try {
await page.goto(TARGET_URL, { waitUntil: 'networkidle', timeout: 30000 });
console.log('Page loaded:', await page.title());
console.log('');
// Get all links
const links = await page.locator('a[href]').all();
console.log(`Found ${links.length} links to check`);
console.log('');
const results = {
working: [],
broken: [],
skipped: []
};
for (const link of links) {
const href = await link.getAttribute('href');
const text = (await link.textContent())?.trim().slice(0, 50) || '[no text]';
// Skip non-HTTP links
if (!href || !href.startsWith('http')) {
results.skipped.push({ href, text, reason: 'not HTTP' });
continue;
}
try {
const response = await page.request.head(href, { timeout: 10000 });
const status = response.status();
if (response.ok()) {
results.working.push({ href, text, status });
console.log(`OK [${status}]: ${href}`);
} else {
results.broken.push({ href, text, status });
console.log(`BROKEN [${status}]: ${href}`);
}
} catch (e) {
results.broken.push({ href, text, error: e.message });
console.log(`ERROR: ${href} - ${e.message}`);
}
}
// Summary
console.log('');
console.log('=== SUMMARY ===');
console.log(`Working links: ${results.working.length}`);
console.log(`Broken links: ${results.broken.length}`);
console.log(`Skipped (non-HTTP): ${results.skipped.length}`);
if (results.broken.length > 0) {
console.log('');
console.log('=== BROKEN LINKS ===');
results.broken.forEach(link => {
console.log(` ${link.href}`);
console.log(` Status: ${link.status || link.error}`);
console.log(` Text: ${link.text}`);
});
}
} catch (error) {
console.error('Link check failed:', error.message);
process.exit(1);
} finally {
await browser.close();
}
})();
Replace <detected-or-provided-url> with the actual URL.
cd ${CLAUDE_PLUGIN_ROOT} && node run.js /tmp/playwright-check-links.js
After execution, provide a summary:
Example output:
Link Check Complete for: http://localhost:3847
Results:
- Working: 15 links
- Broken: 2 links
- Skipped: 3 links (non-HTTP)
Broken Links:
1. https://example.com/old-page
Status: 404
Link text: "Old Documentation"
2. https://api.service.com/health
Error: Connection refused
Link text: "API Status"
If the script fails:
User can optionally specify:
# anchors are checked against base URL