Opens an external site in a new window
Mental Health Awareness Month
“Community”
RODNEY LAB
  • Home
  • Plus +
  • Newsletter
  • Links
  • Profile
RODNEY LAB
  • Home
  • Plus +
  • Newsletter
  • Links

Open Graph SEO in SvelteKit: Custom Share Images # Open Graph SEO in SvelteKit: Custom Share Images #

blurry low resolution placeholder image Open Graph SEO in SvelteKit
  1. Home Rodney Lab Home
  2. Blog Posts Rodney Lab Blog Posts
  3. SvelteKit SvelteKit Blog Posts
<PREVIOUS POST
NEXT POST >
LATEST POST >>

Open Graph SEO in SvelteKit: Custom Share Images #

Updated 6 months ago
9 minute read
Gunning Fog Index: 7.6
3 comments
Content by Rodney
blurry low resolution placeholder image Author Image: Rodney from Rodney Lab
SHARE:

🚀 Before we get going #

Before we get going on this post about Open Graph SEO in SvelteKit, I should mention this is the second post in a series on SvelteKit SEO. The first post included an introduction to SEO in general and also some details on how to add Twitter metadata to your SvelteKit site pages. This time we will look at Open Graph meta, which is great for optimizing how your page looks when it is shared on Signal, Wire, WhatsApp and Slack.

Using Open Graph metadata, we can specify which images to display on social media shares, as well as customize the text that appears on the sharing card. You have probably seen memes about social media apps doing poor crops of shared images. By using Open Graph meta, we preselect an image which is nicely cropped and avoid a poor reflection on our brand. Here is what we are aiming towards:

blurry low resolution placeholder image Open Graph SEO in SvelteKit: Signal Shares: screen capture of Signal post generated from page share.
Open Graph SEO in SvelteKit: Signal app Shares

This is a screenshot from the Signal messaging app, showing some shares of pages from our test site. I added the Open Graph logo overlay in the image itself, just to make it easier to which images are used where. The Signal App uses our preferred titles and descriptions as well as the nicely cropped square image because we include the right Open Graph meta.

Share Buttons #

I should clarify what we are looking at here is updating what appears, for example, in Twitter when someone pastes in a link for your page into a Tweet they are composing. The same will happen if they click a share button on your page which includes the link, but we won’t focus on that here though. Do check out the Svelte Share Buttons post to see how to implement a Twitter, Telegram, WhatsApp, etc share button. Now you have an idea of what we can achieve, shall we have a look at how to do it?

🧑🏽‍🎓 Open Graph Metadata #

Let's start by looking at some general Open Graph tags you can use on any page of your site. Following that, we look at some more specific to blog posts. Finally, we will look at nailing Open Graph SEO SvelteKit social images.

Although Open Graph protocol was developed at Facebook , it has become widely adopted and is used by other apps (as we saw with Signal above). The Twitter tags we looked at in the earlier post look similar to Open Graph ones. In fact, the Twitter protocol is loosely based on the Open Graph one. As mentioned in the previous SvelteKit SEO post, you can omit some Twitter tags if you include the equivalent Open Graph Tag. As an example, you can drop the second tag below and Twitter would know to use the first one:

    
<meta property="og:title" content={pageTitle} />
    
<meta name="twitter:title" content={pageTitle} />

General Open Graph Meta #

