IndexNow setup: key, first push, and how to read the response

IndexNow setup takes a key string, that key hosted as a text file, and one request per publish. Here is the whole path, plus the five response codes and what each one means.

Implementation7 min read1380 views
IndexNow setup: key, first push, and how to read the response

IndexNow is a one-line ping that tells participating search engines a URL was added, changed, or removed. Setting it up takes three things: a key string, that key hosted as a text file on your own host, and one HTTP request per publish. The whole path below is free, takes about twenty minutes, and works the same on a static site as on a CMS.

Read this first

This chapter assumes your page is already reachable and already in your sitemap. If you have not confirmed that, do it before you push anything — a ping for a URL that returns 404 is wasted. The three-step publishing routine in request indexing in Search Console covers that ground, and this chapter is the deep version of its third step.

Check one thing before you build anything: your CMS or CDN may already do this. WordPress, Shopify, Wix, Drupal, Joomla, PrestaShop, Typo3 and Umbraco all have native or plugin support listed on indexnow.org, and Cloudflare ships a native integration. If one of those is already on, you have nothing to build.

Which engines are actually listening

IndexNow is a shared protocol, so one request reaches every participant. The list of supporters is published on indexnow.org and it is short.

EngineOn the IndexNow list
Microsoft BingYes
YandexYes
NaverYes
Seznam.czYes
YepYes
GoogleNot listed

Bing is the one that pays for the rest. Its index is what ChatGPT search and Copilot draw on, so getting into Bing early is the shortest route into an AI answer's source pool. Google needs its own path, which is why the previous chapter has you do both.

Step 1 — make a key and host it

The key is how an engine confirms the submission came from someone who controls the host. It is a string you invent, and the rules on it are narrow: 8 to 128 characters, using only a-z, A-Z, 0-9 and hyphens. A UUID with the braces stripped satisfies all of that and is easy to regenerate.

KEY=$(uuidgen | tr 'A-Z' 'a-z' | tr -d '{}')
echo -n "$KEY" > public/$KEY.txt
echo "https://example.com/$KEY.txt"

The file must be UTF-8, must be named after the key, and must contain the key and nothing else. Deploy it, then open the URL in a browser. If it does not return the key as plain text, stop here — every later step will fail with a 403 and the message will not tell you why.

You can also host the file somewhere other than the root, but then the key only covers URLs under that folder. A key at /catalog/key.txt can submit /catalog/anything and cannot submit /help/anything. Root placement avoids the whole question.

One thing people get backwards here: the key is not a secret in the sense an API token is. You are required to publish it at a URL anyone can read, because that public file is the proof of control. Committing it to your repository is fine. What matters is that the file and the value you send stay in sync — if you rotate one and forget the other, submissions fail closed rather than falling back.

Step 2 — submit one URL by hand

Before automating, prove the wiring with a single GET. This is the form the protocol documents for one URL at a time.

curl -s -o /dev/null -w '%{http_code}\n' \
  "https://api.indexnow.org/indexnow?url=https://example.com/your-page&key=$KEY"

A 200 here means the key file was found and read. It does not mean the page will be indexed. Keep that distinction — the protocol documentation states outright that 200 only indicates the engine received your URL.

Step 3 — switch to the batch endpoint

One URL per request is fine for a manual test and wrong for a publishing pipeline. The batch form takes up to 10,000 URLs in a single POST, which is more than most sites will ever need in one push.

POST /indexnow HTTP/1.1
Host: api.indexnow.org
Content-Type: application/json; charset=utf-8

{
  "host": "example.com",
  "key": "your-key",
  "keyLocation": "https://example.com/your-key.txt",
  "urlList": [
    "https://example.com/page-a",
    "https://example.com/page-b"
  ]
}

The host value has to match the host of every URL in the list. Mixing two hostnames in one payload is the single most common reason a batch that looks fine comes back 422.

Reading the response codes

