Skip to content

fix(leads): report a login wall as a login wall, not "no businesses found" - #128

Merged
ralyodio merged 1 commit into
masterfrom
feat/seed-login-detection
Jul 28, 2026
Merged

ralyodio merged 1 commit into
masterfrom
feat/seed-login-detection

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

Seeding a page that requires a login reported the same thing as seeding an empty directory, sending users off to debug their search terms when they had simply never been shown the page.

Why status codes don't work

Instagram answers explore/search/keyword/?q=... with HTTP 200, having quietly redirected to /accounts/login/?next=<the page you asked for>. A 200 carrying no business links is indistinguishable from a directory with nothing on it — which is exactly how it surfaced.

Two signals instead

  • Redirect onto a login path carrying a return parameter — the site explicitly refusing the request. Visible to a plain fetch, so the common case costs no render.
  • A password field in the DOM — covers login screens that only exist once scripts have run.

Both are needed here: Instagram's redirect shows up in fetch, while its login form does not appear until the page renders.

Not misfiring

A false positive would break a seed that works today, so the negative cases are tested as carefully as the positive one. Verified quiet on:

  • a directory with a "Log in" link in its header
  • a page deliberately seeded as a login page
  • an ordinary redirect (/browse → /browse/page-1)
  • a Cloudflare challenge — a different failure, still reported as one

Also handles cross-host SSO bounces and malformed URLs.

Result shape

discoverFromSeed and discoverProspects now carry loginRequired / loginRequiredSeeds, so the UI can offer to store credentials for that host instead of showing a dead end. Credential storage itself is a follow-up.

Verification note

Instagram began returning 429 to this host after repeated probing, so the live end-to-end path could not be re-confirmed. The tests pin the exact real redirect URL captured before the throttling, so detection is verified against real-world data rather than invented fixtures.

Checks

  • tsc --noEmit clean
  • 684/684 tests pass, 9 new
  • production build compiles

🤖 Generated with Claude Code

…ound"

Seeding a page that requires a login reported the same thing as seeding
an empty directory, which sent users off to debug their search terms
when they had simply never been shown the page.

Status codes are no help. Instagram answers a search URL with HTTP 200,
having quietly redirected to /accounts/login/?next=<the page you asked
for>, so a 200 carrying no business links is indistinguishable from a
directory with nothing on it.

Detection keys off two things instead. A redirect onto a login path that
carries a return parameter is the site explicitly refusing the request,
and it is visible to a plain fetch, so the common case costs no render. A
password field in the DOM covers login screens that only exist once
scripts have run.

Both are needed: Instagram's redirect shows up in fetch, while its login
form does not appear until the page renders.

Care went into not misfiring, since a false positive would break a seed
that works today. A "Log in" link in a directory's header is not a wall,
seeding a login page on purpose is not a wall, an ordinary redirect is
not a wall, and a bot challenge is a different failure that still reports
as one.

The result now carries loginRequired, so the UI can offer to store
credentials for that host rather than showing a dead end.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

vu1nz Security Review

0 finding(s) in PR #?

No security issues found.

@ralyodio
ralyodio merged commit a91eb18 into master Jul 28, 2026
8 checks passed
@ralyodio
ralyodio deleted the feat/seed-login-detection branch July 28, 2026 01:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant