index-now
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data β all from the browser, and deployed in milliseconds.
Viewing readonly version of main branch: v206View latest version
This val automates IndexNow submission by:
- Crawling sitemap URLs.
- Tracking submission history in project-scoped SQLite.
- Submitting only changed URLs.
- Read the IndexNow docs (indexnow.org/documentation) and make sure your key file is already hosted on your domain at a public URL like
https://www.example.org/<key>.txt. - Add at least one site file in
config/sites/*.json(see below for details). - Set required env vars (see below for details).
- Open
/to confirm the dashboard loads. - Run a safe dry run first:
POST /run?dryRun=1withx-indexnow-token. - After dry run looks correct, enable cron via
indexnow.cron.tsfor ongoing automation.
indexnow.http.ts: primary HTTP entrypoint.indexnow.cron.ts: scheduled trigger that POSTs to the HTTP handler at/run.
INDEXNOW_RUN_TOKEN(required): auth token required for/run(manual and cron).INDEXNOW_FORCE_TOKEN(optional but recommended): separate auth token required when usingforce=1.INDEXNOW_ENDPOINT(optional): defaults tohttps://api.indexnow.org/indexnow.INDEXNOW_PER_SITE_RUN_URL_LIMIT(optional): defaults to5000; per-site queue cap per run before batching into IndexNow POSTs.INDEXNOW_ALERTS_ENABLED(optional): defaults to enabled; set to0/falseto disable alert emails.INDEXNOW_ALERT_TO_<SITE>(optional): per-site alert recipient email (e.g.INDEXNOW_ALERT_TO_HANAYOU).
Site configs live in config/sites/*.json with one site per file.
At least one file must exist or the val will throw on startup.
Example: config/sites/hanayou.studio.json
{ "host": "www.hanayou.studio", "sitemapUrl": "https://www.hanayou.studio/sitemap.xml", "keyLocation": "https://www.hanayou.studio/2dc12b205bfe46d19a75077e3991f7ce.txt", "alertToEnvVar": "INDEXNOW_ALERT_TO_HANAYOU", "includePrefixes": ["/journal/", "/guides/"], "excludePrefixes": ["/tag/", "/author/"] }
Notes:
- Keep raw email addresses out of
config/sites/*.json; set as an env var instead. - If
alertToEnvVaris omitted (or env var is empty), the val sends alerts to the default owner email.
- Dashboard:
/ - Run endpoint:
/run /runisPOSTonly and requires auth:Authorization: Bearer <INDEXNOW_RUN_TOKEN>orx-indexnow-token: <INDEXNOW_RUN_TOKEN>
/rundefaults run reason tomanual_run_endpoint.x-indexnow-reason: cron_entrypointis reserved for the cron entrypoint.- Dry run:
POST /run?dryRun=1 - Force resubmit currently eligible URLs:
POST /run?force=1- also requires
x-indexnow-force-token: <INDEXNOW_FORCE_TOKEN>
- also requires
- On non-dry runs, the val emails per-site recipients when configured (otherwise owner) when:
- any URLs are successfully submitted, or
- there are attention conditions (
errors,pending, ordeferred).
- Target a single configured site:
POST /run?site=www.hanayou.studio - Response includes stage-specific URL arrays:
siteRuns[].filteredUrlsfor URLs that passed filters.siteRuns[].changedUrlsfor URLs detected as changed.siteRuns[].queuedUrlsfor changed URLs after run URL-limit capping.siteRuns[].submittedCountcounts only HTTP200responses.- HTTP
202responses are tracked as pending insiteRuns[].pendingCount.
Example:
curl -X POST "https://<your-val>.web.val.run/run?dryRun=1&site=www.hanayou.studio" \ -H "x-indexnow-token: <INDEXNOW_RUN_TOKEN>"
Force example:
curl -X POST "https://<your-val>.web.val.run/run?force=1&site=www.hanayou.studio" \ -H "x-indexnow-token: <INDEXNOW_RUN_TOKEN>" \ -H "x-indexnow-force-token: <INDEXNOW_FORCE_TOKEN>"
- Path:
/monitoronindexnow.http.ts(JSON default) - Purpose: IndexNow health snapshot from config + SQLite state
- Query params:
site(optional): limit report to one configured host.runs(optional): recent run-history records per site (default 50, max 500; this is not a URL count).view(optional):dashboardfor HTML UI, otherwise JSON.
Response highlights:
totals.everSubmitted200Urls: URLs that have ever had a confirmed HTTP200submission.totals.upToDateUrls: URLs whose latest sitemaplastmodis already covered by the last successful submission.totals.needsSubmissionUrls: URLs never successfully submitted, or changed since last successful submission.totals.retryPendingUrls: URLs that need submission and whose latest attempt was a non-200/202failure.sites[].latestRun: latest run summary per site.sites[].recentRuns: recent run history per site.
Dashboard example:
https://<your-val>.web.val.run/?site=www.hanayou.studio&runs=50
SQLite tables:
indexnow_url_state_v1: per-URL state (seen/submitted timestamps, lastmod, status).indexnow_run_log_v1: per-run summaries for observability and debugging.
This val uses https://esm.town/v/std/sqlite/main.ts so data is scoped to this val project.
INDEXNOW_PER_SITE_RUN_URL_LIMITis applied per site for each run.- If more changed URLs are discovered than the limit, the remainder is deferred to future runs.
- To intentionally resubmit unchanged URLs (still within limit), use
force=1withx-indexnow-force-token.
- Daily/incident check:
- Open
/dashboard and confirm site health cards are green. - Review recent runs for
pending,deferred, orErrorstatuses.
- Open
- Manual safe run flow:
- Run dry run first:
POST /run?dryRun=1. - Review
changedCountandqueuedCount. - If expected, run real submission:
POST /run.
- Run dry run first:
- If deferred URLs accumulate:
- Confirm this is expected (large content release, migration, etc.).
- Tune
INDEXNOW_PER_SITE_RUN_URL_LIMITand/or schedule frequency. - Use
force=1only when you intentionally want to resubmit unchanged URLs.
- Alert triage:
- Alert with
pending: retry/watch next run; investigate endpoint throttling. - Alert with
deferred: consider run URL-limit tuning or additional runs. - Alert with
errors: requires action before trusting indexing progress.
- Alert with
- External verification:
- Use Bing Webmaster Tools to verify ingestion trends.