Documentation for the MoonBooth SEO Theme for Hugo

How to use the MoonBooth SEO Theme for Hugo.

Ron Erdos
Updated July 26, 2022

About this theme

Here’s more about the MoonBooth SEO Theme for Hugo and all its SEO advantages.


This site ( uses the theme, as does its sister site, Julia School, where I publish Julia language tutorials. The Julia School GitHub repo is public, if you want to see how I’ve implemented everything on this page (except for Google Analytics and Netlify CMS, neither of which I use on these sites).


Step 1

After purchase, download the .zip of the theme folder. Extract it, then drop it into your /themes/ folder.

Step 2

In your config file (usually /config.toml), add these lines without any indents:

theme = "moonbooth-seo-theme"
disableKinds = ['taxonomy', 'term']
enableRobotsTXT = true

The first line will tell Hugo to go ahead and actually use the theme.

The second line tells Hugo that we’re not using any taxonomies. If you want to use this theme with Hugo taxonomies, feel free to add the relevant code to your site (including updating this part of config.toml).

The third line activates the creation and publication of a robots.txt file at the root of your site.

Step 3

Also in your config file, add these lines and fill in the values between the double quotes:

	blogFooterLinkText = ""
	# Sets anchor text of footer link to the blog

	blogSection = ""
	# Enter your blog folder's name [1]

	color = ""
	# Sets theme colour [2] & Safari mask icon colour [3]

	description = ""
	# Sets homepage meta description (for SEO)

	rssTitle = ""
	# Sets RSS feed title (for RSS readers)

	seoTitle = ""
	# Sets homepage <title> (for SEO)

Notes for code above:

[1] If you haven’t renamed your blog folder, the value you should enter here is Hugo’s default of posts. I customise the name of my blog folder, making it more specific to help Google and humans infer what my content is about. For example, on my Julia language training site, I called it julia. I’ve made its GitHub repo public so you can take a look at its Hugo code if you like.

[2] Theme colour documentation

[3] Safari mask icon documentation

Step 4

N.B. This step is required from v1.0.2 of the theme—released on March 17th, 2022—onwards. It is not necessary for earlier versions.

In the root of your /content/ folder, ensure you have an file (note the leading underscore in the filename). It can be totally blank; mine is.

This file is needed to make the theme’s footer link logic work correctly on your site’s homepage.

Using the theme’s SEO features

Before we get into the theme’s SEO features, here’s a quick primer on the most important text fields for SEO:


To set the <title> and meta description of the homepage, fill in the value of seoTitle and description respectively in config.toml, as discussed above.

The homepage is essentially just a subscribe form, and as such there is no <h1>, only a form label. The font size of this label is the same as the <h1> headings elsewhere on the site, though.

Blog index

SEO fields for the blog index are populated using the approach outlined in the official Hugo documentation. In short, you’ll need to create a file named at the root of your blog directory. If you’re using the default posts as your blog folder, this file will live at /content/posts/

The theme will be looking for three text fields in this file:


Each populates the relevant area of the blog index: title populates the <h1> heading, seoTitle populates the document <title> in the <head> section, and description populates two fields: the meta description in the <head> and an italicised summary just below the <h1>. You can see an example on my Julia language training site.

Blog posts

The way to populate the SEO (and other) fields in a blog post is with the following YAML front matter:

date: 2021-01-19 13:04:46+11:00
authors: ["Firstname Lastname"]
tableOfContents: true

Let’s go over each.

title populates the <h1> on the blog post itself, and also the anchor text of the link from the blog index back to the post.

date populates the following: 1) the date in the byline on the blog post itself; 2) the <lastmod> date in the XML sitemap—this tells Google when the post was last modified; and 3) the <pubDate> in the RSS feed, which provides the date to RSS readers.

seoTitle populates the document <title> in the <head> section.

description populates two fields: the meta description in the <head> and an italicised summary just below the <h1>. You can see an example on my Julia language training site.

authors: ["Firstname Lastname"] populates the byline (author) field near the top of the blog post. Note that the value is an array of strings, which allows Hugo to do things such as build a page of all your authors.

tableOfContents is an optional YAML field, which, if set to true, builds a table of contents for the page, like the one at the top of this article.

Keeping pages out of Google’s index

There are likely a few pages on your site you want to keep out of Google’s index. Your “thank you for signing up” page, your unsubscribe page, and your 404 page, for example.

The reason you want to keep these pages out of Google’s index is because you don’t want to waste Google’s time crawling pages which will never bring you SEO traffic.

Instead, you want to direct Google’s attention to pages that will bring you SEO traffic, such as useful blog posts and product pages.

