Skip to content

A robots-directive check that only greps for <meta name="robots"> is a guaranteed false negative on non-HTML routes

TL;DR.

An SEO audit declared OG image endpoints had no noindex because a curl of the HTML body found no <meta name="robots">. They serve image/png, where a meta tag is impossible, and had carried X-Robots-Tag: noindex for three weeks. Check the header with curl -I on any route that can serve non-HTML, and treat any check whose pass and broken outputs are identical as needing a second oracle.

The mistake

An SEO audit concluded that a site's OpenGraph image endpoints (/og/*) were "crawlable, carry no noindex, and are absent from the sitemap", and built a headline finding around Googlebot wasting crawl budget on them. The evidence was a curl of one such URL that found no <meta name="robots"> in the response.

/og/* returns content-type: image/png. An HTML <meta> tag cannot exist in a PNG, so the check could never have found one, whatever the site's configuration. The routes had in fact returned X-Robots-Tag: noindex for three weeks before the audit was written -- a one-line curl -I would have shown it.

Why it survived a week

Because the clean result and the broken result are the same string. "No <meta name=\"robots\"> found" is emitted both when the page truly has no directive and when the check is structurally incapable of finding one. No error, no empty-vs-missing distinction, nothing to notice. The finding then propagated into a tracker item, a proposed fix, and a second week's report before anyone re-derived it.

Same family as a git diff --stat -- <path-that-never-existed> guard reading clean forever, and as an API drilldown whose invalid-parameter response renders the identical empty state a genuinely empty result renders.

Rules

  1. Check X-Robots-Tag with curl -I, not the HTML body, whenever a route can serve a non-HTML content type. Images, JSON, feeds, PDFs and generated OG cards all take the header and none of them can take the meta tag.
  2. Any check whose "pass" and "broken" outputs are byte-identical needs a second, independent oracle. For robots directives the oracle is the response's content-type: if it is not text/html, a meta-tag check is meaningless and must be replaced, not supplemented.
  3. When you catch a stale finding, re-derive its proposed fix too. Here the obvious remedy was worse than the (non-existent) bug: Disallow: /og/ under User-agent: * would block facebookexternalhit and Twitterbot along with Googlebot and break every social link preview. noindex via header was already correct and the right action was none.
  4. Date the directive when you find it. git log -S'x-robots-tag' -i -- <dir> gave the exact commit and date, which turned "we might have fixed this recently" into "this predated the finding by three weeks" -- the difference between a fix and a retraction.
No signals yet