How does Astro Content Framework support SEO?

The Astro framework is a great way to build static website content but just like any other technology on the web today, it still needs to be SEO optimized.
The Astro framework provides great support for SEO and I've put together some key strategies and tips on how to handle Astro SEO optimization.
In this guide, you'll find everything you need to know to get started with Astro SEO optimization, including:
- What Astro optimization is and why it's important.
- Different ways to handle meta tags.
- Tools to use to make SEO optimization easier.
- How to help search engines better index your site.
- How to inform search engines when there's new content.
In this article you'll learn how to ensure your Astro website is SEO ready. Let's get started.
Why is Astro SEO optimization important?
Astro has the ability to build sites statically, which means that pages need to be optimized at build time.
Optimizing your Astro page content is the process of ensuring your pages are easily indexed by search engines, including:
- Pages are unique and named properly.
- Making sure your pages can be found and indexed by search engines.
- Letting search engines know which pages to crawl.
- Reducing duplication and internal page ranking competition.
- Using Open Graph for optimizing social media sharing and linking.
These are just a few of the key steps we'll cover.
If you don't have an Astro project already, let's start there first.
npm create astro@latest
Also, since a good portion of SEO relies on the page header information, I'll be using a library to help make the job a little easier.
You can always hand code things but it's a little better to make sure things are more consistent across pages. I'll be installing and using the following package.
npm install astro-seo
In this section I'll create a simple layout and page and show how to use the astro-seo
library to add metadata header tags.
The Open Graph protocol was created by facebook to standardize the use of meta tags to improve the way links are shared and visually displayed on social media.
By defining some simple <meta>
tags, any website can greatly improve and optimize how web pages, landing pages and Ads display on these platforms.
For example, here's what a post with Open Graph meta tags would look like.
And here's an example without Open Graph.
As you can see the page doesn't really stand out and look as good. Using Open Graph will ensure the page looks and displays properly on social platforms when shared or placed in Ads.
Other social platforms like X (Twitter) have their own specification but will fallback to Open Graph if defined.
Setting the site name
An important step is to define your site URL in the astro.config.mjs
file. This will be the site name that gets returned using Astro.site
.
It should be decided whether to use www
or not in the site name and stay consistent.
Having inconsistent versions on a page or throughout your website can make the search engine web crawler consider these pages to be unique and possibly skew your metrics and analytics.
/astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
site: 'https://websitedomain.com',
integrations: [
]
});
Also, it's a good idea to define some constants for the base title
and description
of your website.
Each page will have its own title and description but these constants will be for the default and home page.
/src/consts.ts
export const SITE_TITLE = 'Website Name';
export const SITE_DESCRIPTION = 'Welcome to your website description here';
Building an SEO optimized Astro layout
Let's start by creating a new layout called MainLayout
in the /src/layouts
directory. I will omit any CSS styles for any pages in this article since they won't be needed.
/src/layouts/MainLayout.astro
---
import type { SEOProps } from "astro-seo";
import BaseHead from "../components/SEOBaseHead.astro";
type Props = {
metadata: SEOProps;
};
const { metadata } = Astro.props;
---
<html lang="en">
<head>
<BaseHead metadata={metadata} />
<style></style>
</head>
<body>
<header>Header</header>
<div>
<slot />
</div>
<footer>Footer</footer>
</body>
</html>
The SEOBaseHead
component will take as a prop the metadata
object.
/src/components/SEOBaseHead.astro
---
import { SEO, type SEOProps } from 'astro-seo';
import { SITE_DESCRIPTION, SITE_TITLE } from '../consts';
type Props = {
metadata: SEOProps;
}
const metadataBase: SEOProps = {
titleTemplate: `%s | ${SITE_TITLE}`,
titleDefault: SITE_TITLE,
description: SITE_DESCRIPTION,
canonical: Astro.site
}
const { metadata } = Astro.props;
const pageMetadata: SEOProps = Object.assign(metadataBase, metadata);
---
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<SEO {...pageMetadata}></SEO>
And finally, here's the actual page that will use the MainLayout
and set the metadata object.
/src/pages/tutorials/seo/seo-metadata.astro
---
import Layout from "../../../layouts/SEOLayout.astro";
import { SITE_TITLE } from "../../../consts";
const title = "SEO Optimization Metadata";
const description = "Learn how to add SEO metadata tags on the Astro framework";
---
<Layout
metadata={{
title,
canonical: Astro.url,
description,
openGraph: {
basic: {
title,
type: "article",
image: "/public/path/to/someimage.png",
},
optional: {
description,
siteName: SITE_TITLE,
},
},
twitter: {
title,
site: SITE_TITLE,
description,
image: "/public/path/to/someimage.png",
card: "summary_large_image",
},
}}
>
<h1>SEO Optimized Metadata</h1>
<!-- Other page content here -->
</Layout>
As you can see, by providing some simple information about the page will render and output the following Open Graph meta tags.
These tags alone are quite sufficient for SEO optimization of meta tags.
Header Metadata Output:
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title>SEO Optimization Metadata | Website Name</title>
<link rel="canonical" href="https://websitedomain.com/tutorials/seo/seo-metadata"/>
<meta name="description" content="Learn how to add SEO metadata tags on the Astro framework"/>
<meta name="robots" content="index, follow" />
<meta property="og:title" content="SEO Optimization Metadata" />
<meta property="og:type" content="article" />
<meta property="og:image" content="/public/path/to/someimage.png" />
<meta property="og:url" content="https://websitedomain.com/tutorials/seo/seo-metadata" />
<meta property="og:description" content="Learn how to add SEO metadata tags on the Astro framework"/>
<meta property="og:site_name" content="Website Name" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="Website Name" />
<meta name="twitter:title" content="SEO Optimization Metadata" />
<meta name="twitter:image" content="/public/path/to/someimage.png" />
<meta name="twitter:description" content="Learn how to add SEO metadata tags on the Astro framework"/>
You can also add any additional custom meta tags, by using the extend
section, for example:
Defining custom meta tags and links
<Layout
metadata={{
title,
canonical: Astro.url,
description,
openGraph: {
basic: {
title,
type: "article",
image: "/public/path/to/someimage.png",
},
optional: {
description,
siteName: SITE_TITLE,
},
},
twitter: {
title,
site: SITE_TITLE,
description,
image: "/public/path/to/someimage.png",
card: "summary_large_image",
},
extend: {
link: [{ rel: "icon", href: "/favicon.ico" }],
meta: [
{
name: "some:arbitrary:key",
content: "Arbitrary value",
},
{
name: "keywords",
content: "SEO Astro",
}
],
}}
}}
>
<h1>SEO Optimized Metadata</h1>
<!-- Other page content here -->
</Layout>
Generated arbitrary meta and link tags
<head>
<link rel="icon" href="/favicon.ico">
<meta name="some:arbitrary:key" content="Arbitrary value">
<meta name="keywords" content="SEO Astro">
</head>
You can find more information for Open Graph here. It's quite extensive and worth spending some time because social media platforms are an excellent way to share your website page links.
By using these tags you'll ensure your pages are fully shareable and display as expected.
Use a Sitemap in Astro
Using a sitemap.xml
file is what search engines will use as an index to discover all of your available pages.
Not all pages will link one to another, so having a sitemap page will provide a complete index.
Here's a sample of what a sitemap.xml file looks like.
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://yourdomain.com</loc>
<lastmod>2023-04-06T15:02:24.021Z</lastmod>
<changefreq>yearly</changefreq>
<priority>1</priority>
</url>
<url>
<loc>https://yourdomain.com/about</loc>
<lastmod>2023-04-06T15:02:24.021Z</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://yourdomain.com/blog</loc>
<lastmod>2023-04-06T15:02:24.021Z</lastmod>
<changefreq>weekly</changefreq>
<priority>0.5</priority>
</url>
</urlset>
Not all of these fields are really used anymore, in fact Astro's sitemap only uses loc
for the page URL. Here's what these fields represent:
loc
: URL path to page.
lastmod
: Used to indicate when the file was last modified.
changefreq
: This field represents the change frequency of modifications.
priority
: This is the imporance of the URL compared to the other URLs on the site and it ranges from 0.0 - 1.0.
How to generate a sitemap in Astro
Astro makes this process very easy and it will generate these files for you. All you need to do is install using the following command.
npx astro add sitemap
Astro will automatically install the sitemap
integration using the @astrojs/sitemap
package.
Sitemap integration configuration
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';
export default defineConfig({
integrations: [sitemap()],
});
Sitemap files can grow quite large over time in some applications and they can be broken down into smaller sets of 50,000 entries per XML page.
Astro will handle all of these details for you at build time and will examine all page routes.
Astro will also automatically index all dynamic routes like [id]
or [...slug]
or [slug]
provided that the getStaticPaths()
function is defined and returns all param options.
By running the build
command it will output everything to the /dist
folder and you should see your sitemap-index.xml
at the root.
npm run build
Now it can added as a meta
tag link in the header. This makes it easy and we can simply add it to the SEOBaseHead.astro
we created earlier.
...
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="sitemap" href="/sitemap-index.xml" />
<SEO {...pageMetadata}></SEO>
Generate a robots.txt file
A robots.txt
file is a file that is used to instruct search engine crawlers what's allowed to be indexed
and followed
on your site.
to create a robots file you can add a robots.txt
to your public directory root. For most sites this is generally easy to maintain without generating the file dynamically.
Here's an example which includes an entry for the Sitemap
we just generated.
/public/robots.txt
User-agent: *
Allow: /
Sitemap: https://<YOUR SITE>/sitemap-index.xml
You can either declare files that shouldn't be indexed or followed in the robots.txt
file globally, or you can use the options noindex
and nofollow
in the SEO meta header.
Both of these values are false by default and setting these values in the header will opt-out at the page level.
<Layout
metadata={{
title,
canonical: Astro.url,
noindex: true,
nofollow: true,
openGraph: {
...
},
twitter: {
...
}
}}
>
<h1>SEO Optimized Metadata</h1>
<!-- Other page content here -->
</Layout>
Adding these entries will output the following meta
tags in the page header.
<meta name="robots" content="noindex, nofollow">
Use the Astro Image API
Astro provides an <Image>
component, making it very easy to optimize image resources. The faster a large image can load, the better chances of ranking higher on search pages.
Astro has built in API services to optimize images. It generates an <img>
source link from its specialized image optimization API rather than using a standard image source path.
Why do I need Astro Image API?
The <Image>
component provides the following benefits:
- Image sizing at build time.
- Image bundeling at build time.
- Improved Cumulative Layout Shift (CLS) which can greatly reduce page shift during page loading.
- Optimized image content types like
image/webp
.
- Remote image resource loaders.
- Accessibility tag improvements.
- and more, just to name a few.
How to use the Astro Image component
Rather than using a /public
image path, create a folder under the /src
directory to place images. For example, I'll use /src/resources
. Now the file can be bundled by using an import
statement and passing the value as the source of the <Image>
.
According to the Astro documentation, the files in the /public
directory will not be optimized and need to be under the /src
folder for optimization.
/src/pages/tutorials/seo/seo-image.astro
---
import Layout from "../../../layouts/SEOLayout.astro";
import { Image } from "astro:assets";
import BackgroundImage from "../../../resources/img/backdrop.jpg";
const title = "SEO Optimization Image";
const description = "Learn how to use SEO optimized images on the Astro framework";
---
<Layout metadata={{
title,
description
}}>
<h1>SEO Optimized Image</h1>
<Image src={BackgroundImage} width={1200} height={500} alt="Some high quality background image" />
</Layout>
Here's the rendered output HTML. As you can see the image is now being loaded from an internal API endpoint and fully optimized.
Image component rendered output
<img src="/_image?href=%2F%40fs%2FUsers%2Fdavidbecker%2FProjects%2Frepo%2Fbungee%2Fsrc%2Fresources%2Fimg%2Fbackdrop.jpg%3ForigWidth%3D960%26origHeight%3D480%26origFormat%3Djpg&w=1200&h=500&f=webp" alt="Some alt text here" width="1200" height="500" loading="lazy" decoding="async" data-astro-source-file="/.../node_modules/astro/components/Image.astro">
I'm passing the following props to the <Image>
component:
src
: A local import
image.
alt
: Requires an alt attribute for Accessibility.
width
: Width of the image in pixels.
height
: Height of the image in pixels.
class
: Image can still be styled as needed.
The width
and height
should be used to set the optimal dimensions of the image. Astro will generate an optimized image based on these settings or it will automatically determine width
and height
from the imported image data if the attributes are not defined.
Conclusion
As you can see, adding some essential SEO capabilities is really quite easy using Astro.
When combining these techniques with well written page content it can potentially increase your chances of getting higher page ranking on searches.
Just remember that page load performance is an essential part of SEO optimization among other factors. Since Astro generates sites statically and in some cases using SSR, it's going to be very fast on page load times.
Hope this was informative and helps you on your project.