All guidesAI visibility and the agentic web

IndexNow: Instant Search Engine Notification

IndexNow is a free protocol that lets you instantly notify Bing, Yandex, Seznam, and Naver when you publish or update content. Instead of waiting days or weeks for search engines to discover your changes, IndexNow pushes a notification that triggers crawling within minutes. Implementation requires generating a verification key, hosting it as a text file, and calling a single API endpoint.

By Paul Gosnell Updated March 2026 12 min read

p0stman builds for the agentic web. AgentReady scans your site for llms.txt, structured data and crawler access in under a minute, free.

Traditional search engine crawling works on the search engine's schedule, not yours. You publish a new page, submit your sitemap, and wait. Googlebot might visit in hours. Bingbot might take days. Smaller engines could take weeks. During this gap, your content is invisible to search traffic.

IndexNow inverts this model. Instead of waiting for crawlers to discover your content, you tell them it exists the moment you publish it. The protocol was created by Microsoft and Yandex in 2021 and has since been adopted by Seznam.cz and Naver. When you submit a URL to any one IndexNow endpoint, all participating search engines are notified simultaneously.

This guide covers everything you need to implement IndexNow: how the protocol works, which search engines support it, generating and hosting your verification key, building a Next.js API route for single and bulk URL submission, triggering IndexNow automatically on content publish, integrating with Vercel deployments, and monitoring submission success. Use the AgentReady scanner to check whether your site has IndexNow configured.

What is IndexNow?

IndexNow is an open protocol that allows website owners to notify search engines about URL changes instantly. It is a simple HTTP GET or POST request that says: "This URL has been created, updated, or deleted. Please re-crawl it."

The protocol requires two things from your end:

  1. A verification key hosted as a text file at your domain root, proving you own the site.
  2. An API call to the IndexNow endpoint with the URL and your key.

That is it. No OAuth, no API keys to manage, no rate limit tokens. The protocol is deliberately simple.

Which search engines support IndexNow?

Search Engine IndexNow Support Endpoint Market Share
Bing Yes (co-creator) api.indexnow.org ~3% global, ~10% US desktop
Yandex Yes (co-creator) yandex.com/indexnow ~1% global, ~60% Russia
Seznam.cz Yes seznam.cz/indexnow ~25% Czech Republic
Naver Yes searchadvisor.naver.com/indexnow ~55% South Korea
Google No N/A ~90% global

The key benefit of IndexNow is that submitting to any one endpoint notifies all participating engines. You only need to call api.indexnow.org once, and Bing, Yandex, Seznam, and Naver all receive the notification.

Why Bing matters more than you think

Many developers dismiss Bing as irrelevant because Google dominates global search. But Bing powers several important surfaces:

  • Microsoft Copilot uses Bing's index for grounding and real-time search.
  • ChatGPT with browsing historically used Bing for web search (via ChatGPT-User).
  • DuckDuckGo sources its web results primarily from Bing's index.
  • Yahoo Search is powered by Bing.
  • Ecosia, Qwant, and other privacy-focused search engines use Bing as their backend.

By indexing quickly on Bing via IndexNow, your content becomes available across all of these surfaces, including AI-powered ones.

Generating and hosting your verification key

The verification key proves to IndexNow that you own the domain you are submitting URLs for. It is a simple string that you host as a text file at your domain root.

Step 1: Generate a key

The key can be any string of 8-128 characters containing only a-z, A-Z, 0-9, and -. A 32-character hex string is the common convention:

# Generate a random 32-character hex key
node -e "console.log(require('crypto').randomBytes(16).toString('hex'))"

# Example output: a969caaa7704f6a6b5532c5a89159e6a

Step 2: Host the key file

Create a text file at public/<your-key>.txt containing just the key value:

# For a Next.js project
echo "a969caaa7704f6a6b5532c5a89159e6a" > public/a969caaa7704f6a6b5532c5a89159e6a.txt

After deployment, the file must be accessible at https://yourdomain.com/a969caaa7704f6a6b5532c5a89159e6a.txt. The IndexNow endpoint validates ownership by fetching this file.

Step 3: Store the key as an environment variable

Add the key to your environment variables so your API route can reference it without hardcoding:

# .env.local
INDEXNOW_KEY=a969caaa7704f6a6b5532c5a89159e6a

Add INDEXNOW_KEY to your Vercel environment variables for production.

Next.js API route implementation

Create an API route that accepts URLs and submits them to the IndexNow endpoint. This route serves as an internal endpoint that your content management workflows can call.

Single URL submission

// app/api/indexnow/route.ts
import { NextRequest, NextResponse } from "next/server";

