Repository navigation
Add a daily IndexNow submission workflow - #1882
Merged
David Pine (IEvangelist) merged 6 commits intoOct 13, 2026
Merged
Conversation
Adds a scheduled workflow that tells IndexNow search engines about aspire.dev URLs. Each run reads the live sitemap, submits URLs that are new or removed since the previous run, then the next window of a slow rotation through the whole sitemap. When a release/X.Y pull request is merged into main, the workflow waits for that release's What's new page to be live and then starts a full-sitemap burst that the daily runs finish. State is kept in an Actions artifact and IndexNow's undisclosed rate limits are handled by configurable budgets and 429 handling. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
A release adds thousands of generated API pages and rewrites the data of most of the rest, so a plain walk over the sitemap sends the pages that changed no sooner than the ones that did not. - Map the files a release pull request changed to sitemap pages (docs routes, and every page of an API package or module whose data changed beyond the version, source commit and source line numbers) and rank those pages first in the cycle. - Cover the pages that are new when a flush starts with the same ranking, so docs go before the generated API reference however many API pages a release adds. - Read the changed files in the workflow from the release pull request (or the last merged release/X.Y pull request for a manual flush). - Persist state after a flush that was rate limited before anything was accepted, fail a run that a 429 stopped before any URL was accepted, validate the state read from an artifact, ignore artifacts uploaded by runs from forks, and queue runs per job so closed pull requests do not replace a pending run. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
- A pull request for a release whose cycle is still running continues that cycle instead of starting the burst over. The same release can arrive twice: its content pull request and, hours later, the one that merges the release branch back (13.4 had both, and the second changed no files). A manual flush still starts over. - Ignore pull requests from forks when a manual flush looks up the release pull request. - Fix a stale comment on the cap for removed and new URLs, which is joint. - Cover the removed URL cap, the deferred count, a cold start that fails to submit, and the continued cycle in tests. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Priority submissions can exceed the configured per-run rotation budget.
1 open finding
What changed in this PR
Adds automated IndexNow submissions to improve discovery of new, updated, and removed aspire.dev pages.
Changes:
- Adds scheduled, release-triggered, and manual submission modes.
- Implements sitemap planning, persisted state, retries, release prioritization, and safety checks.
- Adds configuration, public verification key, package command, and extensive unit coverage.
| File | Description |
|---|---|
.github/workflows/indexnow.yml |
Runs submissions and persists state. |
src/frontend/scripts/indexnow.ts |
Implements IndexNow orchestration. |
src/frontend/tests/unit/indexnow.vitest.test.ts |
Tests planning, state, triggers, and submissions. |
src/frontend/config/indexnow.json |
Configures endpoint, key, and budgets. |
src/frontend/public/c5f794ab28dc0cb92f48bd970500daa3.txt |
Publishes the verification key. |
src/frontend/package.json |
Adds the indexnow command. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Contributor
Frontend HTML artifact readyThe latest frontend build uploaded the This comment updates automatically when a new frontend build artifact is uploaded. |
Say what the cron expression means, how often it runs, what each run does and why the minute is not on the hour. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The first version grew well past a simple scheduled job. Cut it back to what the job needs: - Drop the mapping from the files a release changed to pages. It hard-coded the content and API data paths and routes, and needed ranking, a skip list and extra state to support it. A release burst now sends the English pages first, which is where the new and updated docs are, then the API reference and the localized pages. - Send one request per run. The budgets fit in the 10,000 URLs IndexNow takes, so there is no chunking, partial acceptance or Retry-After handling: a failed request leaves the progress alone and the next run tries again. - Start a release only from a release/X.Y branch, and keep the state in a single file. - Trim the config and state validation, the logger and the run report to what the job needs. The script goes from 1,664 to 809 lines and the tests from 2,283 to 1,037. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Say why the job declares permissions although the workflow sets none: a job's own block replaces the workflow default, and these two are what the checkout and the state artifact restore need. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
David Pine (IEvangelist)
enabled auto-merge (squash)
October 13, 2026 19:28
Eric Erhardt (eerhardt)
approved these changes
Oct 13, 2026
David Pine (IEvangelist)
disabled auto-merge
October 13, 2026 20:09
David Pine (IEvangelist)
deleted the
ievangelist-indexnow-daily-crawl-workflow
branch
October 13, 2026 20:10
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
Adds a scheduled workflow that tells IndexNow search engines (Bing, Yandex, Naver, Seznam, Yep, Amazon) about aspire.dev URLs, so new docs are discovered quickly, especially right after a release ships.
How it works (
.github/workflows/indexnow.yml+src/frontend/scripts/indexnow.ts, also runnable locally withpnpm indexnow)release/X.Ypull request intomainwaits up to 45 minutes for that release's "What's new" page to be live (the docs slot swap), then starts a burst of up to 10,000 URLs per run that the daily runs finish (about 4 runs today). After that the slow rotation resumes. The sitemap has nolastmod, so the script can't tell an updated page from an unchanged one; the burst sends all English pages first, which is where the new and updated docs are.workflow_dispatchwithmode(daily or flush),limit,release,dry_runandallow_shrink.state.jsonin theindexnow-stateActions artifact (90 days). Losing it only causes a cold start that re-seeds the known list without submitting everything.What the script assumes about the site (listed at the top of
indexnow.ts; everything else is insrc/frontend/config/indexnow.json)/reference/api/is the generated API reference, and the locale folders inconfig/locales.tshold the translations. Both are sent after the English pages.release/X.Ybranch and publishes/whats-new/aspire-X-Y/(aspire-Xfor X.0).No repository secret is needed. An IndexNow key is public by design: the key file has to be downloadable from the site root so engines can verify ownership. The key is committed (
src/frontend/config/indexnow.jsonandsrc/frontend/public/<key>.txt). The workflow only uses the automatic token withcontentsandactionsread access.Safety rails: a key-file preflight (a cold start skips softly until the key file has deployed), refusal of a sitemap that shrank by more than 20% (
allow_shrinkoverrides), state read from an artifact is checked (and artifacts from fork runs are ignored),--limitis a hard cap, and 5xx and network errors retry with back-off.Rollout
https://aspire.dev/c5f794ab28dc0cb92f48bd970500daa3.txt(until then the first run skips).dry_runto see the plan.mode: flushwithrelease: X.Y. Verify in Bing Webmaster Tools under IndexNow.Notes
release10,000 androtation1,000) live inconfig/indexnow.json. A test keeps them within one request.closedpull request event) first runs on the next release and can't be exercised before merging. The trigger matches a merged pull request fromrelease/X.Yin this repository, which is what the 13.4, 13.5 and 13.6 content pull requests are. The pull request that merges the release branch back is not a trigger; a manualflushcovers repairs.concurrencyusesqueue: max, which GitHub documents. actionlint 1.7.12 doesn't know it yet, and the repository doesn't run actionlint in CI.lastmodvalues in the sitemap would let search engines (Bing and Google use them to schedule crawls) and this script tell updated pages apart.Third-party links and affiliations
https://www.indexnow.org/documentation(referenced in a code comment) and thehttps://api.indexnow.org/indexnowendpoint (inconfig/indexnow.json) are the IndexNow protocol's documentation and submission endpoint. IndexNow is an open protocol launched by Microsoft Bing and Yandex, and aspire.dev is also a Microsoft site. This change adds no sponsorship or other affiliation.Validation
From
src/frontend:pnpm exec vitest run --config vitest.config.ts tests/unit/indexnow.vitest.test.ts: passed, 83 tests.pnpm test:unit: passed, 81 files and 1,121 tests (1 skipped).pnpm lint: passed.actionlint1.7.12 on the workflow, with thequeue: maxline removed because actionlint doesn't know it: passed.pnpmfor theschedule,pull_requestandworkflow_dispatchtriggers builds the expected arguments.--mode flush --release 13.6plans 10,000, neither writes state, and an invalid--limitexits 1. The 404 warning for the key file is expected until it deploys.Not run:
pnpm build(left to CI), a real IndexNow submission (the key file isn't deployed yet) and the pull-request-triggered path (first exercised by the next release merge).