CommunityImagegithub.com

getpaidskills/og-image-kit

Generates Open Graph / Twitter (X) share images for every page of a website and wires up the og:* and twitter:* meta tags, then verifies the social preview. Supports Next.js App Router (opengraph-image.tsx with next/og ImageResponse), Astro (build-time PNGs via satori + resvg) and any static site (Pillow script). Use when the user asks for OG images, social share cards, link previews, "my link looks bad on X/Slack/LinkedIn/WeChat", twitter:card, or before launching a site.

What is og-image-kit?

og-image-kit is a Claude Code agent skill that generates Open Graph / Twitter (X) share images for every page of a website and wires up the og:* and twitter:* meta tags, then verifies the social preview. Supports Next.js App Router (opengraph-image.tsx with next/og ImageResponse), Astro (build-time PNGs via satori + resvg) and any static site (Pillow script). Use when the user asks for OG images, social share cards, link previews, "my link looks bad on X/Slack/LinkedIn/WeChat", twitter:card, or before launching a site.

Works with~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/getpaidskills/skills/tree/HEAD/skills/og-image-kit

Installed? Explore more Image skills: steipete/songsee, affaan-m/frontend-design, mattpocock/improve-codebase-architecture · View all 6 →

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

What does og-image-kit do?

Goal: every public page has a 1200×630 share image and correct og:* / twitter:* tags, and you have verified them with scripts/check_og.py, not just written them.

Step 1 — Detect the stack

Look at the repo before writing anything:

SignalStackGo to
next in package.json and an app/ (or src/app/) dirNext.js App RouterStep 2A
next with only pages/Next.js Pages RouterStep 2C (static) or add /api/og with ImageResponse
astro in package.jsonAstroStep 2B
Plain HTML, Hugo, Jekyll, Vite SPA, anything elseStaticStep 2C

Also find: the site's canonical base URL (env var like NEXT_PUBLIC_SITE_URL, site in astro.config.*), brand colors, logo, and the font in use. Ask the user only if none can be found.

Step 2A — Next.js App Router

  1. Make sure the root layout exports metadataBase (OG URLs must be absolute):
    export const metadata = { metadataBase: new URL(process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3000") }
    
  2. Copy assets/nextjs/opengraph-image.tsx to app/opengraph-image.tsx (site default). Edit BRAND, colors and tagline.
  3. For dynamic routes (blog posts, products) copy it into the route segment, e.g. app/blog/[slug]/opengraph-image.tsx, and use assets/nextjs/dynamic-opengraph-image.tsx, which reads params and loads the title from your data source. In Next.js 15+ params is a Promise — await it.
  4. Also add twitter-image.tsx only if the X card must differ; otherwise Next.js reuses the OG image when you set twitter: { card: "summary_large_image" } in metadata.
  5. Per-page text: set title and description in each page's metadata / generateMetadata.
  6. Custom fonts: load a TTF/OTF (not WOFF2) via fetch(new URL("./Inter-Bold.ttf", import.meta.url)) or readFile. CJK text needs a CJK font file or it renders as boxes — subset it to keep size down.

Limits to respect (next/og / satori): flexbox only (no grid), every multi-child div needs display: "flex", keep the bundle small — the Next.js ImageResponse docs list a 500 KB limit for JSX + CSS + fonts + images. Large fonts also slow rendering, so subset them.

Step 2B — Astro

Use assets/astro/og-endpoint.ts as src/pages/og/[...slug].png.ts. It renders a PNG per page at build time with satori + @resvg/resvg-js (npm i satori @resvg/resvg-js), and you reference it from your layout:

<meta property="og:image" content={new URL(`/og/${slug}.png`, Astro.site)} />

Astro.site must be set in astro.config.mjs. Font file: put a TTF in src/assets/fonts/.

Step 2C — Static sites / anything else

Generate PNGs once and commit them:

python3 scripts/generate_og.py --pages pages.json --out public/og --brand "Acme" --bg "#0f172a" --fg "#ffffff" --accent "#38bdf8"

pages.json is a list of {"slug": "pricing", "title": "...", "subtitle": "..."} (see assets/pages.example.json). Requires Pillow (pip install pillow). Pass --font path/to/font.ttf for brand fonts or CJK text (e.g. Noto Sans SC). Then add tags to each page (template in references/meta-tags.md).

Step 3 — Required tags (every page)

<meta property="og:title" content="Page title" />
<meta property="og:description" content="One sentence, ≤ ~160 chars" />
<meta property="og:image" content="https://example.com/og/page.png" />   <!-- absolute URL -->
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:url" content="https://example.com/page" />
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary_large_image" />

Next.js generates these from metadata + opengraph-image.tsx; do not hand-write duplicates.

Step 4 — Verify (do not skip)

Run against the running site (dev server, preview deploy, or production):

python3 scripts/check_og.py http://localhost:3000/ http://localhost:3000/pricing
python3 scripts/check_og.py --json https://example.com/   # machine-readable

It fetches each page, checks the required tags, that og:image is absolute, reachable, an image content-type, ~1.91:1 and at least 600 px wide, and under 5 MB. Exit code 1 on any error. Fix everything marked ERROR; WARN items are recommendations.

Note: social platforms cache previews. After fixing, use the platform's own debugger (LinkedIn Post Inspector, Facebook Sharing Debugger) to re-scrape. X has no public validator any more; post in a draft/DM to check. localhost URLs cannot be scraped by those tools — deploy first.

Design rules for the image

  • 1200×630, PNG, text inside a ~60 px safe margin; title ≤ ~60 chars, max 3 lines.
  • High contrast; it is shown small (~500 px wide) in feeds. Test at 50% zoom.
  • Include brand name/logo; avoid tiny text (< 28 px at 1200 width).
  • See references/platform-specs.md for per-platform notes.

Done when

  • Every indexable page returns og:title, og:description, og:image (absolute), twitter:card
  • check_og.py exits 0 for the home page and at least one page of each route type
  • Images look right (open one PNG and look at it)

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

getpaidskills/agents-md-starter

Creates or upgrades a repository's AGENTS.md (read by Codex, Cursor, and other agents) and a CLAUDE.md that imports it, so Claude Code, Codex, Cursor and Gemini CLI share one set of project rules. Scans the repo to detect languages, package manager, real build/test/lint commands, framework, directory layout and existing rule files (.cursorrules, .cursor/rules, CLAUDE.md, copilot-instructions), then writes a concise, verified rules file. Use when the user asks to set up AGENTS.md or CLAUDE.md, "project rules", "make Claude Code and Codex follow the same conventions", onboard an agent to a repo, or migrate .cursorrules.

getpaidskills/directory-launch-kit

Prepares a product for submission to launch platforms and directories (Product Hunt, Show HN, BetaList, Uneed, Fazier, SaaSHub, TinyLaunch, AI tool directories, agent-skill marketplaces, Reddit, V2EX and more) without submitting anything itself. Picks only the directories the product fits, writes the copy for each form within its field limits from one product.json, resizes screenshots to each platform's sizes (Product Hunt 1270x760 gallery and 240x240 thumbnail, 1200x630 OG), builds a tracker CSV, re-checks prices and rules on the live pages, and later verifies which listings went live and whether their backlinks are follow or nofollow. Use when the user asks where to launch, how to submit to Product Hunt or AI directories, wants launch copy, a directory list, backlinks, or a launch tracker.

getpaidskills/launch-checklist

Pre-launch audit for a website or SaaS - checks SEO tags (title, description, canonical, lang, Open Graph), robots.txt, sitemap.xml, favicon and apple-touch-icon, real 404 status, HTTPS redirect, legal pages (privacy, terms, refund), image alt text, page weight and response time, plus a payment self-check (webhook signature, raw body, idempotency, refunds, secrets, success-page grants), then lists the problems and fixes them in the codebase. Ships a no-dependency crawler script (audit_site.py) that produces a pass/warn/fail report. Use when the user says they are about to launch, ship, go live, submit to Product Hunt or AI directories, or asks "is my site ready", "SEO check", "why is my site not indexed", or wants a launch checklist, or asks whether their payment or webhook setup is safe.

getpaidskills/legal-pages

Drafts a Privacy Policy, Terms of Service and Refund Policy for a SaaS, digital product or website from a short questionnaire, adapted to the payment provider (Creem, Paddle, Lemon Squeezy as Merchant of Record, or Stripe/direct) and to where users are (EU/UK GDPR, California CCPA/CPRA, China PIPL notes), then renders them as Markdown, HTML or Next.js pages and links them in the footer. Output is a starting template, NOT legal advice - the user must review it and have it checked by a qualified lawyer. Use when the user needs privacy policy, terms, refund policy, legal pages, or a payment provider (Paddle/Creem/Lemon Squeezy/Stripe) review asks for them.

Related Skills