Dynamic URL Endpoints · Nuxt Sitemap · Nuxt SEO

[NuxtSEO](https://nuxtseo.com/ "Home")

- [Modules](https://nuxtseo.com/docs/nuxt-seo/getting-started/introduction)
- [Tools](https://nuxtseo.com/tools)
- [Pro](https://nuxtseo.com/pro)
- [Learn SEO](https://nuxtseo.com/learn-seo/nuxt) [Releases](https://nuxtseo.com/releases)

[1.4K](https://github.com/harlan-zw/nuxt-seo)

[Nuxt SEO on GitHub](https://github.com/harlan-zw/nuxt-seo)

[User Guides](https://nuxtseo.com/docs/sitemap/getting-started/introduction)

[API](https://nuxtseo.com/docs/sitemap/api/config)

[Releases](https://nuxtseo.com/docs/sitemap/releases/v8)

Sitemap

- [Switch to Sitemap](https://nuxtseo.com/docs/sitemap/getting-started/introduction)
- [Switch to Nuxt SEO](https://nuxtseo.com/docs/nuxt-seo/getting-started/introduction)
- [Switch to Robots](https://nuxtseo.com/docs/robots/getting-started/introduction)
- [Switch to OG Image](https://nuxtseo.com/docs/og-image/getting-started/introduction)
- [Switch to Schema.org](https://nuxtseo.com/docs/schema-org/getting-started/introduction)
- [Switch to Link Checker](https://nuxtseo.com/docs/link-checker/getting-started/introduction)
- [Switch to SEO Utils](https://nuxtseo.com/docs/seo-utils/getting-started/introduction)
- [Switch to Site Config](https://nuxtseo.com/docs/site-config/getting-started/introduction)
- [Switch to Skew Protection](https://nuxtseo.com/docs/skew-protection/getting-started/introduction)
- [Switch to AI Ready](https://nuxtseo.com/docs/ai-ready/getting-started/introduction)

Search…```k`` /`

v8.0.13

- Playgrounds
- [Discord Support](https://discord.com/invite/275MBUBvgP)

### Getting Started

- [Introduction](https://nuxtseo.com/docs/sitemap/getting-started/introduction)
- [Installation](https://nuxtseo.com/docs/sitemap/getting-started/installation)
- [Data Sources](https://nuxtseo.com/docs/sitemap/getting-started/data-sources)
- [Troubleshooting](https://nuxtseo.com/docs/sitemap/getting-started/troubleshooting)

### Core Concepts

- [Dynamic URL Endpoints](https://nuxtseo.com/docs/sitemap/guides/dynamic-urls)
- [Disabling Indexing](https://nuxtseo.com/docs/sitemap/guides/filtering-urls)
- [Multi Sitemaps](https://nuxtseo.com/docs/sitemap/guides/multi-sitemaps)
- [I18n](https://nuxtseo.com/docs/sitemap/guides/i18n)
- [Nuxt Content](https://nuxtseo.com/docs/sitemap/guides/content)
- [Nuxt Prerendering](https://nuxtseo.com/docs/sitemap/guides/prerendering)
- [Best Practices](https://nuxtseo.com/docs/sitemap/guides/best-practices)
- [Submitting Your Sitemap](https://nuxtseo.com/docs/sitemap/guides/submitting-sitemap)
- [Zero Runtime](https://nuxtseo.com/docs/sitemap/guides/zero-runtime)

### Advanced

- [Lastmod, Priority, and Changefreq](https://nuxtseo.com/docs/sitemap/advanced/loc-data)
- [Images, Videos, News](https://nuxtseo.com/docs/sitemap/advanced/images-videos)
- [Sitemap Performance](https://nuxtseo.com/docs/sitemap/advanced/performance)
- [Sitemap Chunking](https://nuxtseo.com/docs/sitemap/advanced/chunking-sources)
- [Customising the UI](https://nuxtseo.com/docs/sitemap/advanced/customising-ui)

Core Concepts

# Dynamic URL Endpoints

[Copy for LLMs](https://nuxtseo.com/docs/sitemap/guides/dynamic-urls.md)

## [Introduction](#introduction)

When working with a CMS or external data sources, you may need to generate sitemap URLs dynamically at runtime.

The module supports two types of data sources:

- JSON responses from API endpoints
- XML sitemaps from external sources

## [URL Structure Reference](#url-structure-reference)

All sitemap URLs follow this structure, whether from JSON endpoints or the `urls` config:

```
interface SitemapUrl {
  loc: string // Required: The URL path (e.g., '/blog/my-post')
  lastmod?: string | Date // Optional: Last modified date (ISO 8601 format or Date object)
  changefreq?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never'
  priority?: 0 | 0.1 | 0.2 | 0.3 | 0.4 | 0.5 | 0.6 | 0.7 | 0.8 | 0.9 | 1 // Optional: 0.0 to 1.0
  images?: ImageEntry[] // Optional: Array of image objects
  videos?: VideoEntry[] // Optional: Array of video objects
  news?: GoogleNewsEntry // Optional: Google News entry
  _sitemap?: string // Optional: Specify which sitemap this URL belongs to (for multi-sitemap setups)
  _encoded?: boolean // Optional: Mark the URL as already encoded
  _i18nTransform?: boolean // Optional: Automatically transform the URL for all locales
  alternatives?: Array<{ // Optional: For i18n/alternate language URLs
    hreflang: string // Language code (e.g., 'en', 'fr', 'es')
    href: string // Full URL to alternative version
  }>
}
```

## [Using External XML Sitemaps](#using-external-xml-sitemaps)

If you have an existing XML sitemap, you can reference it directly in your configuration:

nuxt.config.ts

```
export default defineNuxtConfig({
  sitemap: {
    sources: [
      'https://example.com/sitemap.xml',
    ]
  }
})
```

## [Dynamic URLs from External APIs](#dynamic-urls-from-external-apis)

When fetching dynamic URLs from external APIs, you have two main approaches:

1. **Direct source configuration** - Use when the API returns data in the correct format
2. **Custom API endpoint** - Use when you need to transform data or implement caching

### [1. Using Source Configuration](#_1-using-source-configuration)

For APIs that require authentication or custom headers, provide sources as an array with fetch options:

nuxt.config.ts

```
export default defineNuxtConfig({
  sitemap: {
    sources: [
      // Unauthenticated endpoint
      'https://api.example.com/pages/urls',
      // Authenticated endpoint
      [
        'https://authenticated-api.example.com/pages/urls',
        { headers: { Authorization: 'Bearer <token>' } }
      ]
    ]
  }
})
```

### [2. Creating Custom Endpoints](#_2-creating-custom-endpoints)

**Step 1: Create the API endpoint**

Use the [`defineSitemapEventHandler()`](https://nuxtseo.com/docs/sitemap/nitro-api/nitro-hooks) helper to create type-safe sitemap endpoints:

Simple

Multiple Sitemaps

WordPress Example

Dynamic i18n

```
import type { SitemapUrlInput } from '#sitemap/types'
// server/api/__sitemap__/urls.ts
import { defineSitemapEventHandler } from '#imports'

export default defineSitemapEventHandler(() => {
  return [
    {
      loc: '/about-us',
      // Specify which sitemap this URL belongs to
      _sitemap: 'pages',
    },
  ] satisfies SitemapUrlInput[]
})
```

```
import type { SitemapUrl } from '#sitemap/types'
// server/api/__sitemap__/urls.ts
import { defineSitemapEventHandler } from '#imports'

export default defineSitemapEventHandler(async () => {
  const [posts, pages] = await Promise.all([
    $fetch<{ path: string, slug: string }[]>('https://api.example.com/posts')
      .then(posts => posts.map(p => ({
        loc: \`/blog/${p.slug}\`, // Transform to your domain structure
        _sitemap: 'posts',
      } satisfies SitemapUrl))),
    $fetch<{ path: string }[]>('https://api.example.com/pages')
      .then(pages => pages.map(p => ({
        loc: p.path,
        _sitemap: 'pages',
      } satisfies SitemapUrl))),
  ])
  return [...posts, ...pages]
})
```

```
// server/api/__sitemap__/wordpress.ts
import { defineSitemapEventHandler } from '#imports'

export default defineSitemapEventHandler(async () => {
  const posts = await $fetch('https://api.externalwebsite.com/wp-json/wp/v2/posts')

  return posts.map(post => ({
    // Transform external URL to your domain
    loc: \`/blog/${post.slug}\`, // NOT post.link
    lastmod: post.modified,
    changefreq: 'weekly',
    priority: 0.7,
  }))
})
```

```
import type { SitemapUrl } from '#sitemap/types'
// server/api/__sitemap__/urls.ts
import { defineSitemapEventHandler } from '#imports'

export default defineSitemapEventHandler(async () => {
  const config = useRuntimeConfig()
  const baseUrl = config.public.siteUrl
  const locales = config.public.i18n.locales.map(locale => locale.code)
  const isoLocales = Object.fromEntries(
    config.public.i18n.locales.map(locale => ([locale.code, locale.iso]))
  )

  // Example: Fetch data for each locale
  const apiQueries = locales.map(locale =>
    $fetch(\`${config.public.apiEndpoint}/sitemap/${locale}/products\`)
  )

  const sitemaps = await Promise.all(apiQueries)

  return sitemaps.flat().map(entry => ({
    // explicit sitemap mapping
    _sitemap: isoLocales[entry.locale],
    loc: \`${baseUrl}/${entry.locale}/product/${entry.url}\`,
    alternatives: entry.alternates?.map(alt => ({
      hreflang: isoLocales[alt.locale],
      href: \`${baseUrl}/${alt.locale}/product/${alt.url}\`
    }))
  } satisfies SitemapUrl))
})
```

**Step 2: Configure the endpoint**

Add your custom endpoint to the sitemap configuration:

Single Sitemap

Multiple Sitemaps

```
export default defineNuxtConfig({
  sitemap: {
    sources: [
      '/api/__sitemap__/urls',
    ]
  }
})
```

```
export default defineNuxtConfig({
  sitemap: {
    sitemaps: {
      posts: {
        sources: [
          '/api/__sitemap__/urls/posts',
        ]
      },
      pages: {
        sources: [
          '/api/__sitemap__/urls/pages',
        ]
      }
    }
  }
})
```

## [Handling Pre-Encoded URLs](#handling-pre-encoded-urls)

By default, the module automatically encodes URL paths. This handles special characters like spaces and unicode (e.g., emojis, accented characters).

If your API or CMS returns URLs that are already encoded, mark them with `_encoded: true` to prevent double-encoding.

server/api/__sitemap__/urls.ts

```
import { defineSitemapEventHandler } from '#imports'

export default defineSitemapEventHandler(async () => {
  // URLs from your API are already encoded
  const urls = await $fetch<{ path: string }[]>('https://api.example.com/pages')
  // e.g. [{ path: '/products/%24pecial-offer' }, { path: '/blog/%F0%9F%98%85' }]

  return urls.map(url => ({
    loc: url.path,
    _encoded: true,
  }))
})
```

When `_encoded: true` is set, the module skips automatic encoding entirely. Make sure your URLs are properly encoded.

[Edit this page](https://github.com/nuxt-modules/sitemap/edit/main/docs/content/1.guides/0.dynamic-urls.md)

[Markdown For LLMs](https://nuxtseo.com/docs/sitemap/guides/dynamic-urls.md)

Did this page help you?

### Related

[Data Sources](https://nuxtseo.com/docs/sitemap/getting-started/data-sources) [I18n Integration](https://nuxtseo.com/docs/sitemap/guides/i18n) [Multi Sitemaps](https://nuxtseo.com/docs/sitemap/guides/multi-sitemaps)

[Troubleshooting Common issues and debugging tips for Nuxt Sitemap.](https://nuxtseo.com/docs/sitemap/getting-started/troubleshooting) [Disabling Indexing How to filter the URLs generated from application sources.](https://nuxtseo.com/docs/sitemap/guides/filtering-urls)

On this page

- [Introduction](#introduction)
- [URL Structure Reference](#url-structure-reference)
- [Using External XML Sitemaps](#using-external-xml-sitemaps)
- [Dynamic URLs from External APIs](#dynamic-urls-from-external-apis)
- [Handling Pre-Encoded URLs](#handling-pre-encoded-urls)

[GitHub](https://github.com/harlan-zw/nuxt-seo) [ Discord](https://discord.com/invite/275MBUBvgP)

### [NuxtSEO](https://nuxtseo.com/ "Home")

- [Getting Started](https://nuxtseo.com/docs/nuxt-seo/getting-started/introduction)
- [MCP](https://nuxtseo.com/docs/nuxt-seo/guides/mcp)

Modules

- [Robots](https://nuxtseo.com/docs/robots/getting-started/introduction)
- [Sitemap](https://nuxtseo.com/docs/sitemap/getting-started/introduction)
- [OG Image](https://nuxtseo.com/docs/og-image/getting-started/introduction)
- [Schema.org](https://nuxtseo.com/docs/schema-org/getting-started/introduction)
- [Link Checker](https://nuxtseo.com/docs/link-checker/getting-started/introduction)
- [SEO Utils](https://nuxtseo.com/docs/seo-utils/getting-started/introduction)
- [Site Config](https://nuxtseo.com/docs/site-config/getting-started/introduction)
- [Skew Protection](https://nuxtseo.com/docs/skew-protection/getting-started/introduction)
- [AI Ready](https://nuxtseo.com/docs/ai-ready/getting-started/introduction)

### [NuxtSEO Pro](https://nuxtseo.com/pro "Nuxt SEO Pro")

- [Getting Started](https://nuxtseo.com/pro)
- [Dashboard](https://nuxtseo.com/pro/dashboard)
- [Pro MCP](https://nuxtseo.com/pro/docs/getting-started/mcp-setup)

### [Learn SEO](https://nuxtseo.com/learn-seo "Learn SEO")

Nuxt

- [Mastering Meta](https://nuxtseo.com/learn-seo/nuxt/mastering-meta)
- [Controlling Crawlers](https://nuxtseo.com/learn-seo/nuxt/controlling-crawlers)
- [Launch & Listen](https://nuxtseo.com/learn-seo/nuxt/launch-and-listen)
- [Routes & Rendering](https://nuxtseo.com/learn-seo/nuxt/routes-and-rendering)
- [Staying Secure](https://nuxtseo.com/learn-seo/nuxt/routes-and-rendering/security)

Vue

- [Vue SEO Guide](https://nuxtseo.com/learn-seo/vue)
- [Mastering Meta](https://nuxtseo.com/learn-seo/vue/mastering-meta)
- [Controlling Crawlers](https://nuxtseo.com/learn-seo/vue/controlling-crawlers)
- [SPA SEO](https://nuxtseo.com/learn-seo/vue/spa)
- [SSR Frameworks](https://nuxtseo.com/learn-seo/vue/ssr-frameworks)
- [SEO Checklist](https://nuxtseo.com/learn-seo/checklist)
- [Pre-Launch Warmup](https://nuxtseo.com/learn-seo/pre-launch-warmup)
- [Backlinks & Authority](https://nuxtseo.com/learn-seo/backlinks)

### [Tools](https://nuxtseo.com/tools "SEO Tools")

- [Social Share Debugger](https://nuxtseo.com/tools/social-share-debugger)
- [Robots.txt Generator](https://nuxtseo.com/tools/robots-txt-generator)
- [Meta Tag Checker](https://nuxtseo.com/tools/meta-tag-checker)
- [HTML to Markdown](https://nuxtseo.com/tools/html-to-markdown)
- [XML Sitemap Validator](https://nuxtseo.com/tools/xml-sitemap-validator)
- [Schema.org Validator](https://nuxtseo.com/tools/schema-validator)
- [Keyword Idea Generator](https://nuxtseo.com/tools/keyword-generator)
- [Keyword Research](https://nuxtseo.com/tools/keyword-research)
- [SERP Analyzer](https://nuxtseo.com/tools/serp-analyzer)
- [Domain Rankings](https://nuxtseo.com/tools/domain-rankings)

Copyright © 2023-2026 Harlan Wilton - [MIT License](https://github.com/harlan-zw/nuxt-seo/blob/main/license) · [mdream](https://mdream.dev)