The Open Graph tags you would use on any page of your site are:

  1. og_site_name: This is just the name of your site.
  2. og:locale: This is the language the shared page is written in. If you skip it, Facebook will assume content is written in American English (en_US), so Americans can leave this one out. If you do need this tag, it should be in language_TERRITORY format. I write my posts in British English, so use en_GB.
  3. og:url: The URL of the shared page.
  4. og:type: Use article here for blog posts and website for other website pages.
  5. og:title: This is an SEO title and will typically be show in the share card. We can set this it to the page title used in the HTML head section (we discussed this in the earlier SvelteKit SEO post).
  6. og:description: You can set this to the page's meta description (see previous post).
  7. fb:app_id: Although you might see this on other pages, it is no longer best-practise to include it . It is safe to ignore the warning when testing with Facebook Sharing Debugger (explained in more detail further down).
  8. Article Open Graph Meta #

    We will have a look at how to integrate that meta into your SvelteKit site in a moment. First, though, here are some additional metadata you can use on article or blog post pages:

    1. article:publisher: if you have a company Facebook page, set this to the URL of your Facebook company page.
    2. article:author: similar to publisher above, but this time you use the personal Facebook page of the author.
    3. article:published_time: use the ISO 8601 date and time format . I set this to the time the article was first published. You generate a date in the right format from the terminal with the date command. To make life easier, I added the alias code below into my ~/.zshrc file  and then just type the command timestamp whenever I need to invoke it:
    4.     
      function timestamp {
      ts=$(echo -n $(date +"%Y-%m-%dT%H:%M:%S.000%z"))
      echo -n $ts | pbcopy
      echo $ts
      }

      This also copies the timestamp to the clipboard. Keen to hear other methods you have for generating timestamps.

      1. article:modified_time: what you would expect it to be (also in ISO 8601 format).
      2. 🖼 Open Graph Images #

        The world of Open Graph images is not a simple one. You can include multiple images in the meta (this is in addition to the Twitter one we looked at previously), however the order you include them in can affect which ones are used. This is because there is a patchwork of policies on which Open Graph image to use for different apps. Taking this into account, the best strategy is probably to optimize for the apps most used by your audience.

        I found what works well for me is to use a Facebook optimized image first and then a square one afterwards. For the first one, I use a 1200 px × 627 px image. Wire and Facebook use this. The second is a square, 400 px × 400 px image. WhatsApp and Signal pick the square image. Telegram, Slack, and Discord use the Twitter image. You may get slightly different results if you change the order you include the tags in. Let me know if there's a popular app I have forgotten to mention. We will see how to include the meta next.

        🗳 Poll #

        Which app do you get most shares of your site pages from?
        Voting reveals latest results.

        🖥 Open Graph SEO in SvelteKit: The Code #

        So we've gone through what we need to include. Let's look at an example of how we code it up. We will look at a blog post. To make it more concrete, we will use the SvelteKit MDsveX blog template .

        Step zero is to create the images. You can generate them automatically, though I prefer to crop them myself in a photo editing app to ensure I get a good crop. If you are cropping images automatically, be sure to check the auto images look good. For the test site, I used images with no text. For your own site you might want to generate a set of template images (one for each aspect ratio) then programmatically add text to customize them for each page or blog post. Be sure to use the Rainbow tool to make sure you have a decent contrast ratio between any text and the background image if you do this.

        Next we crack open some code. To specify which images we want to appear in social shares, we use the front matter section of each blog post's markdown file:

        src/routes/best-medium-format-camera-for-starting-out/index.md
        markdown
            
        ogImage: 'https://rodneylab-climate-starter.imgix.net/best-medium-format-camera-for-starting-out-open-graph.jpg?ixlib=js-3.2.1&w=1200&h=627&s=3bd576df666fae35a312ed02425aac25'
        ogSquareImage: 'https://rodneylab-climate-starter.imgix.net/best-medium-format-camera-for-starting-out-open-graph-square.jpg?ixlib=js-3.2.1&w=400&h=400&s=ab8c1d3f5139d9f48578baba97549f14'
        twitterImage: 'https://rodneylab-climate-starter.imgix.net/best-medium-format-camera-for-starting-out-twitter.jpg?ixlib=js-3.2.0&w=800&h=418&s=5a4968759b838f0209894062d815e045'
        categories: ''
        tags: ''
        ---

        I am using Imgix to host the images, but you can host them anywhere you like. The images we specify in each post's markdown are used in the BlogPost template, where they are passed to the SEO component along with other metadata from the front matter:

        src/lib/components/BlogPost.svelte
        svelte
            
        1 <script>
        2 import BannerImage from '$lib/components/BannerImage.sveelte';
        3 import SEO from '$lib/components/SEO/index.sveelte';
        4
        5 let { imageData, post, sanitisedHtml } = $props();
        6
        7 const {
        8 datePublished,
        9 featuredImage,
        10 featuredImageAlt,
        11 featuredImageSrc,
        12 featuredImageSrcset,
        13 lastUpdated,
        14 ogImage,
        15 ogSquareImage,
        16 postTitle: title,
        17 seoMetaDescription: metadescription,
        18 slug,
        19 twitterImage = null,
        20 } = post;
        21 const { ogImage, ogSquareImage, src: featuredImage, twitterImage } = imageData;
        22
        23 const ogImageObject = ogImage
        24 ? {
        25 url: ogImage,
        26 alt: featuredImageAlt,
        27 }
        28 : null;
        29 const ogSquareImageObject = ogSquareImage
        30 ? {
        31 url: ogSquareImage,
        32 alt: featuredImageAlt,
        33 }
        34 : null;
        35 const twitterImageObject = twitterImage
        36 ? {
        37 url: twitterImage,
        38 alt: featuredImageAlt,
        39 }
        40 : null;
        41 const bannerImageProps = {
        42 featuredImage,
        43 featuredImageAlt,
        44 featuredImageSrc,
        45 featuredImageSrcset,
        46 };
        47 </script>
        48
        49 <SEO
        50 article={true}
        51 {slug}
        52 {title}
        53 {datePublished}
        54 {lastUpdated}
        55 {metadescription}
        56 {timeToRead}
        57 ogImage={ogImageObject}
        58 ogSquareImage={ogSquareImageObject}
        59 twitterImage={twitterImageObject}
        60 />
        61 <BannerImage {...bannerImageProps} />

        You will see we build up image objects containing the image, and its alt text to pass to the SEO component. We have included a fallback in case the images and alt were not given in the original markdown file. The next step in the chain is the SEO component, which passes the relevant meta to its OpenGraph component:

        src/lib/components/SEO/index.svelte
        svelte
            
        1 <script>
        2 import website from '$lib/config/website';
        3 import { VERTICAL_LINE_ENTITY } from '$lib/constants/entities';
        4 import OpenGraph from './OpenGraph.svelte';
        5 import Twitter from './Twitter.svelte';
        6
        7 const {
        8 author,
        9 facebookAuthorPage,
        10 facebookPage,
        11 ogLanguage,
        12 siteLanguage,
        13 siteTitle,
        14 siteUrl,
        15 twitterUsername,
        16 } = website;
        17
        18 const defaultAlt =
        19 'picture of a person with long, curly hair, wearing a red had taking a picture with an analogue camera';
        20
        21 let {
        22 article = false,
        23 lastUpdated,
        24 datePublished,
        25 metadescription,
        26 slug,
        27 timeToRead = 0,
        28 title,
        29 ogImage = {
        30 url: ogImageSrc,
        31 alt: defaultAlt,
        32 },
        33 ogSquareImage = {
        34 url: ogSquareImageSrc,
        35 alt: defaultAlt,
        36 },
        37 twitterImage = {
        38 url: twitterImageSrc,
        39 alt: defaultAlt,
        40 },
        41 } = $props();
        42
        43 const pageTitle = `${siteTitle} ${VERTICAL_LINE_ENTITY} ${title}`;
        44 const openGraphProps = {
        45 article,
        46 image: ogImage,
        47 squareImage: ogSquareImage,
        48 metadescription,
        49 ogLanguage,
        50 pageTitle,
        51 siteTitle,
        52 siteUrl,
        53 ...(article ? { datePublished, lastUpdated, facebookPage, facebookAuthorPage } : {}),
        54 };
        55
        56 const twitterProps = {
        57 article,
        58 author,
        59 twitterUsername,
        60 image: twitterImage,
        61 metadescription,
        62 pageTitle,
        63 timeToRead,
        64 url: `${siteUrl}/${slug}`,
        65 };
        66 </script>
        67
        68 <svelte:head>
        69 <title>{pageTitle}</title>
        70 <meta name="description" content={metadescription} />
        71 <meta
        72 name="robots"
        73 content="index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1"
        74 />
        75 <html lang={siteLanguage} />
        76 </svelte:head>
        77 <Twitter {...twitterProps} />
        78 <OpenGraph {...openGraphProps} />

        Open Graph SEO in SvelteKit: The Svelte OpenGraph Component #

        The final piece of the puzzle is the OpenGraph component itself. This includes all the meta tags we mentioned above:

        src/lib/components/SEO/OpenGraph.svelte
        svelte
            
        1 <script>
        2 let {
        3 article = false,
        4 datePublished,
        5 lastUpdated,
        6 facebookAuthorPage = '',
        7 facebookPage = '',
        8 image,
        9 squareImage,
        10 metadescription,
        11 ogLanguage,
        12 pageTitle,
        13 siteTitle,
        14 url,
        15 } = $props();
        16 </script>
        17
        18 <svelte:head>
        19 <meta property="og:site_name" content={siteTitle} />
        20 <meta property="og:locale" content={ogLanguage} />
        21 <meta property="og:url" content={siteUrl} />
        22 <meta property="og:type" content={article ? 'article' : 'website'} />
        23 <meta property="og:title" content={pageTitle} />
        24 <meta property="og:description" content={metadescription} />
        25 {#if image}
        26 <meta property="og:image" content={image.url} />
        27 <meta property="og:image:width" content="1200" />
        28 <meta property="og:image:height" content="627" />
        29 <meta property="og:image:alt" content={image.alt} />
        30 {/if}
        31 {#if squareImage}
        32 <meta property="og:image" content={squareImage.url} />
        33 <meta property="og:image:width" content="400" />
        34 <meta property="og:image:height" content="400" />
        35 <meta property="og:image:alt" content={image.alt} />
        36 {/if}
        37 {#if article}
        38 <meta property="article:publisher" content={facebookPage} />
        39 <meta property="article:author" content={facebookAuthorPage} />
        40 <meta property="article:published_time" content={datePublished} />
        41 <meta property="article:modified_time" content={lastUpdated} />
        42 {/if}
        43 </svelte:head>

        We include the two images mentioned earlier. In the generated page, you might get problems generating WhatsApp social images if, in the page's HTML head section, the Open Graph image tags come after the first <style> tag. I checked the generated code and this is not an issue here, using SvelteKit. If you are using other frameworks though, and have WhatsApp issues, it is worth checking and re-ordering the elements if needed.

        💯 Open Graph SEO in SvelteKit: Test #

        As always, our last step is to test this all works. As with the Twitter meta, there is a tool for checking Open Graph meta. This is the Facebook Sharing Debugger . To use it, you will need to have a Facebook account and to log in.

        Please enable JavaScript to watch the video 📼

        Open Graph SEO in SvelteKit: Facebook Sharing Debugger

        You can ignore the warning about the missing fb:app_id property (see above).

        🙌🏽 Open Graph SEO in SvelteKit: Wrap Up #

        That's it for this post. We looked at:

        • what Open Graph SEO meta you should include in your website pages and posts;
        • how to generate Open Graph SEO in SvelteKit; and
        • testing your Open Graph metadata.

        In the previous post on SvelteKit SEO, as well as an introduction to SEO in general, we looked at adding SEO meta for Twitter, which is used for Twitter, Slack and other apps. In the next post in the series we will step up a gear and look at the more advanced Schema.org meta you can start including on your site pages. SchemaOrg is a protocol designed to let browsers understand what a website page is about. Using it can lead to higher ranking in Google and more prominent display of your page in search results pages. Looking forward to running through this!

        You can see the code for the story so far on the Rodney Lab GitHub repo .

        🙏🏽 Open Graph SEO in SvelteKit: Feedback #

        Please send feedback! Have you found the post useful? Would you like to see posts on another topic instead? Get in touch with ideas for new posts. Also, if you like my writing style, get in touch if I can write some posts for your company site on a consultancy basis. Read on to find ways to get in touch, further below. If you want to support posts similar to this one and can spare a couple of dollars, rupees, euros or pounds, please consider supporting me through Buy me a Coffee.

        Finally, feel free to share the post on your social media accounts for all your followers who will find it useful. As well as leaving a comment below, you can get in touch via @askRodney on Twitter and also askRodney on Telegram . Also, see further ways to get in touch with Rodney Lab. I post regularly on SvelteKit as well as other topics. Also, subscribe to the newsletter to keep up-to-date with our latest projects.

Thanks for reading this post. I hope you found it valuable. Please get in touch with your feedback and suggestions for posts you would like to see. Read more about me …

blurry low resolution placeholder image Rodney from Rodney Lab
TAGS:
SVELTEKITSEO

Likes:

Likes

  • josef profile avatar
  • Agus profile avatar
  • Kellen Mace profile avatar
  • Kevin Matsunaga profile avatar
  • Vinny profile avatar
  • Richard profile avatar
Likes provided by Mastodon & X via Webmentions.

Related Posts

blurry low resolution placeholder image Svelte Share Buttons: using Web Share API with Fallback

Svelte Share Buttons: using Web Share API with Fallback

sveltekit
<PREVIOUS POST
NEXT POST >
LATEST POST >>

Leave a comment …

Your information will be handled in line with our Privacy Policy .

Comments

  • Maxene

    Hello Rodney! Thanks so much for your post. I've been trying to figure out the best way to add social shares on Svelte, so your posts have been very informational. However, I noticed that the github link doesn't reflect everything you went over - for example, there is no button to share the blog. I haven't been able to have an image appear or hashtags/vias, so this part would be very useful for me.

    3 years ago
    • Rodney

      Hi Maxene, thanks for reaching out and for your kind feedback. I see what you are looking for, this post covers something slightly different, but there is another post for what you need. Here we are focussing on the previews which social apps show if someone pastes in a link for your site to share in a Tweet or message. Just embedding the metadata we look at lets you customise how that preview card appears on the social platform. For share buttons, see the Svelte Share Buttons post where we use the Web Share API and add Twitter, WhatsApp etc share buttons.
      3 years ago
    • Rodney

      I’m also updating the post to make it clearer what we look at here and where you can find the Social Share Button details.
      3 years ago

Ask for more

1 Nov 2022 — Astro Server-Side Rendering: Edge Search Site
3 Oct 2022 — Svelte eCommerce Site: SvelteKit Snipcart Storefront
1 Sept 2022 — Get Started with SvelteKit Headless WordPress

Copyright © 2020 – 2025 Rodney Johnson. All Rights Reserved. Please read important copyright and intellectual property information.

  • Home
  • Profile
  • Plus +
  • Newsletter
  • Contact
  • Links
  • Terms of Use
  • Privacy Policy
We use cookies  to enhance visitors’ experience. Please click the “Options” button to make your choice.  Learn more here.