Eleventy (11ty) Open Graph Meta Tags: Add OG to Nunjucks and Liquid

Add og:title, og:image, og:description, and Twitter card tags to Eleventy (11ty) sites using Nunjucks macros, Liquid includes, and front matter data.

Why Eleventy is OG-friendly

Eleventy (11ty) is a static site generator that builds plain HTML files at build time. There's no JavaScript runtime needed for crawlers — your OG tags are baked directly into the HTML. The challenge is making the templates dynamic enough to generate unique OG tags per page.

Eleventy supports multiple template languages: Nunjucks, Liquid, Handlebars, Markdown, and JavaScript. The examples below cover Nunjucks (most popular) and Liquid.

Base layout with OG tags (Nunjucks)

Create a base layout in _includes/base.njk with dynamic OG tag variables:

{# _includes/base.njk #}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>{{ title or metadata.title }} | {{ metadata.title }}</title>

  {# Open Graph #}
  <meta property="og:title" content="{{ title or metadata.title }}" />
  <meta property="og:description"
    content="{{ description or metadata.description }}" />
  <meta property="og:image"
    content="{{ ogImage or metadata.url + metadata.defaultOgImage }}" />
  <meta property="og:url"
    content="{{ metadata.url + page.url }}" />
  <meta property="og:type"
    content="{{ ogType or 'website' }}" />
  <meta property="og:site_name"
    content="{{ metadata.title }}" />

  {# Twitter Card #}
  <meta name="twitter:card" content="summary_large_image" />
  <meta name="twitter:title" content="{{ title or metadata.title }}" />
  <meta name="twitter:description"
    content="{{ description or metadata.description }}" />
  <meta name="twitter:image"
    content="{{ ogImage or metadata.url + metadata.defaultOgImage }}" />
</head>
<body>
  {{ content | safe }}
</body>
</html>

Global data in _data/metadata.json

// _data/metadata.json
{
  "title": "My Eleventy Site",
  "description": "My site description.",
  "url": "https://example.com",
  "defaultOgImage": "/images/og-default.jpg",
  "twitterHandle": "@yourtwitterhandle"
}

Per-page OG tags in front matter

---
title: My Blog Post
description: A description specifically for this blog post.
ogImage: /images/posts/my-post-og.jpg
ogType: article
layout: base.njk
date: 2026-03-15
---

# Post content here

Liquid template version

For Liquid templates, the syntax is slightly different:

{# _includes/og-tags.liquid #}
{% assign og_title = title | default: metadata.title %}
{% assign og_desc = description | default: metadata.description %}
{% if ogImage %}
  {% assign og_img = ogImage | prepend: metadata.url %}
{% else %}
  {% assign og_img = metadata.defaultOgImage | prepend: metadata.url %}
{% endif %}

<meta property="og:title" content="{{ og_title | escape }}" />
<meta property="og:description" content="{{ og_desc | escape }}" />
<meta property="og:image" content="{{ og_img }}" />
<meta property="og:url" content="{{ page.url | prepend: metadata.url }}" />
<meta property="og:type" content="{{ ogType | default: 'website' }}" />

Common Eleventy OG mistakes

  • Missing site URL in _data: without a base URL, image paths can't be made absolute. Always define metadata.url.
  • page.url includes trailing slash: Eleventy's page.url has a trailing slash by default. Account for this when concatenating URLs.
  • Not escaping values: use | escape in Liquid or | escape in Nunjucks to prevent HTML injection in meta attributes.

Preview your OG tags free at OGFixer.com → Paste your Eleventy site URL to verify how your link card looks on Twitter, LinkedIn, Discord, and Slack.

← All guides