Last week, I refactored parts of this website and broke the endpoint that creates this sitemap. I decided to read up on sitemaps the route. Here is what I learned.
Google’s take on sitemaps
Web developers often assume that Google might only index their site regularly with a sitemap. But is this true? In the Google Search Console docs, Google answers the question “Do I need a sitemap?” with “it depends”. Google recommends a sitemap when
- you launch a new site, and no or few external links point to your site or
- your site is large, and not all pages are linked and discoverable by Google’s crawler.
You do not need a sitemap if
- your site is small (up to 500 relevant pages) or
- your site is linked correctly, and Google can find all relevant pages by crawling it.
My website maier.tech is small, and all pages are discoverable by a crawler, so I would not need a sitemap. Yet, I submitted a sitemap in May 2021 as an initial SEO boost. You can see when Google last read a sitemap in the Google Search Console. For my site, it was almost two years ago:
Different types of sitemaps
Google supports different types of sitemaps. If your site already has an RSS feed, you can submit the feed URL as a sitemap and call it a day. But the most common sitemap type is XML. A simple XML sitemap that indexes only the homepage looks like this:
Every indexed page goes in a <url>
tag. The <loc>
tag contains the URL of the indexed page. The <lastmod>
tag contains the last modified date. You may have encountered posts mentioning two more
tags, <priority>
and <changefreq>
. There is no need to worry about choosing values for these two
tags. Google ignores both (and so does Bing).
Creating a sitemap with SvelteKit
SvelteKit’s SEO docs show an example of a
sitemap implemented as an endpoint in src/routes/sitemap.xml/+server.js
. The GET
handler
assembles an XML string to which you add relevant routes. There is no need to add all routes, only
those you want to be indexed by Google. The catch is that you need to figure out how to retrieve the
entries for your sitemap. There is no copy-paste blueprint for how to create a sitemap with
SvelteKit because a sitemap depends on how you manage the content of your site. But I will walk you
through the steps.
Create endpoints to retrieve relevant pages
I created an endpoint src/api/posts/+server.js
that returns a list of all posts, which it obtains from a file that contains an array with metadata
for all posts. If I managed my posts in a CMS, the endpoint would retrieve them via an API call to
the CMS. Add an endpoint for each type of content you want to include in your sitemap.
Create a sitemap endpoint
Create an endpoint src/routes/sitemap.xml/+server.js
and add an async GET
handler with the
following structure:
Since this endpoint returns XML, I set the content type to application/xml
. Then I fetch all posts
from my endpoint /api/posts
. At the end of the handler, I create the XML string, wrap it in a
response object and return it.
To make creating entries easier, I use this helper function:
function create_entry(path, lastmod) {
return `<url>
<loc>${new URL(path, PUBLIC_CANONICAL_ORIGIN).href}</loc>
${lastmod ? `<lastmod>${lastmod}</lastmod>` : ''}
</url>`;
}
path
is a relative path, and lastmod
is a date string in ISO format. I get both from my /api/posts
endpoint. Google expects absolute URLs in a sitemap. Since I prerender the sitemap, I
cannot obtain the origin of the URL from which the app is served in production. Therefore, I created
an environment variable PUBLIC_CANONICAL_ORIGIN
, which contains my site’s canonical origin https://www.maier.tech. This variable could also be private and named CANONICAL_ORIGIN
. But I also
need access to the canonical origin in my SEO components client-side, which means that the variable
has to be public.
Let’s add error handling to wrap up the handler:
The above code is a simplified version of my actual endpoint, which you can explore on GitHub. My actual endpoint adds caching, validation, and prerendering.
Alternative sitemap creation
If your SvelteKit site uses adapter-static, you can
use package svelte-sitemap. With this package,
instead of implementing an endpoint for a sitemap, you can configure the postbuild
hook in package.json
to scan all routes in the build
directory and create build/sitemap.xml
. This
approach only works with adapter-static, since svelte-sitemap cannot determine all possible routes
for other adapters.