const INDEXNOW_KEY = process.env.INDEXNOW_KEY || "";
const SITE_HOST = "yourdomain.com";

export async function POST(req: NextRequest) {
  try {
    const { url, urls } = await req.json();

    // Validate input
    if (!url && (!urls || !Array.isArray(urls) || urls.length === 0)) {
      return NextResponse.json(
        { error: "Provide a 'url' string or 'urls' array" },
        { status: 400 }
      );
    }

    if (!INDEXNOW_KEY) {
      return NextResponse.json(
        { error: "INDEXNOW_KEY not configured" },
        { status: 500 }
      );
    }

    // Single URL submission via GET
    if (url && !urls) {
      const indexNowUrl = new URL("https://api.indexnow.org/indexnow");
      indexNowUrl.searchParams.set("url", url);
      indexNowUrl.searchParams.set("key", INDEXNOW_KEY);

      const response = await fetch(indexNowUrl.toString());

      return NextResponse.json({
        success: response.ok,
        status: response.status,
        submitted: url,
      });
    }

    // Bulk URL submission via POST
    const urlList = urls || [url];

    const response = await fetch("https://api.indexnow.org/indexnow", {
      method: "POST",
      headers: { "Content-Type": "application/json; charset=utf-8" },
      body: JSON.stringify({
        host: SITE_HOST,
        key: INDEXNOW_KEY,
        keyLocation: `https://${SITE_HOST}/${INDEXNOW_KEY}.txt`,
        urlList: urlList,
      }),
    });

    return NextResponse.json({
      success: response.ok,
      status: response.status,
      submitted: urlList.length,
      urls: urlList,
    });
  } catch (error) {
    return NextResponse.json(
      { error: "IndexNow submission failed" },
      { status: 500 }
    );
  }
}

Understanding the IndexNow response codes

Status Code Meaning
200 URL submitted successfully
202 URL accepted, will be processed later
400 Invalid request (bad URL format, missing key)
403 Key validation failed (key file not found or does not match)
422 URL does not belong to the host
429 Too many requests (rate limited)

Both 200 and 202 mean success. The search engine will crawl the submitted URL. A 202 means it has been queued for processing rather than processed immediately.

Bulk URL submission

IndexNow supports submitting up to 10,000 URLs in a single POST request. This is ideal for batch operations like publishing multiple pages, running a site-wide content update, or re-indexing after a redesign.

Bulk submission format

// POST to https://api.indexnow.org/indexnow
{
  "host": "yourdomain.com",
  "key": "a969caaa7704f6a6b5532c5a89159e6a",
  "keyLocation": "https://yourdomain.com/a969caaa7704f6a6b5532c5a89159e6a.txt",
  "urlList": [
    "https://yourdomain.com/guides/new-guide.html",
    "https://yourdomain.com/blog/updated-post",
    "https://yourdomain.com/products/new-product",
    "https://yourdomain.com/about"
  ]
}

Batch submission utility

For programmatic bulk submission, create a utility function you can call from anywhere in your application:

// lib/indexnow.ts
const INDEXNOW_KEY = process.env.INDEXNOW_KEY || "";
const SITE_HOST = process.env.NEXT_PUBLIC_SITE_URL
  ? new URL(process.env.NEXT_PUBLIC_SITE_URL).host
  : "yourdomain.com";

export async function submitToIndexNow(urls: string[]): Promise<{
  success: boolean;
  status: number;
}> {
  if (!INDEXNOW_KEY || urls.length === 0) {
    return { success: false, status: 0 };
  }

  try {
    const response = await fetch("https://api.indexnow.org/indexnow", {
      method: "POST",
      headers: {
        "Content-Type": "application/json; charset=utf-8",
      },
      body: JSON.stringify({
        host: SITE_HOST,
        key: INDEXNOW_KEY,
        keyLocation: `https://${SITE_HOST}/${INDEXNOW_KEY}.txt`,
        urlList: urls,
      }),
    });

    return {
      success: response.ok || response.status === 202,
      status: response.status,
    };
  } catch {
    return { success: false, status: 0 };
  }
}

// Single URL helper
export async function notifyIndexNow(url: string) {
  return submitToIndexNow([url]);
}

Triggering IndexNow on content publish

The real power of IndexNow comes from automated integration with your content publishing workflow. Here are patterns for different scenarios.

Pattern 1: After saving content in a CMS API route

// app/api/content/publish/route.ts
import { NextRequest, NextResponse } from "next/server";
import { notifyIndexNow } from "@/lib/indexnow";

