Skip to content

Proposal: Bing Webmaster Tools integration #150

Description

@mlava

I've built a working Bing Webmaster Tools integration on a fork and would like to contribute it upstream — but it's a decent chunk of surface area (new table, two migrations, an MCP tool, a page), so I'd rather check the design is one you want before opening a PR you didn't ask for.

It's running on my own deployment against real Bing accounts, and the branch passes ci:check, 815 tests, and the eager-bundle build on top of current main.

Why Bing

It's free first-party data, same as Search Console, and it's the index behind Copilot and ChatGPT search — which makes it relevant to the AI-search angle the project already talks about. It also exposes crawl and index diagnostics plus URL submission that Google doesn't offer at all.

What's in v1

  • OAuth connect (hosted and self-hosted paths), per-project site mapping in a bing_connections table mirroring gsc_connections
  • A Bing page showing daily clicks and impressions
  • One read-only MCP tool, get_bing_performance, project-scoped like the Search Console tools
  • Reads are unmetered — no Autumn credits, matching how GSC reads are treated

Layered the way CLAUDE.md asks: client → repository → service → server function → MCP tool, mirroring the GSC feature closely enough that reviewing one teaches you the other.

The decisions I'd want your opinion on before a PR

1. Bing gets its own page, not a source toggle on Search Performance.

This is the load-bearing call. Bing's API is not a second Search Console — it has no date-range parameter, no device or country dimension, and no paging. Putting it behind a toggle on Search Performance would mean either advertising filters Bing can't honour or degrading the Google page. The asymmetry is permanent rather than something Bing will grow out of.

2. Reads are free and unmetered.

Consistent with specs/0003's treatment of GSC, on the same reasoning: Microsoft doesn't charge for this data, and connecting is an activation hook rather than a metered cost.

3. There's an auth_mode column for a mode that isn't built yet.

Bing rejects localhost redirect URIs and permits one redirect URI per registered OAuth client, so local development can't complete an OAuth flow without a public tunnel — an API-key path would fix that. I didn't build it, but the discriminator column is there so that lane needs no migration later. Happy to drop it if you'd rather not carry an unused column; it costs a migration to add back.

4. A retained probe script.

scripts/bing-oauth-spike.ts is a small CLI that calls Bing endpoints directly. Microsoft's OAuth documentation is wrong in at least two places, so every response shape in the spec was pinned by calling the live API rather than trusting the docs. I kept it because the spec asks for the refresh-token behaviour to be re-checked periodically, and because it's how any further Bing endpoint should be characterised before coding against it. Easy to drop if you'd prefer it not live in scripts/.

Two things worth knowing regardless of the outcome

Bing's OAuth is non-standard in a way that matters. Public reports say it rotates refresh tokens and then rejects the rotated ones — which would be fatal here, because Better Auth overwrites the stored refresh token with whatever a provider returns, so grants would die within one token lifetime. I couldn't reproduce it: Bing returns no refresh_token on refresh at all, replicated across two independent grants before and after regenerating the client secret. So genericOAuth is safe today. What I could not test is the slower "original token expires unpredictably after days" complaint in the same threads.

schema-parity.test.ts only covers the schema modules it happens to import. I hit this when the parity test passed for a table it had never seen. The branch adds the Bing schemas to it, but the general shape — a guard that silently skips anything not wired in — is worth knowing about independently of this feature.

What's not included

API-key connections, URL submission (needs the webmaster.manage scope, a separate consent decision), crawl issues, and Bing keyword data. GetQueryStats and GetPageStats are probed and documented in the spec — they carry AvgImpressionPosition, so a striking-distance view is reachable later — but they're out of v1.

Next step

Branch is ready if you want it. Happy to split it, change any of the four decisions above, or drop it entirely if Bing isn't a direction you want to take the project.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions