---
title: "Use IndexNow with Nuxt AI Ready"
description: "Add IndexNow URL submissions to a site that uses Nuxt AI Ready."
canonical_url: "https://nuxtseo.com/docs/ai-ready/guides/indexnow"
last_updated: "2026-09-05T14:06:05.456Z"
---

Nuxt AI Ready does not submit URLs to IndexNow.

Use this recipe if your Nuxt site already uses Nuxt AI Ready. Read the [IndexNow guide](/learn-seo/nuxt/launch-and-listen/indexnow) first if you need an overview.

Your CMS or host may already submit URLs. If it does, you are done. If not, add this code to your site.

## Generate a Key

Create a 32-character key:

```bash
openssl rand -hex 16
```

Set `NUXT_INDEX_NOW_KEY`{lang="bash"} to the result in your deployment environment.

Add the matching runtime config field and your production URL:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  runtimeConfig: {
    indexNowKey: '',
  },
  site: {
    url: 'https://example.com',
  },
})
```

## Publish the Key

IndexNow checks a public text file before it accepts submissions. Add this route:

```ts [server/routes/indexnow-key.txt.get.ts]
export default defineEventHandler((event) => {
  const { indexNowKey } = useRuntimeConfig(event)

  if (!indexNowKey) {
    throw createError({
      statusCode: 500,
      statusMessage: 'IndexNow key is not configured.',
    })
  }

  setResponseHeader(event, 'Content-Type', 'text/plain; charset=utf-8')
  return indexNowKey
})
```

Deploy the route before sending URLs. Check that `https://example.com/indexnow-key.txt` returns only your key.

## Submit Changed URLs

Keep the submission code in a server utility:

```ts [server/utils/indexnow.ts]
import type { H3Event } from 'h3'

const INDEX_NOW_ENDPOINT = 'https://api.indexnow.org/indexnow'
const INDEX_NOW_LIMIT = 10_000

export async function submitIndexNow(event: H3Event, paths: string[]) {
  if (paths.length === 0)
    return

  const { indexNowKey } = useRuntimeConfig(event)
  if (!indexNowKey)
    throw new Error('IndexNow key is not configured.')

  const site = new URL(getSiteConfig(event).url)
  const urls = paths.map((path) => {
    const url = new URL(path, `${site.origin}/`)

    if (url.origin !== site.origin)
      throw new Error(`IndexNow URL must use ${site.origin}.`)

    url.hash = ''
    return url.href
  })
  const urlList = [...new Set(urls)]

  if (urlList.length > INDEX_NOW_LIMIT)
    throw new Error(`IndexNow accepts at most ${INDEX_NOW_LIMIT} URLs per request.`)

  await $fetch(INDEX_NOW_ENDPOINT, {
    method: 'POST',
    body: {
      host: site.host,
      key: indexNowKey,
      keyLocation: new URL('/indexnow-key.txt', site).href,
      urlList,
    },
  })
}
```

The utility rejects URLs from another host. Call it after the changed URLs are live:

```ts
await submitIndexNow(event, [
  '/articles/new-page',
  '/articles/updated-page',
  '/articles/deleted-page',
])
```

Send only added, updated, or deleted URLs.

The function waits for IndexNow. If a failed submission must not fail publishing, call it from a retryable job.

## Static Sites

A static site cannot run these server files. Put the same key in `public/indexnow-key.txt`{lang="text"}.

Send the POST request from a post-deployment job. Follow the official [IndexNow request format](https://www.indexnow.org/documentation).

## Responses

IndexNow accepts up to 10,000 URLs per request. This utility rejects a larger batch.

Both HTTP `200` and `202` mean accepted. Retry `429` responses with backoff.

See the [IndexNow FAQ](https://www.indexnow.org/faq) for status codes and troubleshooting.