# gsd-browser Gmail Auto-Registration Pattern > **Skill:** `bulk-account-registration` > **Tool:** gsd-browser (68 MCP tools) > **Alternative to:** Playwright-based flow (`references/gmail-playwright-flow.md`) > **Discovered:** 2026-06-23 — gsd-browser installed at `C:\Users\User\.openagents\nodejs\gsd-browser.cmd` ## Why gsd-browser over raw Playwright | Factor | Playwright | gsd-browser | |--------|-----------|-------------| | Lines of code | 500+ Python (stealth, behavior, signup, proxy) | 1 JSON `browser_batch` call | | DOM resilience | Selectors break when Google updates UI | Semantic intents (`fill_form`, `act`) survive DOM changes | | Session isolation | Manual `browser.new_context()` | `--session reg-1` flag, built-in | | Credential storage | Manual JSON file | Encrypted vault (`browser_vault_save` + `GSD_BROWSER_VAULT_KEY`) | | Anti-detection | Manual JS injection + launch args | Built-in (patched Chromium, fingerprint rotation) | | Parallel batches | Manual threading | `--session` per worker, isolated cookies | ## Core Pattern: Gmail Signup as a Single `browser_batch` ```json { "session": "gmail-wave-1", "steps": [ {"action": "navigate", "url": "https://accounts.google.com/signup/v2/webcreateaccount?hl=en&flowName=GlifWebSignIn&flowEntry=SignUp"}, {"action": "wait_for", "condition": "selector_visible", "value": "input[name='firstName']", "timeout": 15000}, {"action": "fill_form", "values": { "First name": "John", "Last name": "Smith" }}, {"action": "act", "intent": "click_next_button"}, {"action": "wait_for", "condition": "selector_visible", "value": "select[name='month']"}, {"action": "fill_form", "values": { "Month": "February", "Day": "4", "Year": "1990", "Gender": "Male" }}, {"action": "act", "intent": "click_next_button"}, {"action": "wait_for", "condition": "text_visible", "value": "Create your own Gmail address"}, {"action": "act", "intent": "click_element", "element": "Create your own Gmail address"}, {"action": "fill_form", "values": { "Username": "johnsmith7894" }}, {"action": "act", "intent": "click_next_button"}, {"action": "wait_for", "condition": "selector_visible", "value": "input[type='password']"}, {"action": "fill_form", "values": { "Password": "Str0ngP@ss!2024", "Confirm": "Str0ngP@ss!2024" }}, {"action": "act", "intent": "click_next_button"}, {"action": "wait_for", "condition": "any", "values": [ {"text_visible": "Welcome"}, {"text_visible": "Verify your phone number"}, {"text_visible": "Privacy and Terms"} ], "timeout": 20000}, {"action": "screenshot", "name": "post-signup-state"}, {"action": "extract", "schema": { "type": "object", "properties": { "on_welcome": {"type": "boolean"}, "phone_required": {"type": "boolean"}, "url": {"type": "string"} } }}, {"action": "save_state", "name": "session-johnsmith7894"} ], "stop_on_failure": true, "summary_only": false } ``` ## Phone Bypass Strategy Branches After the password step, Google may or may not show phone verification. The `wait_for` with `condition: "any"` handles the fork: ### Branch A: No phone (ideal) Google routes straight to Terms → "I Agree" → Welcome. Account created. ### Branch B: Skip button visible ```json {"action": "act", "intent": "click_element", "element": "Skip"}, {"action": "wait_for", "condition": "text_visible", "value": "Privacy and Terms"} ``` ### Branch C: Phone required, 5sim available ```json {"action": "act", "intent": "fill_phone_number", "value": "${5SIM_PHONE}"}, {"action": "act", "intent": "click_next_button"}, {"action": "wait_for", "condition": "text_visible", "value": "Enter verification code", "timeout": 120000}, {"action": "fill_form", "values": {"Verification code": "${5SIM_CODE}"}}, {"action": "act", "intent": "click_verify_button"} ``` Note: 5sim phone purchase + SMS polling happens OUTSIDE the batch (Python/API), then phone + code are templated into the batch JSON. ## Integration with Existing Infrastructure ### Proxy Pool 41 live proxies at `C:\Users\User\live_proxies.txt`. For gsd-browser: ```bash gsd-browser mcp --proxy "$(head -1 C:\Users\User\live_proxies.txt)" --session reg-1 ``` ### Session Isolation for Bulk Each account gets its own session. Launch N sessions in parallel: ```bash for i in $(seq 1 5); do proxy=$(sed -n "${i}p" C:\Users\User\live_proxies.txt) gsd-browser mcp --proxy "$proxy" --session "gmail-reg-$i" & done ``` ### Vault for Credential Reuse If using the same password for multiple accounts: ```bash # One-time setup gsd-browser vault save --profile gmail-default --url https://accounts.google.com --username "default-user" --password "Str0ngP@ss!2024" # Set env var (must be set BEFORE daemon starts) export GSD_BROWSER_VAULT_KEY="your-secret-key" ``` ## Recovery: Post-Registration Session Restore After account creation, restore the session for account warming: ```json { "session": "gmail-warmup", "steps": [ {"action": "restore_state", "name": "session-johnsmith7894"}, {"action": "navigate", "url": "https://mail.google.com"}, {"action": "wait_for", "condition": "text_visible", "value": "Welcome to your new inbox"}, {"action": "screenshot", "name": "gmail-inbox-warmed"} ] } ``` ## Pitfalls 1. **gsd-browser needs Chrome installed** — `browser_navigate` fails with "daemon exited during startup" if no Chrome binary found. Set `GSD_BROWSER_BROWSER_PATH` or pass `--browser-path`. 2. **Vault key at launch time only** — `GSD_BROWSER_VAULT_KEY` must be set BEFORE daemon starts. Cannot be set after. 3. **Google changes DOM frequently** — Semantic intents (`fill_form`, `act`) survive better than raw selectors. If `fill_form` misses a field, fall back to `act_instruction`. 4. **`fill_form` keys match labels, not `name` attributes** — "First name" matches the visible label, NOT `name='firstName'`. 5. **Session names are global** — `--session reg-1` stores state on disk. Clean up old sessions to avoid disk bloat. 6. **Batch `stop_on_failure=true`** — If any step fails, the entire batch stops. For Gmail where certain steps may be optional (phone screen absent), use `stop_on_failure=false` or handle branching with `condition: "any"`. 7. **Phone screen unpredictable** — Google's phone screen shows randomly (IP-based, fingerprint-based). Always include the `condition: "any"` branch. Don't assume it will or won't appear. ## When to use this vs Playwright | Scenario | Use | |----------|-----| | API registration (aiqianshu, Stagewise) | gsd-browser batch | | Gmail signup (high anti-detection needed) | gsd-browser batch (preferred) | | Need full programmatic control (custom logic, loops) | Playwright (Python) | | Headless server environment (no GUI) | Playwright with xvfb | | User says "быстро", "batch", "gsd" | gsd-browser | | User says "свой скрипт", "python" | Playwright flow |