The easiest way to keep necessary but non-SEO-worthy pages out of Google’s index is to put a noindex tag in the <head> section of the relevant page.

Specifically, a tag that looks like this:

<meta name="robots" content="noindex" />

That will tell Google and other reputable search engines not to index (list) the page in search results.

You can add the noindex tag easily with this theme, by adding a parameter to your YAML front matter—for posts and pages—that looks like this:

noindex: true

Sitemap for search engines

One of the parts of this theme I’m most proud of is that when you noindex a page, it also withholds it from the SEO (XML) sitemap and the RSS feed. I’ll explain why.

If you noindex a page but simultaneously list it in your XML sitemap, Google considers that an error, or at least, suboptimal.

It’s kind of like driving a car with the handbrake on.

On the one hand, you’re telling Google to go look at Page X (by listing it in the XML sitemap), but on the other, you’re telling it to stop by including the noindex tag.

Generally speaking, you don’t want to direct Google’s attention to pages which have a noindex tag.


Another theme feature I’m proud of is making the location of the XML sitemap (see above section) easy for Google to discover.

To do that, I use an SEO feature called robots.txt.

This theme will automatically include the location of your XML sitemap in your robots.txt file. All you have to do is include the line:

enableRobotsTXT = true

in your config.toml file.


Broadly, there are three ways to customise styles using this theme; I cover each below. Note that you can use these methods in tandem; they’re not mutually exclusive.

Method 1: Change the value of SCSS variables

The MoonBooth SEO Theme for Hugo uses SCSS—a superset of CSS3—to generate its CSS style sheet.

I’ve designed it this way so that you can change the theme colours in just two lines, rather than doing a potentially messy “find and replace”.

How? SCSS uses variables—something CSS really needs—to keep your styles DRY ("Don’t Repeat Yourself").

All the style variables live in an “SCSS partial” at /themes/assets/scss/_variables.scss.

The variables in the _variables.scss partial look like this:

$color-accent: red;
$color-background: black;
$color-gray: #ccc;
$color-text: white;
$increment: 10px;
$wrapper-max-width: 700px;

Going through each in turn:

$color-accent sets the accent colour. Namely: links and buttons in hovered state, block quote decoration, form input fill, button and table borders. It defaults to red because I had to pick a colour that would stand out.

$color-background sets the background colour. It defaults to black because the theme defaults to dark mode, but you can easily change it (as all variables) by following the steps outlined below.

$color-gray specifies which shade of grey should be used when appropriate. At the moment it only sets the colour of visited links, but may be used for more elements in the future. I made it a variable mainly so that all colours can be specified in one place (the SCSS variables partial).

$color-text sets the colour of paragraphs, links, lists, headings (in non-visited, non-hovered state). It defaults to white because the theme defaults to dark mode (white text on a black background).

$increment sets the rhythm for font sizes. Its default value is 10px, but your fonts will never be that small. In the main stylesheet, paragraphs are $increment * 2 or 20px (did you know you can do maths in SCSS?), <h3> headings are $increment * 2.5 (25px), <h2> headings are $increment * 4 (40px), and <h1> headings are $increment * 6 (60px). If you want to change these multiples, you can learn how to do that in the section on adding custom styles, which is lower down on this page.

$wrapper-max-width sets the maximum width of the content column, and defaults to 700px. This theme is responsive, and uses a single column on both mobile and desktop devices. However, given most phone screens are narrower than 700px, this setting will really only affect desktop and tablet devices. I chose 700px as the default as it makes for easy reading when combined with the default paragraph font size (20px) and the default font family.

Here are all the variables in table form:

Design elementSCSS variableDefault value
Accent colour$color-accentred
Background color$color-backgroundblack
Light gray$color-gray#ccc
Text color$color-textwhite
Font size increment$increment10px
Content width$wrapper-max-width700px

To change the value of any of these variables:

Step 1

Duplicate /themes/assets/scss/_variables.scss into your repo (e.g. outside the /themes folder) at /themes/assets/scss/_variables.scss. You may need to create the /assets/ and/or /scss/ folders. Note the leading underscore in the filename of _variables.scss. The reason you want to duplicate the file into your repo is so that your changes won’t be overwritten if/when you pull theme changes.

Step 2

Copy in all six variables, not just the one(s) you want to change. The master theme.scss file will be expecting to see all six variables filled out in your copy of /assets/scss/_variables.scss (if it exists).

Step 3

Change some/all values as you desire. For example, if you wanted to switch from the default dark theme to a light theme, and from the default red accent colour to blue, the complete contents of your <YOUR_REPO>/assets/scss/_variables.scss file could look like this:

