Battling Google Search Console with OpenCode: Taking Over a Real Chrome Browser

576 words
3 minutes
Battling Google Search Console with OpenCode: Taking Over a Real Chrome Browser

The Backstory#

I had just set up two new blogs (one Chinese, one English) and needed to add them to Google Search Console, then invite a service account as a user. One “Add User” dialog. A couple of clicks. Simple enough.

Let OpenCode automate it, I thought.

The built-in browser-control MCP (backed by playwright-core) fired up a headless browser, navigated to Search Console, and — captcha. Switched to Puppeteer. Still captcha. Tried Playwright’s stealth plugin. Same thing.

After half an hour of banging my head against automation detection, it dawned on me: My real Chrome was already logged into Google right there on my desktop. Why was I trying to open a new one?

The Solution: stealth-chrome MCP#

The idea is embarrassingly simple once you say it out loud: don’t spin up a new browser, take over the one that’s already running.

Chrome DevTools Protocol (CDP) exists exactly for this. Your login sessions, cookies, extensions — all of them are already there, no setup needed.

I wrote a ~50-line MCP server using chrome-launcher, wrapped the CDP connection, and registered it in OpenCode’s MCP config:

~/.config/opencode/opencode.jsonc
{
"mcp": {
"stealth-chrome": {
"type": "local",
"command": [
"node",
"/path/to/stealth-mcp-server.mjs"
],
"enabled": true,
"description": "Real Chrome takeover, persistent session"
}
}
}

Then I removed the old browser-control entry entirely.

First connection: Search Console opened already logged in. Zero captchas. Zero friction. It just worked — like I was clicking around myself.

War Stories#

Of course it wasn’t all smooth sailing. Here are five real gotchas I hit.

1. Click That Wouldn’t Click#

The “Add User” button in Search Console — clicking it with stealth-chrome_click navigated to a completely unrelated page every single time. I retried four times before giving up.

Switched to stealth-chrome_evaluate and called element.click() from JavaScript. The dialog popped right open.

Lesson: SPA event handlers don’t always respond to synthesized CDP clicks. When click fails, evaluate + native element.click() is your fallback.

2. Ref IDs Are Ephemeral#

Every time you snapshot a page, elements get fresh ref IDs (e42, e106, etc.). Navigate away and back? Different refs.

First time I hit this I thought I was losing my mind.

Lesson: Don’t hardcode refs across page transitions. Use JS selectors for anything that spans multiple interactions.

3. You Picked the Wrong Dialog#

Search Console has two [role="dialog"] elements on the same page — one for the sidebar nav, one for the actual modal dialog. document.querySelector('[role="dialog"]') consistently grabbed the sidebar.

Lesson: Use document.querySelectorAll(...) and grab the last one.

4. Input Value Set, SPA Didn’t Care#

I set input.value = 'service-account@...' and clicked “Add”. It told me the email was invalid. The value was clearly there in the DOM.

SPA frameworks listen for input events, not property changes. Setting .value silently doesn’t fire anything.

The fix:

input.value = '[email protected]';
input.dispatchEvent(new Event('input', { bubbles: true }));
input.dispatchEvent(new Event('change', { bubbles: true }));

In Search Console’s settings page, “Users and Permissions” looks like something you click to expand a section. Turns out it’s an honest-to-god <a href="..."> link that navigates to a different page entirely.

Lesson: Inspect a.href before you click. Not everything in a SPA is SPA-routed.

Tools I Actually Used#

ToolWhat For
stealth-chrome_navigateGo to Search Console
stealth-chrome_snapshotSee what’s clickable
stealth-chrome_clickSimple buttons
stealth-chrome_evaluateWorkhorse — JS for everything tricky
stealth-chrome_screenshotVerify state visually

When to Use This#

Any site that needs you to be logged in — Search Console, Cloudflare Dashboard, Gmail, you name it. Stealth-chrome handles it because it is your browser. Just keep Chrome running.

TL;DR#

Don’t fight browser automation detection. Use the browser you’re already logged into.

Set it up once, leave the MCP server running, and never think about headless Chrome again. Just don’t close your browser.

Support & Share

If this article helped you, please share or support!

Sponsor
Battling Google Search Console with OpenCode: Taking Over a Real Chrome Browser
https://blog.zinzin.cc/posts/stealth-chrome-mcp-en/
Author
gzdyj
Published at
2026-07-29
Profile Image of the Author
gzdyj
Code, life, and everything in between.
Announcement
Welcome to my blog! Here I share my tech journey and life thoughts. Feel free to leave a comment.
Categories
Tags
Latest Moments
Site Statistics
Posts
15
Categories
8
Tags
45
Total Words
39,874
Running Days
0 days
Last Activity
0 days ago
Site Info
Build Platform
GitHub Actions
Blog Version
Firefly v6.14.5
License
CC BY-NC-SA 4.0