DEV Community

pickuma
pickuma

Posted on Originally published at pickuma.com

The Bing Webmaster API's 100-URL Daily Cap: 289 URLs Took Three Days and GetQueryStats Was Still Empty

We verified pickuma.com in Bing Webmaster Tools on 2026-08-18 by serving BingSiteAuth.xml, added the msvalidate.01 meta tag a day later as a second signal, and started driving the Webmaster API from a scheduled script on 2026-08-19. Three days of submission state and one weekly snapshot later, this is what the API actually returned.

The short version: GetUrlSubmissionQuota and SubmitUrlBatch work the moment verification lands. The reporting endpoints do not. On 2026-08-21, three days after verification, GetRankAndTrafficStats returned exactly one row and GetQueryStats returned none.

100 a day is a real cap, and 289 URLs took three days

The first GetUrlSubmissionQuota call came back with DailyQuota: 100 and MonthlyQuota: 1300. After one 100-URL SubmitUrlBatch, the same call returned DailyQuota: 0 and MonthlyQuota: 1200. Two separate buckets, both decremented by the same submissions.

That second number matters more than it looks. At the full 100/day rate, a 1300/month allowance is gone in 13 days. If you are planning a recurring push rather than a one-off catch-up, you are budgeting against the monthly figure, not the daily one.

Our sitemap held 286 URLs when the script first ran. Submitting newest-lastmod-first, with the homepage pinned to position one regardless of its date, the corpus drained like this:

  • 2026-08-19: 100 URLs
  • 2026-08-20: 100 URLs
  • 2026-08-21: 89 URLs

That totals 289 rather than 286 because three articles shipped mid-drain and the sitemap grew underneath the job. The state file absorbed it without special handling: each run reads the current sitemap, subtracts everything already sent, and takes the next 100.

That state file is the part worth copying. Without it, a daily cron re-sends the same first hundred URLs every morning and never reaches URL 101. Nothing tells you this is happening — the API accepts duplicate submissions and returns success, so the job looks healthy while covering 35% of the site forever.

The daily quota resets, but the monthly one is the constraint that bites. If you burn 100/day to clear a backlog, you have roughly 13 usable days per month. We did not test whether the monthly counter resets on the calendar month or on a rolling 30-day window, and the API does not say — plan for the pessimistic reading until you have watched a month boundary.

Which endpoints have data on day one, and which stay empty

This is the part the docs will not tell you, because the docs describe the endpoints rather than their warm-up behaviour.

Live immediately after verification: GetUrlSubmissionQuota and SubmitUrlBatch. Both worked on the first call, roughly a day after the verification file went up. You can build the entire submission pipeline before any reporting data exists.

Not live for days: the traffic endpoints. On 2026-08-21, GetRankAndTrafficStats returned a single row — dated 2026-08-18, with 609 impressions and 3 clicks. One row, not a series. And the date on it is the verification date, which means Bing does not backfill history from before you verified. Whatever the site was doing in search the week before, that data does not arrive later; it was never yours to read.

GetQueryStats, called in the same script run seconds later, returned zero rows. Three days after verification, with 609 impressions already recorded, the query breakdown was still empty. Impressions arrive first; the queries that produced them arrive later.

The practical consequence is a code-shape decision. An empty array from these endpoints is not an error and it is not a zero — it is "not yet". Our snapshot script returns { days: 0, impressions: 0, clicks: 0, queries: 0 } when the array is empty and null when the call throws, so a warm-up day and an outage day look different in the series. If you collapse both into 0, your first week of history is a fiction.

What we have not tested: how long GetQueryStats takes to populate, whether it needs a minimum impression threshold to return anything, and whether GetCrawlStats, GetPageStats, or GetCrawlIssues behave the same way — we have not exercised those three at all. One site, one verification, one week. Treat the lag figures as a lower bound on what to expect, not a schedule.

For context on why this endpoint is worth the trouble at all: on the same date, Google Search Console showed 37 indexed URLs against 633 "Crawled - currently not indexed", and Google offers no public API for requesting indexation — that stays manual clicking. Bing has both the submission API and the traffic API. It is the only search series we can record without a human opening a console.

Three failure modes worth writing code around

An empty urlList is an HTTP 400. This is not an edge case — a daily job hits it the first morning after the quota is spent, and again every morning after the corpus is fully submitted. The guard is four lines: if the batch is empty, log and exit 0. Without it, your cron mails you a failure every day for a job that is working correctly.

Errors come back as HTTP 200. SubmitUrlBatch returns a 200 with ErrorCode and Message in the JSON body for at least some failures. Checking response.ok is not sufficient; you have to parse the body and check ErrorCode before treating the submission as done — otherwise you write those URLs into your state file as sent, and they never get retried.

Everything is wrapped in d. Responses follow the old WCF/ASMX JSON convention, so the quota lives at j.d.DailyQuota, not j.DailyQuota, and the traffic rows at j.d. A missing d on a 200 response means the call failed in a way the status code did not report. Our quota function throws on it explicitly.

One non-API item that belongs in the same checklist: check your robots.txt for Crawl-Delay. Google ignores that directive; Bing honours it. We dropped ours on 2026-08-17. Submitting 100 URLs a day to a crawler you have separately instructed to slow down is self-defeating, and nothing in the API surfaces the conflict.

Would we pick this over IndexNow?

Not as a replacement. We run both, and they do different jobs.

IndexNow reaches the same crawler, has no daily quota, and needs no key rotation or per-site verification handshake. For normal publishing — a few URLs a day, announced as they change — IndexNow alone is enough, and the Webmaster API adds operational surface for nothing.

The API earns its place in two situations. The first is a bulk change: after a prune took this corpus from 702 articles to 269, we needed to push the survivors rather than announce a diff, and 100/day with resumable state is the mechanism for that. The second is telemetry — IndexNow tells you nothing back, while GetRankAndTrafficStats gives you an impressions series you can record weekly without a console.

The condition that flips it: if you never do bulk corpus changes and already have search data from another source, skip the API and keep IndexNow.


Originally published at pickuma.com. Subscribe to the RSS or follow @pickuma.bsky.social for new reviews.

Top comments (0)