$color-accent: blue;
$color-background: white;
$color-gray: #ccc;
$color-text: black;
$increment: 10px;
$wrapper-max-width: 700px;

Method 2: Add custom CSS or SCSS

If you want to make style changes that go beyond altering the theme colours or otherwise editing the SCSS variable values, you can do that too.

For example, if you want a different hover effect on the email signup button, you would do that by using the process outlined in this section.

The way to add custom styles is to use an SCSS partial I’ve called _custom.scss. Here, you can overwrite style rules that ship with the theme and/or add your own style rules.

Your custom style rules can be in plain CSS, or you can use SCSS.

Here’s how to make CSS changes to the theme without having to clone its SCSS file.

Step 1

Duplicate /themes/assets/scss/_custom.scss into your repo (e.g. outside the /themes folder) at /themes/assets/scss/_custom.scss. You may need to create the /assets/ and/or /scss/ folders. Note the leading underscore in the filename of _custom.scss. The reason you want to duplicate the file into your repo is so that your changes won’t be overwritten if/when you pull theme changes.

Step 2

Add your CSS or SCSS style rules. That’s it!

Method 3: Major style overhaul

If you want to change a lot of styles, you’ll probably be better off duplicating the theme stylesheet into your repo and editing it there. That way, you won’t have to “swim against the tide” of the existing style rules that ship with the theme, constantly overwriting them as you would if you used Method 2, above. You’ll also have a more efficient style sheet from the browser’s perspective.

Here’s how to use this method:

Step 1

Create a blank SCSS file—don’t worry, you can use just CSS—at <YOUR_REPO>/assets/scss/theme.scss

Step 2

Add your custom CSS and/or SCSS styles. Again, you can use just plain old CSS if you like. That’s it!

[Optional] JavaScript

Custom JS

To add custom JS to your Hugo site using this theme, you don’t have to create your own head.html partial.

Instead, simply create a file at /static/scripts/custom.js and put all your custom JS in that file.

The theme will notice the presence of the custom.js file and create a link to it in the <head> section. If no custom.js file exists (the default state), then no link is created. Simple!

External JS files

If you want to add third-party Javascript—from Stripe, for example—to your site with this theme, simply add the link to the script in config.toml, like this:

	scripts = [""]

This will appear in the <head> section of all your web pages like this:

<script src=""></script>

Note that the theme is expecting an array—hence the square brackets surrounding the value above—even if you only have one third-party script to add.

To add more scripts, simply comma-separate them inside the array, like this:

	scripts = ["", ""]

NB: Read on for an easy way to implement Google Analytics.

[Optional] Google Analytics

If you want to add Google Analytics to your site, the MoonBooth SEO Theme for Hugo makes this easy.

You can use the new version of Google Analytics (GA4), or the sunsetting version, (GA3 a.k.a. Universal Analytics), or neither!

Opt-in if desired; do nothing if you don’t want Google Analytics

This feature is opt-in; if you don’t use Google Analytics, simply do nothing. You won’t end up with any extraneous code on your site. (That’s what I do on my own sites, including this one—no GA in sight!)

No inflated pageviews from localhost

I particularly like the fact that with the MoonBooth SEO Theme for Hugo, you won’t get any inflated pageviews or other GA metrics when using localhost.

This is because I’ve added conditional logic which requires the Hugo environment to be set to production for the GA code to be inserted. Hugo automatically sets the environment to production when running the hugo command to build your site.

Conversely, when you run hugo server to view your site locally via localhost, Hugo automatically sets the environment to development. As mentioned earlier, because of the conditional logic I’ve included in the MoonBooth SEO Theme for Hugo, this means your GA code won’t be inserted for localhost pageviews.

How to implement Google Analytics for Hugo

To add Google Analytics (GA4 or GA3) when using the MoonBooth SEO Theme for Hugo, simply follow the instructions below.

In config.toml, under the [params] section, add a parameter named ga_id and set the value as a string containing your Google Analytics id.

For example, for Google Analytics 3 (a.k.a. Universal Analytics; IDs start with UA-), you’d have something like this:

	ga_id = "UA-123456789-1"

(Obviously you’d use your own UA- ID.)

Whereas for Google Analytics 4 (GA4), you’d have something like this in your Hugo site’s config.toml:

	ga_id = "G-A1B2C3D4E5"

(Obviously you’d use your own G- ID.)

[Optional] Social media markup

The MoonBooth SEO Theme for Hugo also includes optional automatic markup in the form of meta tags for Facebook and Twitter. This is an opt-in feature; if you don’t want the markup, simply do nothing. However, I do recommend enabling this feature; read on to see why.

