Skip to Content
ProvidersBing Webmaster Tools

Bing Webmaster Tools

Category: SEO & Analytics
Integration type: Tenant API key (stored in integrations table)
External API: Bing Webmaster Tools API v1


Purpose

Bing Webmaster Tools provides organic search performance data from Bing and DuckDuckGo (DuckDuckGo partially relies on Bing’s index). While Google Search Console covers the dominant search engine, Bing Webmaster Tools ensures clients with significant Bing traffic are not flying blind.

Key uses:

  • Report Writer — Bing organic search section alongside GSC data
  • Site Auditor — Bing’s crawl errors and index coverage (complements GSC)
  • Keyword Researcher — Bing keyword performance data as a secondary source

Bing Webmaster Tools is an optional integration — it is only relevant for clients who have measurable Bing traffic (typically B2B, finance, enterprise, and older demographic audiences where Bing/DuckDuckGo market share is higher).


Config Structure

Tenant integration

Bing Webmaster Tools uses an API key, not OAuth:

interface BingWebmasterConfig { apiKey: string; // From Bing Webmaster → User Settings → API Access siteUrl: string; // Exact URL as registered in Bing Webmaster (e.g. "https://acmeplumbing.com/") }
integrations row: provider: 'bing_webmaster' api_key: encrypt(apiKey) metadata: { siteUrl }

Integration Pattern

Tool layer (packages/tools/src/bing-webmaster.ts)

class BingWebmasterTool { private baseUrl = 'https://ssl.bing.com/webmaster/api.svc/json'; constructor( private apiKey: string, private siteUrl: string, ) {} private params(extra: Record<string, string> = {}) { return { apikey: this.apiKey, ...extra }; } async getQueryStats(options: { startDate: string; // YYYY-MM-DD endDate: string; }): Promise<BingQueryStat[]> { const response = await axios.get(`${this.baseUrl}/GetQueryStats`, { params: { ...this.params(), siteUrl: this.siteUrl, startDate: options.startDate, endDate: options.endDate, }, }); const data = response.data.d ?? response.data; return (data.QueryStats ?? []).map((row: any) => ({ query: row.Query, clicks: row.Clicks, impressions: row.Impressions, ctr: row.Ctr, avgPosition: row.AvgImpPosition, })); } async getPageStats(options: { startDate: string; endDate: string; page?: string; // Filter to a specific URL; omit for all pages }): Promise<BingPageStat[]> { const params: any = { ...this.params(), siteUrl: this.siteUrl, startDate: options.startDate, endDate: options.endDate, }; if (options.page) params.page = options.page; const response = await axios.get(`${this.baseUrl}/GetPageStats`, { params }); const data = response.data.d ?? response.data; return (data.PageStats ?? []).map((row: any) => ({ url: row.Page, clicks: row.Clicks, impressions: row.Impressions, ctr: row.Ctr, avgPosition: row.AvgImpPosition, })); } async getCrawlStats(): Promise<BingCrawlStats> { const response = await axios.get(`${this.baseUrl}/GetCrawlStats`, { params: { ...this.params(), siteUrl: this.siteUrl }, }); const stats = response.data.d?.CrawlStats ?? response.data.CrawlStats ?? {}; return { crawledUrls: stats.CrawledUrls, inIndexUrls: stats.InIndexUrls, blockedByRobots: stats.RobotsBlockedUrls, crawlErrors: stats.CrawlErrors, }; } async getSites(): Promise<{ url: string; verified: boolean }[]> { const response = await axios.get(`${this.baseUrl}/GetUserSites`, { params: this.params(), }); const sites = response.data.d?.Sites ?? response.data.Sites ?? []; return sites.map((s: any) => ({ url: s.SiteUrl ?? s, verified: s.IsVerified ?? true, })); } async verify(): Promise<void> { const sites = await this.getSites(); const match = sites.find(s => s.url === this.siteUrl); if (!match) throw new Error(`Site ${this.siteUrl} not found in Bing Webmaster Tools`); } }

Bing API response format quirk

Bing Webmaster API wraps responses in either d or a direct root object depending on the endpoint and API version. The tool layer handles both patterns (response.data.d ?? response.data).


Data Coverage

MetricBing WebmasterGoogle Search Console
ImpressionsYesYes
ClicksYesYes
CTRYesYes
Average positionYesYes
Page-level dataYesYes
Device breakdownPartialYes
Country breakdownNo (API)Yes
Index coverageCrawl statsURL inspection
BacklinksNoNo (use DataForSEO/Ahrefs)

Test Cases

Unit tests (packages/tools/src/bing-webmaster.test.ts)

TestApproach
getQueryStats() builds correct paramsMock axios.get; assert apikey, siteUrl, startDate, endDate
getQueryStats() handles d wrapperMock { d: { QueryStats: [...] } }; assert rows returned
getQueryStats() handles unwrapped responseMock { QueryStats: [...] } directly; assert rows returned
getCrawlStats() maps to typed objectMock crawl stats; assert field names normalised
verify() throws when siteUrl not in listMock getSites returns list without tenant URL; assert throws
Throws on 401 (invalid API key)Mock 401; assert propagated

© 2026 Leadmetrics — Internal use only