Go Open Graph Meta Tags: Add OG to Your Go Web App
How to add og:title, og:image, og:description, and Twitter card meta tags in Go — using net/http, html/template, Gin, Echo, or Fiber.
Standard library: net/http + html/template
// main.go
package main
import (
"html/template"
"net/http"
)
type PageData struct {
Title string
Description string
OGImage string
CanonicalURL string
}
var tmpl = template.Must(template.New("page").Parse(`<!DOCTYPE html>
<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><h1>{{.Title}}</h1></body>
</html>`))
func blogPostHandler(w http.ResponseWriter, r *http.Request) {
slug := r.PathValue("slug") // Go 1.22+ path value
post := getPost(slug) // your data source
data := PageData{
Title: post.Title,
Description: post.Excerpt,
OGImage: "https://yourdomain.com/og/" + slug + ".png",
CanonicalURL: "https://yourdomain.com/blog/" + slug,
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
tmpl.Execute(w, data)
}
func main() {
http.HandleFunc("/blog/{slug}", blogPostHandler)
http.ListenAndServe(":8080", nil)
}Gin framework
// main.go — Gin
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.LoadHTMLGlob("templates/*")
r.GET("/blog/:slug", func(c *gin.Context) {
slug := c.Param("slug")
post := getPost(slug)
c.HTML(http.StatusOK, "post.html", gin.H{
"Title": post.Title,
"Description": post.Excerpt,
"OGImage": "https://yourdomain.com/og/" + slug + ".png",
"CanonicalURL": "https://yourdomain.com/blog/" + slug,
})
})
r.Run(":8080")
}{{/* templates/post.html */}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{.Title}}</title>
<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:image" content="{{.OGImage}}">
<link rel="canonical" href="{{.CanonicalURL}}">
</head>
<body><h1>{{.Title}}</h1></body>
</html>Echo and Fiber
Both follow the same pattern — render an HTML template with OG meta values injected:
// Echo
e.GET("/blog/:slug", func(c echo.Context) error {
slug := c.Param("slug")
post := getPost(slug)
return c.Render(http.StatusOK, "post.html", map[string]interface{}{
"Title": post.Title,
"Description": post.Excerpt,
"OGImage": "https://yourdomain.com/og/" + slug + ".png",
"CanonicalURL": "https://yourdomain.com/blog/" + slug,
})
})
// Fiber
app.Get("/blog/:slug", func(c *fiber.Ctx) error {
slug := c.Params("slug")
post := getPost(slug)
return c.Render("post", fiber.Map{
"Title": post.Title,
"Description": post.Excerpt,
"OGImage": "https://yourdomain.com/og/" + slug + ".png",
"CanonicalURL": "https://yourdomain.com/blog/" + slug,
})
})Go OG image generation with the image package
// og_image.go — generates a simple OG PNG from a title string
package main
import (
"image"
"image/color"
"image/draw"
"image/png"
"net/http"
)
func ogImageHandler(w http.ResponseWriter, r *http.Request) {
img := image.NewRGBA(image.Rect(0, 0, 1200, 630))
draw.Draw(img, img.Bounds(), &image.Uniform{color.RGBA{17, 17, 17, 255}}, image.Point{}, draw.Src)
// Add text using a font package like golang.org/x/image/font
// (simplified for clarity — use freetype or go-text/typesetting in production)
w.Header().Set("Content-Type", "image/png")
w.Header().Set("Cache-Control", "public, max-age=86400")
png.Encode(w, img)
}Verify your Go app's OG tags
After deploying, paste your URL into OGFixer to preview how your Go app's links appear on Twitter, LinkedIn, Slack, and Discord — and catch any OG tag issues before they go live.