export async function POST(req: NextRequest) {
  const { title, slug, content } = await req.json();

  // Save content to database
  // await supabase.from("posts").insert({ title, slug, content });

  // Notify IndexNow (fire-and-forget, do not block on this)
  const pageUrl = `https://yourdomain.com/blog/${slug}`;
  notifyIndexNow(pageUrl).catch(() => {
    // Silent fail - IndexNow is best-effort
  });

  return NextResponse.json({ success: true, url: pageUrl });
}

Pattern 2: Vercel deployment webhook

Trigger IndexNow for all pages after a successful Vercel deployment. Create a webhook endpoint that Vercel calls post-deployment:

// app/api/deploy-hook/route.ts
import { NextRequest, NextResponse } from "next/server";
import { submitToIndexNow } from "@/lib/indexnow";

// List of important URLs to re-index on every deployment
const IMPORTANT_URLS = [
  "https://yourdomain.com/",
  "https://yourdomain.com/services",
  "https://yourdomain.com/about",
  "https://yourdomain.com/contact",
  "https://yourdomain.com/guides/",
  // Add your key pages here
];

export async function POST(req: NextRequest) {
  // Verify this is from Vercel (optional: check a secret header)
  const secret = req.headers.get("x-webhook-secret");
  if (secret !== process.env.DEPLOY_WEBHOOK_SECRET) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const result = await submitToIndexNow(IMPORTANT_URLS);

  return NextResponse.json({
    success: result.success,
    submitted: IMPORTANT_URLS.length,
  });
}

Pattern 3: Sitemap-based bulk submission

Parse your sitemap and submit all URLs. This is useful for initial setup or periodic re-submission:

// scripts/submit-sitemap-to-indexnow.ts
import { submitToIndexNow } from "@/lib/indexnow";

async function submitSitemap() {
  // Fetch and parse your sitemap
  const res = await fetch("https://yourdomain.com/sitemap.xml");
  const xml = await res.text();

  // Extract URLs (simple regex approach)
  const urls: string[] = [];
  const regex = /<loc>(.*?)<\/loc>/g;
  let match;
  while ((match = regex.exec(xml)) !== null) {
    urls.push(match[1]);
  }

  // Submit in batches of 10,000
  for (let i = 0; i < urls.length; i += 10000) {
    const batch = urls.slice(i, i + 10000);
    const result = await submitToIndexNow(batch);
    console.log(
      `Batch ${Math.floor(i / 10000) + 1}: ${result.status} ` +
      `(${batch.length} URLs)`
    );
  }
}

submitSitemap();

Testing your IndexNow implementation

Verify the key file is accessible

# Check that your key file is served correctly
curl https://yourdomain.com/a969caaa7704f6a6b5532c5a89159e6a.txt

# Should output just the key:
# a969caaa7704f6a6b5532c5a89159e6a

Submit a test URL

# Single URL submission via GET
curl "https://api.indexnow.org/indexnow?url=https://yourdomain.com/test-page&key=a969caaa7704f6a6b5532c5a89159e6a"

# Should return 200 or 202

Test your API route

# Submit via your API route
curl -X POST https://yourdomain.com/api/indexnow \
  -H "Content-Type: application/json" \
  -d '{"url": "https://yourdomain.com/guides/indexnow-guide.html"}'

# Bulk submission
curl -X POST https://yourdomain.com/api/indexnow \
  -H "Content-Type: application/json" \
  -d '{
    "urls": [
      "https://yourdomain.com/page-1",
      "https://yourdomain.com/page-2",
      "https://yourdomain.com/page-3"
    ]
  }'

Monitoring IndexNow submissions

Bing Webmaster Tools

Bing Webmaster Tools provides an IndexNow status dashboard that shows submitted URLs, processing status, and any errors. Verify your site in Bing Webmaster Tools at bing.com/webmasters and navigate to the IndexNow section to see submission history.

Logging submissions in your database

For your own analytics, log IndexNow submissions to a Supabase table:

-- Supabase migration
CREATE TABLE indexnow_submissions (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  url text NOT NULL,
  status_code integer,
  success boolean DEFAULT false,
  batch_id text,
  created_at timestamptz DEFAULT now()
);

CREATE INDEX idx_indexnow_created_at
  ON indexnow_submissions (created_at DESC);

Update your utility function to log submissions:

// In lib/indexnow.ts, after the fetch call:
// await supabase.from("indexnow_submissions").insert(
//   urls.map(url => ({
//     url,
//     status_code: response.status,
//     success: response.ok || response.status === 202,
//     batch_id: batchId,
//   }))
// );

IndexNow and the broader discovery layer

