socialcard
What it does
On every publish, socialcard reads the post's title, author, and publish date, renders one of three SVG card templates, uploads it, and writes the URL to post.data.metadata.ogImage. Your theme points og:image at that URL. No design tool, no third-party image service.
It only runs for content with status published. Drafts, archived, and scheduled content are skipped. A rendering or upload error is logged, never thrown - a bad card is never a reason to fail a publish.
Install
npm install @plugdash/socialcardRegister
Open astro.config.mjs at the root of your Astro project. Import the plugin at the top, then add it to the pluginsarray of the emdash() integration - the one that sits inside Astro's top-level integrations array:
import { defineConfig } from "astro/config"
import emdash from "emdash/astro"
import { socialcardPlugin } from "@plugdash/socialcard"
export default defineConfig({
integrations: [
emdash({
plugins: [
socialcardPlugin({
template: "bold",
background: "#111827",
foreground: "#fef3c7",
}),
],
}),
],
})Configuration
Pass options at register time. They are seeded into the plugin's KV store on install, and reseeded automatically whenever the config object in astro.config.mjs changes - so editing the file and restarting is enough, you don't need to touch the admin.
Props
| prop | type | default | description |
|---|---|---|---|
template | "default" | "minimal" | "bold" | "default" | Card layout |
width | number | 1200 | Card width in pixels |
height | number | 630 | Card height in pixels |
background | string (hex) | "#0f172a" | Background colour |
foreground | string (hex) | "#f8fafc" | Text (and, on minimal, paper) colour |
logo | string (URL) | Logo drawn in the top-left corner | |
fonts.title | string (CSS font stack) | system sans | Font stack for the title line |
fonts.body | string (CSS font stack) | system sans | Font stack for the byline |
Templates
There are three built-in layouts:
- default - large title, small author + date byline, subtle gradient over the background colour
- minimal - title only, on a clean paper background (the palette is inverted from the other two, so the defaults read as dark text on light paper)
- bold - large type set against a strong colour block down the left edge
Here's the same post rendered with each one:



Titles over 80 characters are truncated with an ellipsis. The byline is author and date joined by a middle dot - if either is missing, that half is dropped; if both are missing, the byline line is omitted entirely rather than left blank.
Using the card in your layout
Read metadata.ogImage from the post and point your meta tags at it:
---
const post = await emdash.content.get("posts", Astro.params.id)
const { ogImage } = post.data.metadata ?? {}
---
{ogImage && <meta property="og:image" content={ogImage} />}
{ogImage && <meta property="og:image:width" content="1200" />}
{ogImage && <meta property="og:image:height" content="630" />}
{ogImage && <meta name="twitter:image" content={ogImage} />}One real limitation worth knowing before you rely on this: the card is an image/svg+xml file, not a PNG. Most OG consumers accept SVG fine, but Twitter/X and Facebook specifically rejectimage/svg+xml for og:image andtwitter:image. Treat this as an interim format until a rasterised version ships - see the package README for why (a sandboxed plugin bundle has no way to load the font binary or wasm blob that a PNG renderer needs).
No component
socialcard has no companion Astro component. It is pure infrastructure - it writes a URL to metadata and gets out of the way. Wiring that URL into your <head> is a couple of meta tags in your own layout, shown above.
For agents
After installing and registering the plugin, publish a test post and confirm post.data.metadata.ogImage is populated with a URL ending in .svg. If it is not:
- Check the post status is "published", not draft
- Confirm the plugin declares
content:read,content:write, andmedia:write - Republish - existing posts saved before the plugin was installed need a new save to pick it up