Express.js Open Graph Tags: Add OG Meta to Your Node App

Add og:title, og:image, og:description and Twitter card tags to any Express.js app using template engines or string interpolation — with live examples.

Express.js + EJS: the quickest setup

// views/partials/head.ejs
<head>
  <title><%= ogTitle %></title>
  <meta property="og:title"       content="<%= ogTitle %>" />
  <meta property="og:description" content="<%= ogDescription %>" />
  <meta property="og:image"       content="<%= ogImage %>" />
  <meta property="og:url"         content="<%= ogUrl %>" />
  <meta property="og:type"        content="website" />
  <meta name="twitter:card"       content="summary_large_image" />
  <meta name="twitter:title"      content="<%= ogTitle %>" />
  <meta name="twitter:image"      content="<%= ogImage %>" />
</head>

// router/posts.js
router.get('/:slug', async (req, res) => {
  const post = await Post.findOne({ slug: req.params.slug });
  res.render('post', {
    ogTitle: post.title,
    ogDescription: post.excerpt,
    ogImage: `https://yourdomain.com/og/${post.slug}.png`,
    ogUrl: `https://yourdomain.com/posts/${post.slug}`,
  });
});

Express + Handlebars (HBS)

{{! views/layouts/main.hbs }}
<head>
  <title>{{ogTitle}}</title>
  <meta property="og:title"       content="{{ogTitle}}" />
  <meta property="og:description" content="{{ogDescription}}" />
  <meta property="og:image"       content="{{ogImage}}" />
  <meta property="og:url"         content="{{ogUrl}}" />
  <meta name="twitter:card"       content="summary_large_image" />
</head>

// route
res.render('post', {
  layout: 'main',
  ogTitle: post.title,
  ogDescription: post.excerpt,
  ogImage: `https://yourdomain.com/og/${post.slug}.png`,
  ogUrl: req.protocol + '://' + req.get('host') + req.path,
});

Express middleware for default OG tags

Add a middleware that sets default OG locals so every route has a fallback:

// middleware/og-defaults.js
module.exports = (req, res, next) => {
  res.locals.ogTitle       = 'My App — Default Title';
  res.locals.ogDescription = 'Default description for my app.';
  res.locals.ogImage       = 'https://yourdomain.com/og/default.png';
  res.locals.ogUrl         = req.protocol + '://' + req.get('host') + req.originalUrl;
  next();
};

// app.js
app.use(require('./middleware/og-defaults'));
// Individual routes can override res.locals.ogTitle etc.

Express API + SPA frontend

If Express is your API backend and a React/Vue SPA is your frontend, OG tags must be set server-side — either via SSR, prerendering, or a dedicated bot-detection middleware that returns full HTML for scrapers. SPAs don't work for OG tags because social scrapers don't execute JavaScript.

The easiest solution: use a prerendering service like Prerender.io or serve a special SSR response when User-Agent matches a known scraper bot.

Verify your Express OG tags

After deploying, paste your URL into OGFixer to preview how Twitter, Slack, Discord, and LinkedIn will render your links.

Related guides