Five codes cover everything the endpoint returns, and each one points at a different mistake. This table is the part of the chapter worth keeping open while you build.

CodeMeaningWhat to fix
200ReceivedNothing. Received, not indexed
400Bad requestMalformed JSON or bad URL encoding
403Key not validKey file missing, or file found but key not inside it
422UnprocessableA URL does not belong to the host, or the key breaks the format rules
429Too many requestsThrottle your pushes; you are being read as spam

403 is where almost every first attempt lands, and it has exactly two causes: the file is not where you said it was, or the file is there and the key inside does not match what you sent. Fetch the key file with curl and diff it against the value in your script before changing anything else. A 422 on a batch that worked as a single URL points at the host field, not at the key.

The deliverable: a push you can drop into your publish step

Take this, change two lines, and run it at the end of whatever publishes your content. It reads your sitemap, pushes everything in one batch, and prints the code so a failure is visible instead of silent.

#!/usr/bin/env bash
set -euo pipefail
HOST="example.com"
KEY="your-key"

URLS=$(curl -s "https://$HOST/sitemap.xml" \
  | grep -o '<loc>[^<]*</loc>' \
  | sed 's/<[^>]*>//g' \
  | python3 -c 'import json,sys; print(json.dumps([l.strip() for l in sys.stdin if l.strip()]))')

curl -s -o /dev/null -w 'indexnow: %{http_code}\n' \
  -X POST "https://api.indexnow.org/indexnow" \
  -H 'Content-Type: application/json; charset=utf-8' \
  -d "{\"host\":\"$HOST\",\"key\":\"$KEY\",\"keyLocation\":\"https://$HOST/$KEY.txt\",\"urlList\":$URLS}"

Two habits make this hold up over time. Log what you pushed and when, so a repeat push can be skipped rather than repeated. And push on change, not on schedule — a nightly push of an unchanged sitemap is what earns a 429.

Three ways an IndexNow setup goes wrong

All three return a code you can see, which is why the response table above is the thing to check first.

  1. The key file is served with the wrong content type or an extra newline. It still looks right in a browser. Fetch it with curl and compare byte for byte.
  2. The push runs before the deploy finishes. The engine arrives at a URL your host has not published yet, and the ping is spent on a 404.
  3. Every build pushes the whole sitemap. Nothing breaks at first, then submissions start returning 429 and the useful pushes are lost with the noise.

What IndexNow will not do

It will not get a page indexed. It moves discovery earlier; the engine still decides whether the page is worth keeping, and a thin page discovered faster is still a thin page. It does not reach Google, which is not on the participant list, so it never replaces the Search Console side of your routine.

We also cannot tell you how much earlier it lands. Measuring that properly needs a control group of unpushed URLs tracked over weeks, and we have not run that test on our own sites yet. Anyone quoting you a specific number of hours saved should be asked what their control group was.

What IndexNow is worth checking against is the rest of the pipeline. If your sitemap is stamping every URL with the build time, pushing harder does not fix the signal you are sending — our sitemap lastmod survey found 13 of 24 sites in that state. QueryWin is being built to check that whole chain rather than one endpoint.

Common questions

Does IndexNow work for Google?

Google is not among the supporters listed on indexnow.org. We have not tested whether Google reads these submissions through any other route, so we will not claim either way.

How often can I submit?

The protocol sets no published hourly limit, but 429 exists precisely for over-submission. The official guidance for user-generated content is to taper: every item up to 20, then every fifth up to 100, then every tenth up to 1,000.

Do I need Bing Webmaster Tools?

Not to submit. You need it to verify — it is where you can see whether your URLs were received, and it is the only free confirmation the protocol has.

Can I change the key later?

Yes. Host the new key file, switch the value in your script, and keep the old file up for a while. Engines re-read the key file when you submit, so there is no registration step to redo.

Part of the QueryWin handbook · Level 2

IndexNow setup: key, first push, and how to read the response