The three moving parts
A key, a key file served at the root, and a request that names changed URLs. Nothing else is required, and nothing else is inferred.
Set it up
- Generate a key. Any random string will do, and it is not a secret.
- Write it to a text file named after the key, at the site root.
- Deploy, then fetch the file and confirm the body is the key alone.
- Add the submission step to the pipeline, after a successful deploy.
- Keep the key stable, or update the file and the script together.
The filled setup
key: 4f2a9c1b7e
key file: /4f2a9c1b7e.txt
key file check: fetched 2026-09-18, 200, body is the key on one line
host: meridian-landscaping.example
changed urls: 22, from the launch
request: https://api.indexnow.org/indexnow
response: accepted, 2026-09-18 22:41
deploy step, in order
1. build
2. deploy
3. fetch one url on the live host, and fail the step if it is not 200
4. post the changed urls
5. record the response code in the build log
The code
const key = process.env.INDEXNOW_KEY;
const host = 'meridian-landscaping.example';
const changed = process.argv.slice(2);
const response = await fetch('https://api.indexnow.org/indexnow', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({
host,
key,
keyLocation: `https://${host}/${key}.txt`,
urlList: changed,
}),
});
console.log('indexnow', response.status);
if (!response.ok) process.exit(1);
Acceptance: the setup works when
- the key file returns 200 at the exact path, with no redirect
- the body is the key alone, with no whitespace or extra text
- one submission is accepted, and the response code is in the log
- the step runs after deploy, not before
- only URLs whose content changed are sent
Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| 403 from the endpoint | The key file is missing or mismatched | Fetch the exact path yourself |
| 422 from the endpoint | The URL list is empty or malformed | Log the list, then send one URL |
| A redirect on the key file | The host rewrites .txt |
Serve the file directly from the root |
| Every URL is sent every deploy | The step sends the output directory | Diff the content, then send changes |
| Nothing is crawled afterwards | Acceptance is not a crawl | Check the engine’s own report in a week |
Limits
Only participating engines read these requests, and acceptance proves nothing about a crawl.
This page describes the shape of the setup. No engine documentation was reachable while it was written. The response codes above are possible outcomes, not published behaviour.