The theme uses an approved combination of Open Graph markup (for both Facebook and Twitter) and Twitter card markup (to add extra information for Twitter cards).

If you enable this opt-in feature—more on that below—the theme will generate meta tags to ensure your pages look great when shared on Facebook and Twitter. Note that even if you have no personal social media presence, others may share your content, so it’s worth having the preview of your content look as good as possible.

The social media meta tags are super-lightweight, and are not “like”, “share” or “tweet” buttons, so they have no ability to track users on your site—there’s zero Javascript involved.

If you don’t want the social media tags, simply do nothing—you won’t get any extraneous social media code on your site. However, again, if you choose not to enable this feature, your articles and homepage will probably not look their best when shared on Facebook and Twitter.

If you do want these meta tags—again, I recommend enabling this feature—read on to see how. There’s only one step!

How to enable social media tags for Hugo

There’s only one step—simply create a .png image of your site logo or brand (here’s mine) that’s 1200px wide and 630px high. Add it to your Hugo site’s /static/ folder, and you’re done!

After publishing (or in localhost mode), you should be able to see it at /opengraph.png (again, see my example above).

Note that if you don’t add this .png image, you won’t get any social media tags. This is because the image tag is required for Open Graph.

At the risk of sounding repetitive, do note that the theme is looking specifically for a .png image named opengraph.png. PNGs are the best image type for logos (other than SVGs, which unfortunately aren’t accepted by Facebook and Twitter as preview images).

Read on to see which social media tags you’ll get, and which data populates them.

Which Open Graph tags will appear?

The following Open Graph tags will appear when you enable social media tags in the theme (again, how to enable is covered above).

og:title This is pulled from the title field in the YAML front matter of posts and pages, or from the title in config.toml for the homepage.

og:description This is pulled from the description field in the YAML front matter of posts and pages, or from the description in config.toml for the homepage.

og:type This is set to article for blog posts (such as the one you’re reading right now) and pages (such as the About page) and to website for all other content types (including the home page and blog indexes).

og:site_name This is populated by the site title in config.toml.

og:image This will be hardcoded to /opengraph.png, which is the image you’ll need to create in order to enable social media markup. See above section for details.

og:image:secure_url This will also be hardcoded to /opengraph.png.

og:image:type This will be hardcoded to image/png.

og:image:width This will be hardcoded to 1200 (1200 pixels; Facebook’s recommended width).

og:image:height This will be hardcoded to 630 (630 pixels; Facebook’s recommended width).

og:image:alt This will be populated by the site title in config.toml plus the word logo. For example, the value of this field for my site is MoonBooth logo.

Which Twitter tags will appear?

Just one Twitter-specific tag will appear:

twitter:card This will be hardcoded to summary_large_image.

All other Twitter metadata reuses the Open Graph tags discussed above. This is a Twitter-approved solution.

[Optional] Netlify CMS

Do you have a content team or person who wants a WYSIWYG editor to add and update content on a Hugo site? The free and mostly excellent Netlify CMS provides this functionality.

This is an opt-in feature of the MoonBooth SEO Theme for Hugo; if you don’t want the Netlify CMS, simply do nothing. You won’t get any extraneous code clogging up your site!

You don’t need to be hosted on Netlify to use the Netlify CMS

You don’t need to be hosted on Netlify to use the Netlify CMS. From the official site linked above:

Not all Netlify sites use Netlify CMS, and not all sites using Netlify CMS are on Netlify … Netlify CMS … has never been locked to the Netlify platform (despite the name).

How to implement the Netlify CMS for Hugo

To enable Netlify CMS on the MoonBooth SEO Theme for Hugo, simply create a parameter named netlify_cms set to true under [params] in config.toml.

The relevant part of your config.toml will look something like this:

	netlify_cms = true

Once done, all the necessary Netlify CMS code will be added. Again, this is an opt-in feature of the MoonBooth SEO Theme for Hugo, so if you don’t want the Netlify CMS added, simply do nothing, and no extraneous code will clog up your pages.

How to purchase

You can purchase the MoonBooth SEO Theme for Hugo here:

You can also read the benefits page here.


I’d love feedback on this theme—I’m on ron dot erdos at [the site you’re on], or on Twitter (DMs open).

"Thanks so much for your work ... I'm migrating my WordPress blog to Hugo and it's been really helpful." — Francisco S., engineer and blogger

"I love your content. The information that you provide have been very useful in the development of my personal website." — Mattia C., engineer and researcher

The planets in our solar system