| name | data-broker-optout |
| description | Automates U.S. people-search and data-broker opt-outs with Cursor @Browser and Gmail MCP (user-gmail) using config.yml and BROKER.md (BADBOOL). Use when the user asks to opt out, remove personal data from brokers, run Redactly, process BADBOOL, fill broker forms, or work on internet privacy control in this repo. |
Data Broker Opt-Out
Automate opt-outs from people-search sites with Cursor @Browser only. Subject data lives in config.yml; broker steps and URLs live in BROKER.md.
Do not use Playwright, Selenium, or other local browser automation in this repo.
Setup (once)
uv sync
Optional — list brokers from BADBOOL:
uv run python skills/data-broker-optout/scripts/parse_brokers.py BROKER.md
uv run python skills/data-broker-optout/scripts/parse_brokers.py BROKER.md --json
Load config in Python (agents only; never log values):
from config_helpers import load_config, birthday_parts
Quick start
- Read
config.yml (PII — never commit, log, or paste into chat).
- List brokers by priority (
parse_brokers.py or BROKER.md 💐 / ☠ sections).
- Read the broker's
### section in BROKER.md.
- Automate with @Browser —
browser_navigate, browser_snapshot, browser_fill, browser_click, etc.
- One broker at a time — finish each site before starting the next (see Sequential execution).
- CAPTCHA / Cloudflare — hard user gate; stop the session until the user completes it manually (see CAPTCHA / Cloudflare hard gate).
- End with a session summary (no full PII) — but not if the active broker is waiting on a CAPTCHA/Cloudflare handoff (see hard gate).
Sequential execution
Default: run brokers one by one — one active broker tab, complete or record status in output/progress.yml, then the next. Do not open multiple broker opt-outs in parallel unless the user explicitly asks.
Do not go to the next broker until the current broker is done. Treat the active broker as a gate: no browser_navigate to another broker’s opt-out/find URL, no Gmail searches for another broker’s mail, and no “while we wait” work on a different site until the current broker reaches a terminal status in output/progress.yml.
A broker is done (you may advance) when its status is one of:
| Status | Meaning |
|---|
done | Opt-out submitted and any required email/link confirmation finished |
skipped | User confirmed skip (📞/💰/🎫) or broker not applicable |
not-listed | No matching listing; documented in notes |
blocked | CAPTCHA/Cloudflare or site block after user handoff; cannot proceed |
Stay on in-progress, pending-email, or pending-user until resolved (including after the user replies done for CAPTCHA or you confirm via Gmail + @Browser). Only then update output/progress.yml and start the next broker from BROKER.md.
CAPTCHA / Cloudflare is stricter: while the active broker shows a challenge, that broker is a hard gate — see CAPTCHA / Cloudflare hard gate. Do not start the next broker, peek at other sites, or “continue the run” in the same turn.
| Mode | How |
|---|
| Agent (@Browser) | Single broker tab; use MCP browser tools; record output/progress.yml between brokers |
| Broker list CLI | parse_brokers.py — planning only, no browser |
Rules:
- One broker flow at a time — leave the previous tab on a confirmation page or close it before the next broker (unless the user asked to keep tabs for email confirm).
- No early switching — if the current broker needs CAPTCHA, email confirm, or a resubmit, finish that broker first; do not open Radaris/Nuwber/etc. “in parallel” or “while waiting.”
- CAPTCHA / Cloudflare — hard gate only; one challenge tab; stop and wait for user done before any next broker (see CAPTCHA / Cloudflare hard gate).
- Skip by default — tier 1 (💐) first; skip 📞/💰/🎫 unless the user confirms.
@Browser rules
Mandatory: Use the cursor-ide-browser MCP for all form filling, navigation, and screenshots.
- Lock workflow —
browser_navigate → browser_lock → interactions → browser_unlock.
- Snapshot before clicks — use
browser_snapshot for element refs; prefer browser_fill / browser_click over raw CDP for input.
- Screenshots on failure —
browser_take_screenshot; save or note path under output/screenshots/<broker>/.
- Never log config values — read from
config.yml and type into fields only via browser tools.
Gmail MCP (verification email)
Use the Gmail MCP server (user-gmail) to read verification and opt-out emails. Do not navigate to Gmail in @Browser.
- Find threads —
CallMcpTool → server user-gmail, tool search_threads:
query: Gmail search syntax, e.g. newer_than:2d (from:beenverified OR from:peopleconnect OR from:radaris OR from:nuwber OR from:checkpeople OR subject:opt-out OR subject:verify)
- Check spam if nothing in inbox:
in:spam newer_than:7d subject:verify
- Narrow to the subject inbox:
to:<email-from-config.yml> newer_than:1d
- Read full message —
get_thread with threadId from search; use messageFormat: FULL_CONTENT to get htmlBody / plaintextBody and extract the confirmation link.
- Confirm in browser —
browser_navigate to the verification URL in @Browser; complete any on-site steps; update output/progress.yml (pending-email → done when confirmed).
- Privacy — Do not paste full email bodies or tokens into chat; log broker name + status only.
If Gmail MCP is unavailable or returns auth errors, ask the user to fix MCP auth or paste the verification link, then continue in @Browser.
Typical flow
browser_navigate(opt-out URL)
browser_lock
browser_snapshot → find refs
browser_fill / browser_click (from config.yml fields per broker section in BROKER.md)
[CAPTCHA / Cloudflare? → HARD STOP → user manual → wait for done → then resume THIS broker only]
browser_take_screenshot (submitted or error)
browser_unlock
update output/progress.yml
[pending-email? → Gmail MCP search_threads → get_thread → browser_navigate(verify link)]
Priority
| Tier | Symbol | Count | Action |
|---|
| 1 | 💐 | 13 | Do first |
| 2 | ☠ | 6 | Do after tier 1 |
| 3 | — | rest | Then remaining People Search Sites |
| skip | 📞 💰 🎫 | — | Skip unless user confirms |
Also cover Search Engines when the user wants de-indexing, not just broker removal.
Per-broker workflow
- [ ] Search — @Browser: goto find URL, confirm listing exists
- [ ] Capture — copy profile URL from address bar or listing link
- [ ] Opt out — @Browser: fill from config.yml, submit, handle multi-step
- [ ] Verify — Gmail MCP: find confirmation email, open link in @Browser; phone-only (📞) → ask user
- [ ] Record — status: done | skipped | pending-email | blocked | not-listed
Data rule: Only submit fields the broker already shows on the listing. No SSN or full ID numbers.
CAPTCHA / Cloudflare hard gate
When Cloudflare (“Just a moment…”, “Performing security verification”), Turnstile, reCAPTCHA, hCaptcha, or any other CAPTCHA is visible (or still present after the short wait below), the active broker becomes a hard gate. The user must finish it manually before anything else happens.
Hard gate rules (mandatory)
- Stop automation immediately on that broker — no more
browser_click, browser_fill, CDP tricks, or “one more try” on the challenge.
- Do not go to the next broker — no
browser_navigate to another opt-out/find URL, no Gmail searches for another broker, no parse_brokers.py planning for “what’s next,” no parallel tabs, no “while you solve this I’ll start X.”
- End the agent turn after handoff — unlock @Browser (
browser_lock unlock), set output/progress.yml to pending-user with challenge type in notes, optional screenshot under output/screenshots/<broker>/, send the user message below, then stop. Do not continue the broker list in the same turn.
- Wait for an explicit user reply — the user must complete the challenge in the open tab and reply
done (or say they cannot). Until then, do not resume automation, even if the user sends unrelated messages.
- After
done only — resume the same broker from the same URL/step (submit form, email confirm, etc.). Advance to the next broker only when this broker reaches a terminal status (done, skipped, not-listed, or blocked if the user cannot finish).
- Never use CAPTCHA-solving services, bypass plugins, or repeated challenge clicks.
pending-user for CAPTCHA/Cloudflare is not permission to move on — it means “blocked on user until done.”
Detection flow
- Wait 10–15s in @Browser for auto-complete; at most one gentle retry (refresh or re-snapshot) on the same page.
- Challenge still present → hard gate (steps above).
- User replies
done → verify via snapshot/screenshot that the challenge is gone, then continue this broker only.
- User cannot finish →
status: blocked, screenshot, session summary; only then may you start the next broker.
Message to send the user (then stop)
[Broker name] is showing a security check (Cloudflare / CAPTCHA). Please complete it manually in the browser tab I have open (check the box, solve the puzzle, or wait for “Just a moment…” to finish). I will not continue to any other broker until you reply done and this step is finished.
Captchas and blocks
Same triggers and prohibitions as the hard gate. Summary: stop, hand off, wait for done, resume same broker only.
Do not loop retries, click the widget repeatedly, or use CAPTCHA-solving services.
Cloudflare and bot challenges
Tier-1 sites (BeenVerified, Nuwber search, etc.) often show “Performing security verification”, “Just a moment…”, or Turnstile. Cloudflare’s Browser Run product is built for agents that need a real browser, Live View, and Human in the Loop — not for silently defeating site security.
What to do (authorized opt-out only)
| Step | Action |
|---|
| 1 | @Browser: navigate; wait for domcontentloaded / snapshot |
| 2 | Wait 10–15s — some challenges auto-complete |
| 3 | One gentle retry (refresh or re-snapshot) |
| 4 | Ask the user — manual CAPTCHA/Cloudflare in @Browser; wait for done |
| 5 | Optional Cloudflare Browser Run (remote CDP MCP) only if user wants; CAPTCHA still manual via Live View |
| 6 | User cannot finish → blocked, screenshot, session summary |
Human in the loop (required for CAPTCHA)
Agents must not attempt to solve CAPTCHAs. Follow the hard gate: pause the whole run until the user replies done; no next broker until this broker clears the challenge.
- Cursor @Browser — User completes challenge in the open tab; agent resumes same broker after
done only.
- Browser Run Live View — User opens Live View and completes the challenge; agent resumes same broker after
done only.
Optional: Cloudflare Browser Run via MCP
Use when local @Browser repeatedly gets “Access restricted” or stuck Cloudflare interstitials. Requires env vars (never commit): CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_API_TOKEN.
chrome-devtools-mcp + Browser Run (docs):
{
"mcpServers": {
"browser-rendering": {
"command": "npx",
"args": [
"-y",
"chrome-devtools-mcp@latest",
"--wsEndpoint=wss://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/browser-rendering/devtools/browser?keep_alive=600000",
"--wsHeaders={\"Authorization\":\"Bearer <API_TOKEN>\"}"
]
}
}
}
Replace placeholders from the Cloudflare dashboard.
What not to do
- Playwright, Puppeteer, or
uv run playwright in this repo
- CAPTCHA-solving farms or “stealth” bypass plugins
- Assuming Browser Run
/crawl will skip challenges (it won’t)
Status values
| Status | When |
|---|
blocked | Cloudflare interstitial, Turnstile, or “Access temporarily restricted” after retry + HITL offer |
pending-user | User must finish in browser (CAPTCHA/Cloudflare/phone/etc.); hard gate — agent stops until user replies done; no next broker |
Escalate to user
Always ask the user (do not guess) for: Cloudflare/CAPTCHA/Turnstile (hard gate — manual completion, then done; no next broker until then), phone-only (📞), paid flows (💰), ID upload (🎫), Gmail MCP auth failures (or user must forward a link), or live site contradicts BROKER.md instructions.
Session summary template
## Opt-out session
**Completed:** BrokerA, BrokerB
**Pending user:** BrokerC (email confirm)
**Skipped:** BrokerD (📞 phone required)
**Not listed:** BrokerE
**Blocked:** BrokerF (captcha — see output/screenshots/)
Reference
- @Browser patterns, parent companies, field mapping: reference.md
- Broker list JSON:
uv run python skills/data-broker-optout/scripts/parse_brokers.py BROKER.md --json