The blind search missed my own LinkedIn
Shipped
First release of a skill that takes nothing but a person’s name, blind-searches the open web for their presence, keeps only what an identity gate can prove is actually them, and renders the result as a styled brand report. I dogfooded it on my own name, which is how I know the interesting part: the first real run confidently reported no LinkedIn and no X presence, and both accounts exist, under the exact handle the run had already confirmed everywhere else. The fix that shipped, a mandatory handle sweep with a three-state answer for every probe, is a pattern for any tool that has to assert absence.
Search results are not a coverage claim
The run had done its search rounds properly: name queries, handle queries, domain queries. What it never did was ask the walled platforms directly. Google’s own documentation on how its crawler works says it plainly: some pages “may not be accessible without logging in to the site”, and those pages simply are not crawled. A platform that shows logged-out visitors a login wall is, to a search index, mostly not there.
So “the search returned nothing” and “the account does not exist” are different facts, and a pipeline that flattens them into one will do what mine did: report a person absent from the two platforms where their professional presence actually lives. The corpus was not wrong anywhere it had evidence; it was wrong everywhere it had mistaken no-evidence for evidence.
Probe every handle by URL
The reliable move is the one OSINT tooling has used forever. Sherlock, the standard username-enumeration tool, does not search for usernames at all; it requests the profile URL directly on each of its 400+ sites and reads the response. Profile URLs are predictable, so a handle is checkable even where an index is blind.
My skill now does the same as a required discovery round: take every handle the subject verifiably uses anywhere (the domain name, the GitHub login, the npm scope, any slug a bio points at) and probe it on each major platform, whether or not search ever mentioned it:
export function probeUrls(handle) {
return [
`https://x.com/${handle}`,
`https://linkedin.com/in/${handle}`,
`https://github.com/${handle}`,
`https://npmjs.com/~${handle}`,
`https://medium.com/@${handle}`,
`https://youtube.com/@${handle}`,
`https://reddit.com/user/${handle}`,
`https://instagram.com/${handle}`,
];
}
People reuse handles far more consistently than search engines index them. Both accounts my run missed were sitting at <platform>/<the anchor handle>, one probe away the whole time.
Three outcomes, not two
The subtle part is interpreting a probe. HTTP gives you claims, not truths: in RFC 9110’s terms, a 404 says the server found no current representation, while a 403 says it understood you and refuses, which are different statements about whether anything is there. And a walled platform’s answer to a logged-out request often proves nothing in either direction; a 200 whose body is a login prompt, or an empty shell, has confirmed neither presence nor absence. So each probe resolves to one of three states, and the middle one is the load-bearing addition:
export function classify(status, bodyText, handle) {
if (status === 404) return "absent-claimed"; // the platform said not-found
if (status >= 200 && status < 300) {
if (bodyText.toLowerCase().includes(handle.toLowerCase()) &&
!looksLikeLoginWall(bodyText)) {
return "readable"; // content a stranger can read
}
return "walled"; // answered, proved nothing
}
return "walled"; // 403s, rate-limits, bot walls
}
(looksLikeLoginWall is your platform-specific detector for sign-in prompts and empty app shells.) A walled probe is not a dead end; it means work outward for proof that does not need the profile page. Post-permalink URL shapes are often indexed even when profiles are not, and when the subject is sitting in the room, their own authenticated tools can prove ownership, recorded honestly as out-of-band corroboration.
An account that is proven to exist but cannot be read logged-out gets recorded as an existence-only snapshot: the artifact says how it was probed and what tied it to the subject, claims nothing about content, and the report’s coverage row is tagged so a reader knows the content is invisible to a logged-out stranger, not missing. Only a handle no probe can substantiate on any platform is reported absent. From my run’s frozen corpus, the sidecar for one such source:
{
"id": "s11",
"url": "https://www.amazon.com/stores/author/B0B135VGS7",
"kind": "mention",
"platform": "amazon.com",
"title": "Amazon author page",
"status": "confirmed",
"corroboration": "Amazon's author page for the book already tied to the subject (s5); the SERP title names the subject and the store lists that book",
"existenceOnly": true,
"fetchedAt": "2026-08-11T17:56:55.784Z",
"file": "s11.md"
}
The existenceOnly flag is a field, not a phrase in a title, which is what lets the report machinery tag the coverage row automatically instead of a human remembering to.
A checklist in prose is a checklist that didn’t run
The sweep existed in this skill’s reference docs from the start, as prose. The failed run proves what that is worth: nothing forced it, so nothing ran it. Two structural changes made it real. The checklist became a command (sweep --handle <h>), which prints one probe row per platform per handle, so every transcript carries evidence of which probes ran and what each returned; coverage became auditable instead of assumed. And discovery’s stop rule changed: the pipeline may not conclude until every swept platform has a row that says readable, walled, or absent-claimed. A corpus without those rows is not coverage, it is whatever the search engine happened to index.
Verify it on your own name
Run the probe list against a handle you own, and read the classifications next to what you know is true. You should see something shaped like this:
platform url probe
github github.com/<you> readable
npm npmjs.com/~<you> readable
linkedin linkedin.com/in/<you> walled
x x.com/<you> walled
instagram instagram.com/<you> absent-claimed
The test that matters: every account you know you have must show up as readable or walled, never absent-claimed. If a platform where you have an account classifies as absent, your classifier is trusting a status code or an empty shell more than it should.
Gotchas
- The evidence was already in hand, unread. My missed LinkedIn slug was sitting inside a round-one search result URL, a post permalink of the form
linkedin.com/posts/<handle>_…, and the run never parsed it. Result URLs are data, not just links to visit: mine them for slugs and handles before concluding anything about a platform. - A fix that adds coverage must raise the eval floors with it. The corrected run found 7 confirmed sources where the broken one found 5, so the frozen baseline was refreshed and its anti-vacuity floor raised in the same change. Leave the old floor in place and the eval keeps passing on a corpus the size the bug used to produce, which quietly re-licenses the bug.
- An empty success is not a finding. A walled endpoint answering HTTP 200 with an empty or shell body is easy to read as “the URL worked”, and the discovery rules had to say explicitly that it confirms neither presence nor absence. Treat an empty success as proof of nothing, in either direction, or your three states silently collapse back into two.
Sources
- In-depth guide to how Google Search works — pages behind logins are not crawled, so login-walled profiles are largely invisible to search
- Sherlock — username enumeration by probing profile URLs directly across 400+ platforms
- RFC 9110: HTTP Semantics — what 403 and 404 actually assert, and why a status code is a claim rather than ground truth
Changelog
- chore(brandreport): gitignore run artifacts; say where runs belong (1efdb75)
- feat(brandreport): harden the run contract from three real runs (#206) (2107f44)
- feat(brandreport): add --id refresh-in-place; re-run picks up the anchor’s new X link (#205) (b49c84b)
- fix(brandreport): the handle sweep — walled platforms are probed, not left to search (#204) (7a5628b)
- feat(brandreport): analyze a personal online brand from nothing but a name (0.1.0) (#203) (cafa725)