Search Console's Page indexing report put 14 URLs from this site under "Crawled – currently not indexed". Only 4 of them were pages. The other 10 were files: six per-page opengraph-image routes, feed.xml, favicon.ico, and the root card twice, once with its cache-busting query. None of those should ever be in the index, so the status is harmless for them. I still added X-Robots-Tag: noindex to every one, but the more useful thing I learned is what that header does not do.
Why does Google crawl opengraph-image at all?#
In the App Router, an opengraph-image.tsx file next to a page becomes a route that returns a PNG, and Next.js writes its URL into the page's head:
<meta property="og:image" content="https://www.mohamedgado.com/projects/quizz-app/opengraph-image">Googlebot follows URLs it finds, and this is a plain absolute URL on your own domain. It fetches the image, sees that it isn't a page, and doesn't index it as one. Search Console reports that outcome as "Crawled – currently not indexed". That label covers "we looked and passed", and for a social card that is the right result.
So if the only rows in that bucket are image routes, feeds and icons, nothing is broken. The rows worth reading are the HTML pages. For those, the status usually means Google judged the content thin or too close to another page. I wrote about that case in Discovered – currently not indexed.
Why only some of my files had noindex#
I already had a rule from April that sent noindex on the root files:
// next.config.js, headers()
{
source:
'/:file(favicon\\.ico|icon\\.svg|apple-touch-icon\\.png|opengraph-image|twitter-image)',
headers: [{ key: 'X-Robots-Tag', value: 'noindex' }],
}/:file(...) matches one path segment. /opengraph-image matches it, and /projects/quizz-app/opengraph-image doesn't, so every per-page card went out with no robots header at all:
$ curl -sI https://www.mohamedgado.com/projects/quizz-app/opengraph-image | grep -i x-robots
$ curl -sI https://www.mohamedgado.com/opengraph-image | grep -i x-robots
X-Robots-Tag: noindexThe fix is two more rules: one for the dynamic route folders, one for the feeds:
{
source: '/:dir(projects|writing)/:slug/:file(opengraph-image|twitter-image)',
headers: [{ key: 'X-Robots-Tag', value: 'noindex' }],
},
{
source: '/:feed(feed\\.xml|writing/feed\\.xml)',
headers: [{ key: 'X-Robots-Tag', value: 'noindex' }],
},I named the two folders instead of writing /:path*/opengraph-image. A pattern that open is one typo away from matching a page, and a noindex header on a page is far worse than a missing one on a PNG.
A test that runs real paths through the matcher#
Reading the config by eye is how the gap got in. The test compiles each rule's source with the same path-to-regexp build that Next.js ships, then checks paths in both directions:
const { pathToRegexp } = load('next/dist/compiled/path-to-regexp')
const covered = (path: string) =>
noindex.some((r) => pathToRegexp(r.source, [], { strict: true, delimiter: '/' }).test(path))
for (const path of ['/projects/quizz-app/opengraph-image', '/writing/feed.xml' /* ... */])
assert.ok(covered(path), `${path} is indexable`)
for (const path of ['/', '/projects/quizz-app', '/writing'])
assert.ok(!covered(path), `${path} is a page but sends noindex`)Before the fix it failed on /projects/quizz-app/opengraph-image is indexable. The second loop matters as much as the first. It is what stops a later, broader rule from quietly deindexing the pages.
Does noindex clear the Search Console report?#
Not necessarily, and this is the part I didn't expect. My root /opengraph-image and /favicon.ico have sent noindex since April, and they were still listed under "Crawled – currently not indexed" in November. The report shows Google's last verdict on a URL. For a file it has already decided not to index, a new header may never change which bucket the row sits in.
So the header doesn't tidy the report. What it does:
- It makes the decision explicit instead of leaving it to Google's judgment, and it keeps the cards out of Google Images, where a text card on a dark background is worth nothing.
- It doesn't block anyone. It isn't a
robots.txtdisallow, so Googlebot can still fetch the image, and so can Facebook, X, Slack and LinkedIn when they build a link preview. The card keeps working everywhere it is meant to.
What I'd do on a new Next.js site#
- Ignore image, feed and icon rows in "Crawled – currently not indexed". Read the HTML rows.
- If you want the files marked, send
X-Robots-Tag: noindexon every depth ofopengraph-imageandtwitter-image, not only the root. - Never disallow those routes in
robots.txt. A crawler that can't fetch the image can't show your card. - Pin the rule with a test that also asserts the pages are not matched.