Integrating OpenGraphImage.com with Hugo

OpenGraphImage.com is a service that will generate images from HTML templates. By leveraging Hugo’s custom output formats we can make quick work of this task and have dynamic opengraph images for each page in our site.

First thing we need to do is add the custom outputFormats and outputs to the hugo/src/config.yaml file.

# ...

outputFormats:
  OG:
    path: '/og/'
    mediaType: 'text/html'
    permalinkable: false
    noUgly: true

outputs:
  page:
    - HTML
    - OG
  home:
    - HTML
    - RSS
    - OG
  section:
    - HTML
    - OG
  taxonomy:
    - HTML
    - OG
  term:
    - HTML
    - OG

This tells Hugo that we want to generate an additional HTML file per page of our site in the /og/... folder, matching the path of the primary HTML version.

This additional HTML page will become the page OpenGraphImage.com will capture a snapshot of.

Next thing we need to do is create a new layout for the OG output. The base template will be hugo/src/layouts/_default/baseof.og.html. To get everything working, we will simply output the site title in white text on a black background using TailwindCSS.

<!-- hugo/src/layouts/_default/baseof.og.html -->
<!doctype html>
<html>
  <head>
    {{ block "head" . }}
      <title>{{ .Title }}</title>
      {{ partial "style" . }}
    {{ end }}
  </head>
  <body class="relative flex flex-col h-screen">
    <div class="flex items-center content-center w-full h-full bg-neutral-100">
      <div class="w-[1200px] mx-auto">
        <div class="aspect-w-[1.9] aspect-h-1 overflow-hidden">

          {{ block "main" . }}
            <div class="text-white bg-neutral-900">
              <div class="relative flex items-center w-full h-full p-24">
                <div>
                  <div class="mb-4 text-7xl">
                    {{ .Title }}
                  </div>
                  <div class="text-3xl text-neutral-400">
                    {{ .Permalink }}
                  </div>
                </div>
              </div>
            </div>
          {{ end }}

        </div>
      </div>
    </div>
  </body>
</html>

We also need a .og.html layout for the list and single. I will keep these blank so the default layout will be used, but, this is how you can customize the OpenGraph image for each page, section, taxonomy and term.

<!-- hugo/src/layouts/_default/list.og.html -->
<!-- hugo/src/layouts/_default/single.og.html -->

{{ define "main" }}
{{ end }}

With that, we can ./up.sh and open a browser to http://localhost:1313/og/ and see what our OpenGraph image will look like.

Next, in order to configure the OpenGraphImage.com origin, we need to deploy the site to the internet. This way OpenGraphImage.com will be able to access the OG html pages. Deployment is out of scope for this article so the next steps will assume that you have already deployed to https://www.example.com.

With your public website URL ready, you’ll need to create an origin from your OpenGraphImage.com dashboard.

Name the origin something to help you identify it in the future, then set the “Render Base Url” to your OG path https://www.example.com/og and click the “Generate Default Image” button. You should then see a preview showing our site title in white text on a black background.

Set the “Default Link” field to your website homepage https://www.example.com, everything else is optional. After clicking the create button, you will be taken to the origin detail page where you will get the KEY and SECRET needed to generate the required signature.

Let’s save these values in our hugo/.env file and ./up.sh again.

# hugo/.env
HUGO_OPENGRAPH_KEY=KEY
HUGO_OPENGRAPH_SECRET=SECRET

With the environment variables set we can create a partial to generate the OpenGraphImage.com url. OpenGraphImage.com will map the https://cdn.opengraphimage.com/KEY our website at the “Render Base Url” we specified earlier. For example https://cdn.opengraphimage.com/KEY/folder/page/ will reference https://www.example.com/og/folder/page/.

This way, we can generate an image per page of our site.

<!-- hugo/src/layouts/partials/og.html -->

{{ $key := getenv "HUGO_OPENGRAPH_KEY" }}
{{ $secret := getenv "HUGO_OPENGRAPH_SECRET" }}
{{ $path := printf "%s%s" $key .RelPermalink }}
{{ $signature := md5 (printf "%s%s" $secret $path)}}
{{ $image_url := printf "https://cdn.opengraphimage.com/%s?s=%s" $path $signature }}

<meta property="og:image" content="{{ $image_url }}"/>
<meta property="og:image:width" content="1200"/>
<meta property="og:image:height" content="630"/> 
<meta name="twitter:card" property="twitter:card" content="summary_large_image"/>

Last thing we need to do is call the partial from the hugo/src/layouts/_default/baseof.html layout.

<!-- hugo/src/layouts/_default/baseof.html -->

<html lang="{{ .Lang }}">
  <head>
    <!-- ... -->

    {{ block "head" . }}
      <!-- ... -->

      {{ partial "og" . }}
    {{ end }}
  </head>

  <!-- ... -->
</html>

At this point we have Hugo building our OpenGraph images dynamically based on the page data and have generated the OpenGraphImage.com url for the social share image. We can now deploy our site and use one of the OpenGraph image debugginhg tools: