Skip to content

Instantly share code, notes, and snippets.

@jackabox
Last active February 11, 2026 12:49
Show Gist options
  • Select an option

  • Save jackabox/1733b240778ea7e063aa769ffc00f0df to your computer and use it in GitHub Desktop.

Select an option

Save jackabox/1733b240778ea7e063aa769ffc00f0df to your computer and use it in GitHub Desktop.
Craft CMS Seomatic with Astro

Craft CMS - GraphQL

query SiteWideExample {
  seo: seomatic(asArray: true) {
    metaTitleContainer
    metaTagContainer
    metaLinkContainer
    metaJsonLdContainer
    metaScriptContainer
  }
}

Grab the seomatic values as an array, pass these through to your astro front-end with however you are fetching them.

Usage

In your layout file add the following:

---
import SEO from '@/components/SEO.astro'

const { pageSeo } = Astro.props
---

<html lang="en">
  <head>
		<meta name="viewport" content="width=device-width, initial-scale=1">
		<meta charset="UTF-8">
		<SEO
		    pageSeo={pageSeo}
 			seo={seo}
		/>
  </head>

You can then further update the title and description on pages by passing through title and descriptions.

---
interface SeomaticMetaTitleContainer {
title: {
title: string
}
}
interface StandardContentName {
content?: string
name?: string
}
interface StandardLinkRel {
href: string
rel: string
type?: string
}
interface LanguageAlternate {
href: string
rel: string
hreflang: string
}
interface SeomaticMetaTagContainer {
generator: StandardContentName
keywords: StandardContentName
description: StandardContentName
referrer: StandardContentName
robots: StandardContentName
'fb:profile_id': StandardContentName
'fb:app_id': StandardContentName
'og:locale': StandardContentName
'og:locale:alternate': StandardContentName
'og:site_name': StandardContentName
'og:type': StandardContentName
'og:title': StandardContentName
'og:description': StandardContentName
'og:image': StandardContentName
'og:image:width': StandardContentName
'og:image:height': StandardContentName
'og:image:alt': StandardContentName
'facebook-site-verification': StandardContentName
'twitter:card': StandardContentName
'twitter:site': StandardContentName
'twitter:creator': StandardContentName
'twitter:title': StandardContentName
'twitter:image': StandardContentName
'twitter:image:width': StandardContentName
'twitter:image:height': StandardContentName
'twitter:image:alt': StandardContentName
'google-site-verification': StandardContentName
'bing-site-verification': StandardContentName
'pinterest-site-verification': StandardContentName
}
interface SeomaticMetaLinkContainer {
canonical: StandardLinkRel
home: StandardLinkRel
author: StandardLinkRel
publisher: StandardLinkRel
alternate: [LanguageAlternate]
}
// When grabbing these from the GraphQL as an array they come
// as json encoded, so technically, this is all strings
interface SeomaticInterface {
metaTitleContainer: string
metaTagContainer: string
metaLinkContainer: string
metaJsonLdContainer: string
}
interface Props {
pageSeo?: SeomaticInterface
seo: SeomaticInterface
}
const { pageSeo = null, seo } = Astro.props
const renderSeo = pageSeo ?? seo
const metaTitle: SeomaticMetaTitleContainer = JSON.parse(renderSeo.metaTitleContainer)
const metaTag: SeomaticMetaTagContainer = JSON.parse(renderSeo.metaTagContainer)
const metaLink: SeomaticMetaLinkContainer = JSON.parse(renderSeo.metaLinkContainer)
const metaJson = renderSeo.metaJsonLdContainer
---
<title set:html={metaTitle?.title?.title} />
<meta name="description" content={metaTag?.description?.content ?? ''} />
<meta name="keywords" content={metaTag?.keywords?.content} />
<meta name="referrer" content={metaTag?.referrer?.content} />
<!-- OG Info -->
<meta property="og:title" content={metaTag?.['og:title']?.content} />
<meta property="og:type" content={metaTag?.['og:type']?.content} />
<meta property="og:site_name" content={metaTag?.['og:site_name']?.content} />
<meta property="og:url" content={metaTag?.['og:url']?.content || Astro.url.href} />
{metaTag?.['og:image']?.content && <meta property="og:image" content={metaTag?.['og:image']?.content} />}
{metaTag?.['og:width']?.content && <meta property="og:image:width" content={metaTag?.['og:width']?.content}/>}
{metaTag?.['og:height']?.content && <meta property="og:image:height" content={metaTag?.['og:height']?.content}/>}
{metaTag?.['og:alt']?.content && <meta property="og:image:alt" content={metaTag?.['og:alt']?.content}/>}
<!-- Twitter Info -->
{metaTag?.['twitter:card']?.content && <meta name="twitter:card" content={metaTag?.['twitter:card']?.content}/>}
{metaTag?.['twitter:site']?.content && <meta name="twitter:site" content={metaTag?.['twitter:site']?.content}/>}
{metaTag?.['twitter:creator']?.content && <meta name="twitter:creator" content={metaTag?.['twitter:creator']?.content}/>}
{metaTag?.['twitter:title']?.content && <meta name="twitter:title" content={metaTag?.['twitter:title']?.content}/>}
{metaTag?.['twitter:image']?.content && <meta name="twitter:image" content={metaTag?.['twitter:image']?.content}/>}
{metaTag?.['twitter:image:width']?.content && <meta name="twitter:image:width" content={metaTag?.['twitter:image:width']?.content}/>}
{metaTag?.['twitter:image:height']?.content && <meta name="twitter:image:height" content={metaTag?.['twitter:image:height']?.content}/>}
{metaTag?.['twitter:image:alt']?.content && <meta name="twitter:image:alt" content={metaTag?.['twitter:image:alt']?.content}/>}
<!-- Verification codes -->
<meta name="facebook-site-verification" content={metaTag?.['facebook-site-verification']?.content}/>
<meta name="google-site-verification" content={metaTag?.['google-site-verification']?.content}/>
<meta name="bing-site-verification" content={metaTag?.['bing-site-verification']?.content}/>
<meta name="pinterest-site-verification" content={metaTag?.['pinterest-site-verification']?.content}/>
<!-- Can/Links -->
<link rel="canonical" href={metaLink?.['canonical']?.href} />
<link rel="home" href={metaLink?.['home']?.href} />
<link rel="author" href={metaLink?.['author']?.href} type={metaLink?.['author']?.type} />
<!-- Languages -->
{metaLink.alternate.map(alternate => <link rel={alternate?.rel} hreflang={alternate?.hreflang} href={alternate?.href} />)}
<!-- JSON-LD -->
<script is:inline type="applciation/ld+json" set:html={metaJson}></script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment