Skip to content

phucbm/next-og-image

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@phucbm/next-og-image

npm version npm downloads npm dependents github stars github license

Tiny helpers to ship Open Graph images and page metadata in Next.js (Edge-ready). Drop-in defaults, easy overrides, and a dead-simple render API.


Install

pnpm add @phucbm/next-og-image

Requires: Next.js 13.4+ (App Router), React 18+, Node 18+. Recommended: export const runtime = "edge" for the OG route.


Quick start

1) Default OG image (no custom component)

app/api/og-image/route.ts

import { renderOgImage } from "@phucbm/next-og-image";

export const runtime = "edge";

export async function GET(request: Request) {
  return renderOgImage(request);
}

app/(default)/page.tsx

import { generatePageMetadata } from "@phucbm/next-og-image";

export const generateMetadata = generatePageMetadata({
  siteName: "Example Site",
  title: "Example Site - Design. Code. Repeat.",
  description: "A simple demo page for Open Graph metadata.",
  canonicalPath: "/",
});

Open: /api/og-image?siteName=Example&title=Hello&description=World


Custom OG image component

app/api/og-image/route.ts

import { renderOgImage } from "@phucbm/next-og-image";
import { OgImage } from "@/components/OgImage";

export const runtime = "edge";

export async function GET(request: Request) {
  return renderOgImage(request, OgImage);
}

Your OgImage receives { siteName, title, description } as props.


Use a static image instead of generated one

import { generatePageMetadata } from "@phucbm/next-og-image";

export const generateMetadata = generatePageMetadata({
  siteName: "Example Site",
  title: "Example Site - Design. Code. Repeat.",
  description: "A simple demo page for Open Graph metadata.",
  canonicalPath: "/",
  imageUrl: "/images/hero-image-01.jpg", // from /public/images/hero-image-01.jpg
});

Pass custom data into your OG component (e.g., logo)

app/api/og-image/route.tsx

import { type OgImageRenderFn, renderOgImage } from "@phucbm/next-og-image";
import { OgImage } from "@/components/OgImage";

export const runtime = "edge";

export async function GET(request: Request) {
  const origin = new URL(request.url).origin;
  const logoUrl = new URL("/logo.png", origin).toString(); // /public/logo.png -> /logo.png

  const render: OgImageRenderFn = (props) => <OgImage {...props} logoUrl={logoUrl} />;

  return renderOgImage(request, render, { width: 1200, height: 630 });
}

components/OgImage.tsx

import type { OgImageInput } from "@phucbm/next-og-image";

type Props = OgImageInput & { logoUrl?: string };

export function OgImage({ siteName, title, description, logoUrl }: Props) {
  return (
    <div style={{
      width: "100%", height: "100%", display: "flex", flexDirection: "column",
      justifyContent: "space-between", padding: "48px", color: "#141413",
      background: "linear-gradient(135deg, #f0eee6, #faf9f6)"
    }}>
      <div style={{ display: "flex", alignItems: "center", gap: 16 }}>
        {logoUrl && <img src={logoUrl} alt="" width="88" height="88" />}
        {siteName && <div style={{ fontSize: 70, fontWeight: 800, letterSpacing: "-0.02em" }}>{siteName}</div>}
      </div>

      <div style={{ display: "flex", flexDirection: "column", gap: "24px" }}>
        <h1 style={{ fontSize: 120, fontWeight: 800, margin: 0 }}>{title}</h1>
        {description && (
          <p style={{ fontSize: 56, margin: 0, maxWidth: "1000px", opacity: 0.95 }}>
            {description}
          </p>
        )}
      </div>
    </div>
  );
}

Important:

  • Put the image in /public/logo.png and reference it as /logo.png.
  • next/og requires an absolute URL inside the renderer; always build from req.url’s origin (as shown).

API

renderOgImage(request, render?, options?)

  • request: the Request from your API route.

  • render?: (props: OgImageInput) => ReactElement — custom renderer for the image.

    • props includes { siteName: string; title: string; description: string | null }.
  • options?: ImageResponseOptions (e.g., { width, height, headers, emoji, fonts, ... }).

Returns a new ImageResponse(...).

generatePageMetadata(input)

  • Builds a Next.js Metadata object and wires the page’s OG/Twitter tags.
  • If imageUrl is not provided, it generates a URL to your /api/og-image with the page’s values.
  • Accepts all your SEO fields plus any native Metadata keys.

Null-override behavior (for social image): If you pass socialImage: { title: null }, that field is intentionally hidden (no fallback to page title). undefined continues to fallback.


Tips & Gotchas

  • Route must handle JSX → name it route.tsx if you inline JSX.

  • Import React when using JSX in API routes:

    import React from "react";
  • Absolute URLs only for <img src>. Build from new URL(req.url).origin.

  • SVGs are not supported by next/og — use PNG/JPEG/WebP.


Showcase

Projects using this package:


Chrome Extension

Use Social Share Preview (by Placid app) to quickly test OG images in the browser.


Example query (dev)

/api/og-image?siteName=Example&title=Hello&description=Ship+it

That’s it. Copy the snippets above into your app and you’re live.

License

MIT © PHUCBM

About

Tiny helpers to ship Open Graph images and page metadata in Next.js.

Topics

Resources

License

Stars

Watchers

Forks

Contributors 3

  •  
  •  
  •