Generating dynamic sitemaps with Qwik City & Builder.io

A clever way of generating dynamic site maps in a Qwik City app with updated data from the builder.io content API is to use middleware. You can construct the site map using the data and send a response to the client as XML.

Create a new route called sitemap.

This will dynamically generate a sitemap of all your builder pages at 'https://base-url/sitemap'.

import { type RequestHandler } from "@builder.io/qwik-city";

export const onGet: RequestHandler = async (req) => {
  const data = await fetch(
    "https://cdn.builder.io/api/v2/content/page?apiKey=your-api-key&fields=data.url&query.data.includeInSitemap.$ne=false"
  );
  if (!data.ok) {
    throw req.error(404, "Error fetching content");
  }
  const res = await data.json();
  const pageUrls = res.results.map((page: any) => page.data.url);
  console.log(pageUrls);
  let sitemapXml =
    '<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n';
  pageUrls.forEach((url: string) => {
    sitemapXml += `<url><loc>https://YOUR-BASE-URL${url}</loc></url>\n`;
  });
  sitemapXml += "</urlset>";

  const response = new Response(sitemapXml, {
    status: 200,
    headers: {
      "Content-Type": "text/xml",
    },
  });
  console.log(response);
  req.send(response);
};

You could also create a dynamic route like 'sitemap/[slug]/index.tsx' to dynamically generate more than one site map.

import { type RequestHandler } from "@builder.io/qwik-city";
import { getContent } from "@builder.io/sdk-qwik";

const API_KEY = import.meta.env.PUBLIC_BUILDER_API_KEY;

export const onGet: RequestHandler = async (req) => {
  const slug = req.params.slug;
  console.log(slug);
  const entry = await getContent({
    model: "blog-article",
    apiKey: API_KEY,
    query: { "data.handle": slug },
    options: { includeRefs: true },
  });
  console.log(entry);
  let sitemapXml =
    '<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n';

  sitemapXml += `
    <url>
      <loc>https://YOUR-BASE_URL/blog/${slug}</loc>
      <lastmod>${new Date(entry?.data?.date).toISOString()}</lastmod>
      <changefreq>monthly</changefreq>
      <priority>0.8</priority>
    </url>\n`;

  sitemapXml += "</urlset>";

  const response = new Response(sitemapXml, {
    status: 200,
    headers: {
      "Content-Type": "text/xml",
    },
  });
  console.log(response);
  req.send(response);
};