Skip to content
Development

The package I almost used, and why the ephemeral build container said no

By Victor Da Luz
astroseocloudflaredev-logsite

Bing Webmaster Tools wants IndexNow set up: a small protocol where you ping one endpoint and Bing, Yandex, Seznam, and Naver all find out a page changed, instead of waiting for each of them to crawl around to it eventually. The protocol itself is almost insultingly simple - host a text file with a random key, POST a URL list somewhere, done. The interesting part of this issue wasn’t the protocol. It was figuring out what “somewhere” and “when” actually mean for a site that deploys the way this one does.

The obvious answer was almost the wrong one

There’s a real, maintained Astro package for this - astro-indexnow. Astro 4 through 7, MIT license, does exactly what the issue asked for: hashes your built pages, only resubmits the ones that changed since last time. I went in assuming I’d install it, wire up a key, close the issue in ten minutes.

Then I read how it tracks “changed since last time”: it hashes every built HTML file into a JSON cache, and to compare against the previous build, that cache file has to be committed back to the repo after each build. Their docs say this outright - it’s designed for CI/CD setups that can add a “commit the cache file” step after building.

This site deploys through Cloudflare Workers Builds: push to main, Cloudflare spins up a throwaway container, builds, deploys, and the container is gone. There’s no step where anything gets written back to the repository - by design, it’s a one-way pipe. The package assumes a shape of CI/CD that this deploy doesn’t have. Not a bug in the package, just a mismatch I wouldn’t have caught without actually reading past the install instructions.

What I built instead

IndexNow’s own docs say resubmitting URLs that haven’t changed costs nothing - there’s no penalty, no rate-limit trap for being “wasteful.” So for a site with about 26 pages, change-diffing was solving a problem I didn’t have. I skipped the cache entirely and just resubmit everything, every deploy.

That turned into a small Astro integration instead of a dependency. Astro hands every integration a pages array in its astro:build:done hook - literally every prerendered route, already deduped, no HTML-walking or sitemap-parsing required. I read the actual hook source in node_modules rather than trust what I remembered about the API, since “I remember it works like X” is exactly the kind of assumption that costs an hour later. Forty lines, zero new dependencies, one fetch call.

The part that needed a second lookup

Without a guard, this integration would fire on every single build - my local npm run dev iterations, and the separate preview-branch trigger this repo uses for non-main pushes. Both would happily submit the production domain’s URLs to a real search index, repeatedly, for no reason.

Cloudflare Workers Builds injects WORKERS_CI_BRANCH into the build environment - I hadn’t used this before, had to go find it in Cloudflare’s own docs. Gate on === 'main' and the integration goes silent everywhere except the actual production build.

Proving it before it could really be proven

The key file wasn’t live yet - it ships in this same commit - so I couldn’t get a real “yes, IndexNow accepted this” until after merge. What I could do: force WORKERS_CI_BRANCH=main locally and let the integration make a real network call to the real API. It came back 202 Accepted, not the 403 I was expecting for an unverifiable key. Turns out IndexNow queues submissions for async key verification rather than bouncing them - so a 202 pre-deploy tells you the request shape is correct, and you find out for certain post-deploy. Good enough to ship with a documented follow-up instead of blocking on it.

Related reading

Development

The description nobody wrote

Bing said the site's meta descriptions were too short. Almost every page had a good one - except the homepage and the blog index, the two pages everybody actually lands on.

Read