Localized Sitemap Astro Storyblok

Generate localized sitemaps for your Astro and Storyblok project

Seppe Gadeyne

Freelance web developer

In this article, I will guide you through creating localized sitemaps for your Astro and Storyblok projects. We will cover fetching content from Storyblok, creating a sitemap endpoint, and generating the sitemap XML.

Localized Sitemap Astro Storyblok
Generate localized sitemaps for your Astro and Storyblok project


  1. Prerequisites

  2. Install dependencies

  3. Setting up environment variables

  4. Creating helper functions

  5. Creating the sitemap endpoint

  6. Conclusion


Before you can begin, ensure that you have the following prerequisites installed on your system:

You also need to have a Storyblok space with stories in it.

Install dependencies

We will incorporate the desired integrations into our project. Execute the following commands from within the Astro folder.

npm install storyblok-js-client

Setting up environment variables

First, set up a .env file in your Astro project with the following public variables that we will use in our functions:


Replace yourdomain.com and your-storyblok-api-token with your existing domain and Storyblok API token.

Creating helper functions

For this sitemap endpoint, we will need two JavaScript functions that make our lives easier when fetching multiple stories from Storyblok. You can use these functions in any other framework as well. To fetch data from the Storyblok API, we will use the universal JavaScript SDK for Storyblok's API. In our example, we save these two files in src/library.


This function gets the region code according to the full_slug from Storyblok. Remember to modify the locale and region to align with your requirements.

export function getLocale(slug = '') {
  let locale = 'en';

  if (slug.match(/^nl\//)) {
    locale = 'nl';

  return locale;


This client helps us fetch stories from Storyblok.

import StoryblokClient from 'storyblok-js-client';

export const sb = new StoryblokClient({
	accessToken: import.meta.env.STORYBLOK_TOKEN

export const defaultConfig = {
		import.meta.env.STORYBLOK_VERSION === 'draft' || import.meta.env.DEV
			? 'draft'
			: 'published'

Creating the sitemap endpoint

Now, make the sitemap endpoint in your src/pages folder, like sitemap-[language].xml.js, and add the following code:

// Import necessary functions
import { sb, defaultConfig } from '../library/sb';
import { getLocale } from '../library/getLocale';

// Define static paths for languages
export function getStaticPaths() {
  return [
    ['en', 'nl'].map((language) => ({
      params: {

// Fetch sitemap data for a specific language
export async function get({ params, site }) {
  // Fetch stories from the Storyblok API
  const data = await sb.getAll('cdn/stories', {
	starts_with: params.language === 'en' ? '' : `${params.language}/`,
		params.language === 'en' ? 'settings/*,templates/*,nl/*,voorbeeld' : 'settings/*,templates/*',

  // Initialize sitemap XML content
  let sitemap = `<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">`;

  // Iterate through each story and generate sitemap entries
  data.forEach((story) => {
	let xhtml = '';
	story.alternates.forEach((alternate) => {
		xhtml += `<xhtml:link rel="alternate" hreflang="${getLocale(
		)}" href="${site}${
			alternate.full_slug === 'home' ? '' : `${alternate.full_slug.replace(/\/$/, '')}`

	sitemap += `<url><loc>${site}${
		story.full_slug === 'home' ? '' : `${story.full_slug.replace(/\/$/, '')}`

  // Close the sitemap XML content
  sitemap += '</urlset>';

  // Return sitemap XML content with appropriate headers
  return {
    headers: {
      'Content-Type': 'application/xml',
    body: sitemap,


This tutorial shows you how to create a localized sitemap for your Astro project using Storyblok. Following the steps above, you can fetch content from Storyblok, create a sitemap endpoint, and generate the sitemap XML.

Your website will now benefit from a localized sitemap, making it easier for search engines to discover and index your content in different languages. Good luck, and happy coding!

Frequently asked questions


Let's dive deeper into some frequently asked questions.

Can I use this code with other headless CMS solutions?

Yes, you can adapt the code to work with other headless CMS solutions by modifying the Storyblok client to another one to fetch data from your preferred CMS API.

How can I add more languages to my sitemap?

To add more languages, update the getStaticPaths function to include the additional languages you want to support and update the getLocale function to handle the new language slugs.

Can I use this sitemap solution for non-multilingual websites?

Yes, you can use this solution for non-multilingual websites as well. Remove the language-specific code and adjust the content fetching from Storyblok to match your website's structure.

Do I need to submit my sitemap to search engines manually?

While search engines may discover your sitemap on their own, it's a good practice to submit your sitemap manually to major search engines like Google and Bing. This ensures they know your sitemap and can start indexing your content.

How often should I update my sitemap?

It's recommended to update your sitemap whenever you add, update, or remove content from your website. Since this solution generates the sitemap dynamically at build-time, it will always be up-to-date when search engines request it.

How can I exclude certain pages from my sitemap?

To exclude specific pages from your sitemap, update the sb.getAll() function call by adding the slugs you want to exclude to the excluding_slugs parameter when fetching data from Storyblok.