SEO is a big field and most of it is not a developer problem. But two pieces are entirely ours, because they live in the codebase: the sitemap and the canonical tag.
Here is what each one does, in plain language, and how to add both.
Step 1: What a sitemap actually is
A sitemap is a file listing every page on your site that you want Google to know about. That is all it is. A list of URLs.
Search engines find pages by following links. That works, but it is slow and it misses things — a page nobody links to may never be found. A sitemap is you handing over the list directly instead of hoping the crawler stumbles across everything.
What it looks like
It is an XML file, usually at /sitemap.xml:
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://example.com/</loc>
<lastmod>2026-09-02</lastmod>
<priority>1.0</priority>
</url>
<url>
<loc>https://example.com/blog/</loc>
<lastmod>2026-09-02</lastmod>
<priority>0.8</priority>
</url>
</urlset>
Only <loc> is required. A few honest notes:
- Use full URLs.
https://example.com/blog/, not/blog/. Relative paths are invalid here. prioritybarely matters. Google has said it largely ignores it. Harmless to include, do not agonise over the numbers.lastmoddoes matter — but only if it is honest. Setting every page to today's date on every deploy teaches Google to ignore the field.- Only list pages you want indexed. No admin pages, no thank-you pages,
nothing marked
noindex.
Tell crawlers where it is
Add a robots.txt at your site root:
User-agent: *
Allow: /
Sitemap: https://example.com/sitemap.xml
Then submit it once in Google Search Console. That is also where you find out which pages actually got indexed, which is the only real feedback you get.
Step 2: The problem canonical tags solve
This one is less obvious, and more important.
The same page on your site is often reachable at several different URLs:
https://example.com/blog/my-post
https://example.com/blog/my-post/
https://www.example.com/blog/my-post
http://example.com/blog/my-post
https://example.com/blog/my-post?utm_source=twitter
https://example.com/blog/my-post.html
To you that is one page. To a search engine those are six different pages with identical content.
Two things go wrong. Google has to guess which one is the real one, and it may not pick the one you would. And any credit from people linking to your page gets split across the six versions instead of adding up to one strong page.
The fix is one line
In the <head> of the page, you name the official version:
<link rel="canonical" href="https://example.com/blog/my-post" />
This says: whatever address you arrived at, this is the real one — index that, and give it the credit.
The rule that surprises people: put it on every page, including the canonical page
itself, pointing at itself. That is called a self-referencing canonical, and it is
what stops query strings like ?utm_source=twitter from being treated as
separate pages.
Step 3: Mistakes that are easy to make
Pointing every page at the homepage
The classic disaster. Someone adds one canonical tag to a shared layout template and every page on the site now says "the real page is the homepage". Google takes you at your word and drops the rest. Each page must point at itself.
Using a relative URL
<!-- risky -->
<link rel="canonical" href="/blog/my-post" />
<!-- correct -->
<link rel="canonical" href="https://example.com/blog/my-post" />
Always absolute, always including https://. Relative canonicals resolve
differently depending on how the page was reached, which defeats the point.
Canonical and noindex together
Contradictory instructions — one says "index this other page instead", the other says "index nothing here". Pick one.
Being inconsistent about the trailing slash
If your canonical says /blog/, your sitemap says /blog, and your
internal links say /blog/index.html, you have created the exact problem you were
trying to fix. Pick one format and use it in the canonical, the sitemap, and your links.
Step 4: How the two work together
They answer different questions, and search engines want both:
- Sitemap: "here is every page that exists."
- Canonical: "and here is the official address of the one you are looking at."
A sitemap without canonicals means crawlers find your pages and then get confused by duplicates. Canonicals without a sitemap means the duplicates are resolved but some pages never get found. Neither takes long — do both.
Step 5: A checklist
- Write
/sitemap.xmlwith the full URL of every page you want indexed. - Add
/robots.txtwith aSitemap:line pointing at it. - Add a self-referencing
<link rel="canonical">to every page, absolute URL. - Pick one URL format — trailing slash or not — and use it everywhere.
- Submit the sitemap in Google Search Console and check back in a week.
- Add
og:andtwitter:meta tags while you are in there, so shared links get a proper preview.
For a small static site this is genuinely an afternoon of work, and it is the difference between being findable and not. This site has all of it — you can read /sitemap.xml and /robots.txt directly, and view source on any page to see the canonical tag.
Short version: a sitemap lists your pages so crawlers do not have to guess. A canonical tag names the official URL of a page so duplicates do not split your ranking. Every page points its canonical at itself, always with a full absolute URL, and keep the URL format consistent everywhere.