Hono Open Graph Meta Tags: Add OG to Your Hono App
How to add og:title, og:image, og:description, and Twitter card meta tags in a Hono app — deployed on Cloudflare Workers, Bun, Node.js, or any edge runtime.
Basic HTML response with OG meta tags
Hono's html helper makes it easy to return server-rendered HTML with OG meta tags embedded directly in the <head>:
// src/index.ts
import { Hono } from 'hono';
import { html } from 'hono/html';
const app = new Hono();
app.get('/blog/:slug', async (c) => {
const slug = c.req.param('slug');
const post = await getPost(slug); // your data source
return c.html(html`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>${post.title}</title>
<meta name="description" content="${post.excerpt}" />
<meta property="og:title" content="${post.title}" />
<meta property="og:description" content="${post.excerpt}" />
<meta property="og:image" content="https://yourdomain.com/og/${slug}.png" />
<meta property="og:url" content="https://yourdomain.com/blog/${slug}" />
<meta property="og:type" content="article" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="${post.title}" />
<meta name="twitter:description" content="${post.excerpt}" />
<meta name="twitter:image" content="https://yourdomain.com/og/${slug}.png" />
<link rel="canonical" href="https://yourdomain.com/blog/${slug}" />
</head>
<body>
<h1>${post.title}</h1>
</body>
</html>`);
});
export default app;Hono JSX renderer with OG tags
Hono supports JSX rendering via the hono/jsx renderer middleware. Inject OG meta tags in your layout component:
// src/index.tsx
import { Hono } from 'hono';
import { jsxRenderer, useRequestContext } from 'hono/jsx-renderer';
const app = new Hono();
app.use(jsxRenderer(({ children, title, description, ogImage, canonicalUrl }) => {
return (
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>{title}</title>
<meta name="description" content={description} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={ogImage} />
<meta property="og:url" content={canonicalUrl} />
<meta property="og:type" content="article" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={title} />
<meta name="twitter:image" content={ogImage} />
<link rel="canonical" href={canonicalUrl} />
</head>
<body>{children}</body>
</html>
);
}));
app.get('/blog/:slug', async (c) => {
const slug = c.req.param('slug');
const post = await getPost(slug);
return c.render(
<main>
<h1>{post.title}</h1>
<p>{post.excerpt}</p>
</main>,
{
title: post.title,
description: post.excerpt,
ogImage: `https://yourdomain.com/og/${slug}.png`,
canonicalUrl: `https://yourdomain.com/blog/${slug}`,
}
);
});
export default app;Dynamic OG image endpoint in Hono
Generate OG images on-demand with a dedicated Hono route that returns a PNG. On Cloudflare Workers, use @vercel/og or the Resvg-js WASM library:
// src/index.ts — OG image endpoint
import { Hono } from 'hono';
const app = new Hono();
app.get('/og/image', async (c) => {
const title = c.req.query('title') ?? 'My Page';
const desc = c.req.query('desc') ?? '';
// Generate SVG and convert to PNG (example using a simple SVG)
const svg = `<svg width="1200" height="630" xmlns="http://www.w3.org/2000/svg">
<rect width="1200" height="630" fill="#111827"/>
<text x="60" y="260" font-size="56" font-family="sans-serif" fill="white">${title}</text>
<text x="60" y="340" font-size="28" font-family="sans-serif" fill="#9ca3af">${desc}</text>
</svg>`;
// In production, use Resvg WASM to render SVG → PNG on the edge
return c.body(svg, 200, { 'Content-Type': 'image/svg+xml' });
});
export default app;Reference the endpoint in your page's OG meta tag: og:image = https://yourdomain.com/og/image?title=My+Post&desc=Short+description
Hono on Cloudflare Workers: edge caching for OG images
Add Cache-Control headers to your OG image endpoint so Cloudflare caches them at the edge and reduces generation costs:
c.header('Cache-Control', 'public, max-age=86400, s-maxage=86400, stale-while-revalidate=3600');Verify your Hono app's OG tags
After deploying, paste your URL into OGFixer to preview how your Hono app's links appear on Twitter, LinkedIn, Slack, and Discord — and catch any OG tag issues before they go live.