Getting Started

OpenGraph images are created by taking a snapshot of a webpage hosted on your own webserver. If you dont have a webserver readily available, you can create a project site from scratch in Github Pages and use the template for your index.html.

You can use the template below as a base for creating your own templates. This template sets up a canvas that will support the default 1200x600 or 1200x630 sizes and uses tailwindcss and alpinejs. The rendering process will automatically set the canvas size so you do not need to include the canvas element in your templates.

<!doctype html>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src=""></script>
    <script src="" defer></script>
  <body class="h-screen">
    <div class="flex items-center h-full bg-neutral-800">
      <div class="relative w-full h-full mx-auto overflow-hidden bg-white" x-data="openGraphImage();">

        <!-- Start: Your HTML Template -->
        <h1 class="flex items-center justify-center h-full text-3xl">
          <span x-text="params.title || 'Use the `title` query parameter to change me.'"></span>
        <!-- End: Your HTML Template -->


      document.addEventListener('alpine:init', () => {'openGraphImage', () => {
          const params = new URLSearchParams(;

          return {
            params: Object.fromEntries(params.entries()),

            init() {
              window.__og = window.__og || [];

              // Set the default destination for ``
              window.__og.push(['link', '']);

              // Give alpine.js a chance to finish before triggering the render
              this.$nextTick(() => {


If you went the GitHub pages route, you should have a URL that looks something like this:

Even if you have your own webserver you still have a URL that is comprosed of these parts:

Setting Up your Origin

The HOST is what you will use for the “Render Base URL” when creating your origin. The “Render Base URL” can also include a base path to help you organize your templates. This is especially handy when you need to create a default image for a template that has a different render size.

Building Your URL

Your origin KEY is combined with the PATH and QUERY STRING to create the path for your image. The DOMAIN part of the url can be, to render an image, or for redirecting the user to the link specified using the javascript api.

You can also use the shorter and domains.

During the render process, the PATH and QUERY STRING are passed to the “Render Base URL” server, along with any default render params behind the scenes.

While this URL will work, it will only return the default image you created when setting up the origin. We serve the default image whenever we encounter an error from your host, rendering, or if we get a missing or invalid signature.

Securing Your Renders

To complete your URL, you will need to generate the signature using the origin SECRET and KEY combined with the PATH and QUERY STRING. Signed URLs should only be generated on a server or at build time.

Once you have the MD5 hash signature, you will append it to the end of the querystring as an s parameter.

Here are some other things to look out for when building your URL:

  • All querystring keys and values must also be percent encoded before signing.
  • Ensure the path you are signing starts with your origin key and not a /

Once you have the signed URL, you can use it for your og:image meta tags or image src as described in the documentation.

Example Code For Generating An MD5 Signature


const crypto = require('crypto');

const getOGImageUrl = (basePath, key = 'key', secret = 'secret') => {
  const path = `${key}${basePath}`;
  const signature = crypto.createHash('md5').update(`${secret}${path}`).digest('hex').toString();

  if (path.indexOf('?') === -1) {
    return `${path}&s=${signature}`;

  return `${path}?s=${signature}`;

console.log(`<meta property="og:image" content="${getOGImageUrl('/my-page-url/')}">`);


defmodule OpenGraphImage do
  def get_og_image_url(base_path, key \\ "key", secret \\ "secret") do
    path = "#{key}#{base_path}"
    signature =
      :crypto.hash(:md5, "#{secret}#{path}") |> Base.encode16(case: :lower)

    if String.contains?(path, "?") do

IO.puts ~s(<meta property="og:image" content="#{OpenGraphImage.get_og_image_url("/my-page-url/")}">)



function getOGImageUrl($basePath, $key = 'key', $secret = 'secret') {
    $path = $key . $basePath;
    $signature = md5($secret . $path);

    if (strpos($path, '?') === false) {
        return "" . $path . "&s=" . $signature;

    return "" . $path . "?s=" . $signature;

echo '<meta property="og:image" content="' . getOGImageUrl('/my-page-url/') . '">';


Create living images and links, dynamically generated and personalized on the fly for embedding on your website or email campaigns.

© 2024 OpenGraphImage, LLC. All rights reserved.