
Dead Link Checker That Avoids False Positives
How it works
Link & Session Checker is for the case where your link checker says everything is fine (or everything is dead) and you do not trust it. It reads what you observed and sorts each link or saved session into ALIVE, DEAD or UNDETERMINED with the reason.
Phase 1 — Evidence. Status, key headers and a body snippet for each URL; names, flags and dates (never values) for saved sessions.
Phase 2 — Classify. SPA that answers 200 for any path, 403/429/challenge pages as UNDETERMINED, login redirects, soft 404s, HEAD vs GET differences.
Phase 3 — Probes. Safe curl or Playwright snippets with decision rules, including an authenticated request to a logged-in-only page for sessions.
Phase 4 — Table. Verdict, evidence, confidence and next step per item, with pacing guidance so you do not hammer a site.
Sample output
Real, unedited output from running this Skill on a sample problem:
## Evidence
Marker means the text a healthy page must show. Only item 1 came with one ("Add to cart"). No marker was given for items 5, 6, A or B.
| Item | Observed |
|---|---|
| 1 | 200, 1412 bytes, empty `<div id="root">`. The invented path `/products/zzzz-nothing` returned the identical 1412 bytes. |
| 2 | 403, `server: cloudflare`, `cf-mitigated: challenge`, title "Just a moment..." |
| 3 | 302 to `/login?next=/reports/q3`, on a link meant to be public |
| 4 | 404, body "Page not found" |
| 5 | 200, 48210 bytes, own title, h1 "Tomato Soup", "Prep 15 min", "Print recipe" |
| 6 | 200, 9020 bytes, generic title "Example Board", body "Sorry, this topic is no longer available" |
| A | `sid` is a session cookie with no expires. `_trk` (2027-09-01) looks like a tracking cookie. Last verified 2026-10-01. Logged-in-only page: `/account/orders`. |
| B | `auth_token` expires 2026-10-10 (claimed, now past). `refresh` expires 2027-01-15. Last verified 2026-09-20. Never tested after 10-10. |
## Verdicts
| Item | Verdict | Evidence | Confidence | Next step |
|---|---|---|---|---|
| 1 blue-lamp | UNDETERMINED | 200, same shell as a fake path, no marker visible | unconfirmed | Render and look for "Add to cart" (Probe 1) |
| 2 2024-recap | UNDETERMINED (blocked, not dead) | 403, `cf-mitigated: challenge` | confirmed block | Open it in your own browser. Do not retry. |
| 3 reports/q3 | UNDETERMINED (gated or moved) | 302 to /login, no session sent | unconfirmed | Open it in a private window. If it asks for login, the sharing setting changed. |
| 4 old-setup | DEAD | Real 404 with a not-found body | confirmed | Replace or remove the link |
| 5 soup/tomato | ALIVE | 200, page-specific h1 and recipe content, distinct title | likely (no marker supplied) | None. Give a marker such as "Prep 15 min" to make this confirmed. |
| 6 t/12345 | DEAD | Soft 404: 200, generic title, explicit "no longer available" | likely (no marker supplied) | Replace or remove the link |
| A shop session | UNDETERMINED | Last verified 2026-10-01, never probed since. The cookie date proves nothing. | unconfirmed | Probe 2 |
| B portal session | UNDETERMINED | `auth_token` date passed (claimed). `refresh` may still renew the login. | unconfirmed | Probe 3 |
## Probes to run
**Probe 1, item 1 (the control test was already done; render it):**
```js
// node probe.js 'https://app.example-shop.test/products/blue-lamp' 'Add to cart'
const { chromium } = require('playwright');
(async () => {
const b = await chromium.launch(); const p = await b.newPage();
const r = await p.goto(process.argv[2], { waitUntil: 'networkidle', timeout: 30000 });
const text = await p.locator('body').innerText();
console.log(JSON.stringify({ status: r && r.status(), url: p.url(), title: await p.title(),
marker: text.includes(process.argv[3]), head: text.slice(0, 200) }));
await b.close();
})();
Marker true is ALIVE. Marker false with explicit not-found text is DEAD. A challenge page is UNDETERMINED.
Probe 2, session A:
curl -sS -L --max-time 20 --max-redirs 3 -b 'shop-session.txt' -c 'shop-session.txt' -o /tmp/me.html \
-w 'status=%{http_code} final=%{url_effective}\n' 'https://<shop-host>/account/orders'
grep -c -i '<logged-in-only-marker>' /tmp/me.html
Replace <shop-host> with your real host. Pick a marker that only a logged-in user sees, such as a logout link or an order heading. "Log in" is not usable because footers show it to everyone.
Probe 3, session B: use the same command with portal-cookies.txt and a logged-in-only portal URL (<logged-in-only-url>, not given). curl's cookie-file reader normally skips cookies past their expires date, so this probe sends no auth_token and tests the request without it. A bounce to the login page therefore means "this file no longer logs in". It does not prove the server-side session is gone. If your portal has a documented refresh step, look that up yourself, because the refresh cookie's purpose is not stated in your notes.
Notes
- Pacing: each URL gets one request per run. Space requests to the same host at least 2 seconds apart and different hosts about 1 second apart. Hosts here are all different, and the control test for item 1 is already done.
- Token rotation: check your notes on whether
refreshrotates on use before running Probe 3. The-cflag saves any returned cookies. - Never paste cookie values. Names, flags and dates are enough.
- Items 2 and 3 need a human in a browser. Do not retry them.
- Re-run schedule: sessions daily at most, links weekly.
## Use cases
- Cleaning dead links out of docs, a blog or a link list
- Checking whether a saved login session still works
- Telling a bot block from a dead page
- Avoiding the trap of trusting a cookie's expiry date
## FAQ
**Do I paste my cookies?** No. Paste names, flags and dates only; the Skill tells you to redact values.
**Does it get around blocks?** No. Changing a User-Agent is only a diagnostic aid; a deliberate block is reported as UNDETERMINED.
**Does it call the sites?** No. You run the probes and paste results back; use it only on links and accounts you own or may test.


