The detector matched the word it was hunting for, in the page it was submitting
This post describes one script’s behavior against the Search Console web interface in October 2026. Quota behavior and page labels change without notice; treat the numbers as a snapshot of my account, not a specification.
My indexing script stopped a batch of three URLs because it believed the daily quota was exhausted. It was not. Two seconds after the first click, the detector found the word it was hunting for — in the title and body of the page being submitted. That page was my own article about the quota. The false alarm cost a working window, and it wrote a wrong conclusion into my notes before I caught it.
The alarm fired two seconds after the click
The job runs every day around lunchtime and submits a short queue of URLs to Search Console’s “Request Indexing” tool. The quota is shared across every property under one Google account and behaves like a rolling window, so the script’s rule is simple: the moment it sees the quota message, stop the queue and hand the rest to the next window. On October 17, 2026, it saw the message immediately.
| Time (Beijing, 2026-10-17) | What happened | URLs submitted |
|---|---|---|
| 13:37 | Scheduled batch starts; three blog URLs pass the read-only pre-check | 0 |
| 13:42:48 | First URL clicked; the script reports the quota exhausted | 0 |
| 13:42:50 | The whole batch stops, per the stop rule | 0 |
| 19:30–19:31 | The detection rule is fixed; the same queue retries and two URLs submit in one click each | 2 |
| 19:43 | A different site’s batch hits the real cap and stops | 2 |
The stop rule is correct. The reading that triggered it was not.
The detector was reading my own blog post
The first URL in the queue was https://javaeye.dev/blog/google-request-indexing-quota/, a post I published five days earlier about measuring the quota. Its title contains the word quota and its body repeats the word dozens of times. The script’s detector did this: after each click, it read the entire page text and asked whether the string quota appeared anywhere.
That question was guaranteed to be true. The page was about the only thing the detector was looking for.
The signal I actually needed lives in the platform’s dialog — a badge or banner that appears after a submission completes, with a fixed sentence about the daily limit. Everything else on the page is content, and content is exactly what I cannot control. My own article was the worst possible subject for a substring test, but any page could contain the word by accident: a changelog mentioning “quota”, a comparison table, a quoted error message.
The screenshot from that run shows what was on screen at the moment of the alarm: a progress dialog reading “Testing the actual URL” (translated from the Chinese interface), and no quota text at all. The evidence to overturn the verdict had been captured automatically. Nobody read it until the evening.
A false stop is expensive when the resource is a clock
The account’s daily capacity in early October floated between 9 and 16 successful submissions, which I measured separately. A stop is meant to protect that pool. But a false stop spends the resource it was designed to protect: the queue did not move for six hours, and the three URLs stayed unsubmitted while the window ran.
The second cost was worse. That morning’s log entry recorded the false alarm as a second data point for a scheduling conclusion — that the quota window rolls on a 24-hour clock. The conclusion may still be right; I have other evidence for it. But one of its two supporting observations was an alarm that never happened, and that note survived in the file for hours because the alarm looked like evidence.
A false positive is not just noise. It becomes a fact in your log if you let it.
The fix was to stop scanning the page
The change was small and it removed the whole class of error. Instead of reading the page, the script now waits for the status dialog and reads only that element. Instead of searching for a topic word, it matches the platform’s sentence as a whole.
// before — any occurrence of the topic word anywhere on the page
const text = await page.innerText('body');
if (text.includes('quota')) return 'quota-exhausted';
// after — only the dialog, only the platform's own phrasing
const dialog = await visibleDialog(page); // null if nothing is showing
if (!dialog) return 'unknown';
const text = await dialog.innerText();
if (/daily quota/i.test(text)) return 'quota-exhausted'; // match the localized phrase too
if (/could not be indexed/i.test(text)) return 'rejected'; // localized equivalent
return 'submitted';
Three differences matter. The scan is scoped to the dialog, so the article can say whatever it likes. The match is the platform’s fixed phrase rather than a word from my own topic vocabulary. And there is now a third state: unknown. The old script had two outcomes, “submitted” and “quota exhausted”, so anything it failed to parse fell into the second one. A detector that cannot say “I do not know” will say “failed” instead.
The same detector fired for real the next day
The next afternoon the account had almost nothing left. One URL submitted at 13:38, and the next click produced the quota banner — the real one, with the fixed sentence in the dialog. The script stopped the batch, saved the screenshot, and this time the screenshot agreed with the verdict.
So the rule now has both a known false positive and a known true positive, on consecutive days, on the same script. That is the only kind of evidence that tells you a detector has been fixed rather than merely silenced.
Six rules I now apply to every detector
- Keep the detector’s vocabulary disjoint from the subject’s. If the thing being checked can contain the words the check is looking for, the check is not measuring the platform — it is measuring the input.
- Match the platform’s sentence, not the topic. “Quota” is a subject. “You have exceeded your daily quota for today” is a claim made by someone else.
- Give the detector three states. Passed, failed, and unknown. The third one is not a failure to be hidden; it is the honest output when evidence is missing.
- Save the evidence the alarm fired on. A screenshot taken automatically is worthless if the human step reads only the script’s verdict. The verdict and its evidence have to be reviewed together.
- Write the adversarial fixture. The test I now keep is a page whose title contains the trigger word for innocent reasons. My old suite never had one, so the false positive had no way to surface before production.
- Verify the fix in the artifact, not in the note. Before the evening retry I found that another “already fixed” error signature existed only in my notes — the script itself had never been updated. A fix is a property of the file. Grep the file.
Rule 5 is the one I expect to keep paying for. Every detector is built with examples of the failure it is meant to catch. Almost none are built with an example of something that merely looks like the failure, which is exactly the shape of a false alarm.
What this does not fix
The quota is still real, still shared across every property under the account, and still small enough that a stopped batch matters. Rolling windows still mean a missed evening can push a queue into the next day. The detector is more honest now; the resource did not change.
What changed is the failure mode. Before, a parsing gap turned into a confident “quota exhausted” and a stopped queue. Now the same gap turns into “unknown”, which stops the queue too — but leaves a record that says why, and a screenshot that can be read in ten seconds. For an unattended job, that difference is the whole point: an alarm is only useful if the next person can tell what it saw.
This article was created with the help of AI. AI was not used to write the content; it assisted only with translation and grammar checks.