IndexNow is one piece of a comprehensive discovery strategy. It works alongside other discovery mechanisms to ensure your content reaches both traditional search engines and AI systems.

  • robots.txt controls which crawlers can access your site.
  • XML Sitemaps provide a complete URL inventory for crawlers to discover.
  • IndexNow actively pushes notifications when content changes.
  • llms.txt provides AI-specific content discovery.
  • Bot tracking helps you understand which crawlers are visiting and what they access.

Together, these mechanisms ensure maximum visibility across search engines and AI platforms.

Best practices

Only submit URLs that have actually changed

Do not submit your entire sitemap on every deployment. Only submit URLs where the content has actually been created or modified. Submitting unchanged URLs wastes quota and can reduce the priority search engines assign to your future submissions.

Submit immediately after publishing

Call IndexNow as part of your publish workflow, not as a batch job that runs hours later. The sooner you notify, the sooner the content appears in search results.

Make IndexNow fire-and-forget

Never let IndexNow failures block your content publishing. Use .catch(() => {}) on the promise and move on. IndexNow is a speed optimisation, not a critical dependency. Search engines will discover your content through normal crawling even if IndexNow fails.

Include the keyLocation parameter

While technically optional, the keyLocation parameter tells search engines exactly where to find your key file, avoiding any ambiguity and speeding up verification.

Common issues and solutions

403 error: key validation failed

Cause: The key file at https://yourdomain.com/<key>.txt is not accessible or does not contain the correct key value.

Fix: Verify the file exists at the correct URL, contains only the key (no extra whitespace or newlines), and is served with a text/plain content type.

422 error: URL does not belong to host

Cause: The URL you submitted does not match the host associated with the key.

Fix: Make sure the URL domain matches the domain where your key file is hosted. You cannot use one key to submit URLs for a different domain.

Key file not served on Vercel

Cause: Next.js or Vercel's routing is interfering with the .txt file.

Fix: Place the file in the public/ directory. Vercel serves files from public/ as static assets. Verify the file is included in your deployment by checking https://yourdomain.com/<key>.txt after deploying.

Frequently Asked Questions

What is IndexNow and which search engines support it?

IndexNow is a protocol that lets website owners instantly notify search engines when content is created, updated, or deleted. It is supported by Bing, Yandex, Seznam.cz, and Naver. When you ping one IndexNow endpoint, all participating search engines are notified. Google does not support IndexNow but has its own Indexing API for specific structured data types.

Does Google support IndexNow?

No. Google does not support the IndexNow protocol. Google relies on its own crawling infrastructure, Sitemaps, and the Google Indexing API (which is limited to JobPosting and BroadcastEvent structured data). However, submitting to IndexNow still provides significant value through Bing, Yandex, Seznam, and Naver, as well as all services powered by Bing's index including Microsoft Copilot and DuckDuckGo.

How do I generate an IndexNow verification key?

Generate a unique key string of 8 to 128 characters containing letters, numbers, and hyphens. A 32-character hex string is the common convention. Use node -e "console.log(require('crypto').randomBytes(16).toString('hex'))" to generate one. Save the key as a text file at public/<key>.txt and reference it in your API calls.

Can I submit multiple URLs at once with IndexNow?

Yes. IndexNow supports bulk submission via a POST request to the /indexnow endpoint with a JSON body containing a urlList array. You can submit up to 10,000 URLs per request. This is ideal for batch operations like publishing multiple pages or re-indexing after a site-wide content update.

How do I trigger IndexNow automatically when content is published?

Call your IndexNow API route from your content publishing workflow. In a CMS, add a webhook that fires on publish. In a Next.js app, call the IndexNow endpoint from your content creation API route after successfully saving the new content. Use fire-and-forget pattern so IndexNow does not block the publishing flow.

What happens if IndexNow submission fails?

IndexNow submission is best-effort. If it fails, the search engines will still discover your content through normal crawling and sitemap processing. Failed submissions do not harm your SEO. Implement retry logic with exponential backoff for reliability, but never let IndexNow failures block your content publishing flow.

How quickly does Bing index pages after IndexNow notification?

Bing typically processes IndexNow notifications within minutes to hours. New content can appear in Bing search results within 10 minutes of submission in ideal cases. This is dramatically faster than waiting for Bing's crawler to discover the page organically, which can take days or weeks.

Is IndexNow free to use?

Yes. IndexNow is completely free and open. There are no API keys to purchase, no rate limits to worry about for normal usage, and no cost per submission. The protocol was created by Microsoft and Yandex and is designed to be universally accessible to all website owners.

Related Guides

Paul Gosnell, founder of p0stman

Paul Gosnell · Founder, p0stman

Want to know how AI agents see your site?

AgentReady checks your site for the signals in this guide and tells you exactly what to fix. Free, no signup, results in under a minute.

Scan your site Free scan. No signup.