Django Open Graph Meta Tags: Add OG Tags to Templates and Views

Learn how to add og:title, og:image, og:description, and Twitter card tags to Django templates — with per-view dynamic data and a reusable base template pattern.

Why Django is great for OG tags

Django renders HTML on the server, so social crawlers automatically receive a fully populated page — including any <meta> tags in your templates. There is no JavaScript execution step; what Django renders is what crawlers read. This makes adding OG tags straightforward: it's just HTML in a template.

Base template with OG tag blocks

The cleanest pattern is to define default OG tags in a base.html template and override them in child templates using Django's {% block %} tag:

{# templates/base.html #}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>{% block title %}My Django Site{% endblock %}</title>

  {# Open Graph #}
  <meta property="og:title" content="{% block og_title %}My Django Site{% endblock %}">
  <meta property="og:description" content="{% block og_description %}Default site description.{% endblock %}">
  <meta property="og:image" content="{% block og_image %}https://example.com/og-default.jpg{% endblock %}">
  <meta property="og:url" content="{% block og_url %}https://example.com{% endblock %}">
  <meta property="og:type" content="{% block og_type %}website{% endblock %}">

  {# Twitter Card #}
  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:title" content="{% block twitter_title %}My Django Site{% endblock %}">
  <meta name="twitter:description" content="{% block twitter_description %}Default site description.{% endblock %}">
  <meta name="twitter:image" content="{% block twitter_image %}https://example.com/og-default.jpg{% endblock %}">
</head>
<body>
  {% block content %}{% endblock %}
</body>
</html>

Override in child templates

In any page template that extends base.html, override only the blocks you need:

{# templates/blog/post_detail.html #}
{% extends "base.html" %}

{% block title %}{{ post.title }} | My Blog{% endblock %}

{% block og_title %}{{ post.title }}{% endblock %}
{% block og_description %}{{ post.excerpt }}{% endblock %}
{% block og_image %}{{ post.cover_image_url }}{% endblock %}
{% block og_url %}https://example.com/blog/{{ post.slug }}/{% endblock %}
{% block og_type %}article{% endblock %}

{% block twitter_title %}{{ post.title }}{% endblock %}
{% block twitter_description %}{{ post.excerpt }}{% endblock %}
{% block twitter_image %}{{ post.cover_image_url }}{% endblock %}

{% block content %}
  <h1>{{ post.title }}</h1>
  {{ post.body }}
{% endblock %}

Passing OG data from views

Pass context variables from your view and render them directly in the template:

# views.py
from django.shortcuts import render, get_object_or_404
from .models import Post

def post_detail(request, slug):
    post = get_object_or_404(Post, slug=slug)
    og_image = post.cover_image.url if post.cover_image else request.build_absolute_uri('/static/og-default.jpg')
    return render(request, 'blog/post_detail.html', {
        'post': post,
        'og_image': og_image,
        'og_url': request.build_absolute_uri(),
    })

Use request.build_absolute_uri() to generate absolute URLs for og:url and image paths.

django-meta package

For complex sites, the django-meta package provides a structured approach with model mixins, view mixins, and template tags:

pip install django-meta

# settings.py
INSTALLED_APPS = [..., 'meta']
META_SITE_PROTOCOL = 'https'
META_USE_OG_PROPERTIES = True
META_USE_TWITTER_PROPERTIES = True

# models.py
from meta.views import Meta
class Post(models.Model):
    # ...
    def as_meta(self, request):
        return Meta(
            title=self.title,
            description=self.excerpt,
            image=request.build_absolute_uri(self.cover_image.url),
            url=request.build_absolute_uri(self.get_absolute_url()),
            object_type='article',
        )

Common Django OG tag mistakes

  • Relative image paths: og:image must be an absolute URL. Use request.build_absolute_uri() in views.
  • HTML-encoding issues: special characters in titles or descriptions must be HTML-escaped. Django's auto-escaping handles this in templates, but verify with {{ value|escape }}.
  • Missing fallbacks: always define default OG values in your base template for pages without specific overrides.

Preview your OG tags free at OGFixer.com → Paste your Django URL to see exactly how your link card renders on Twitter, LinkedIn, Discord, and Slack.

← All guides