eleventy-plugin-shotpipe
v0.2.0
Published
Dynamic Open Graph images for Eleventy via Shotpipe — zero build-time cost, zero-signup setup. URLs are signed locally at build time and rendered lazily on first crawler hit.
Maintainers
Readme
eleventy-plugin-shotpipe
Open Graph images for Eleventy with zero build-time cost.
An og:image plugin for 11ty that signs image URLs locally at build time (one HMAC, microseconds per page) and renders the actual image lazily on the first social-crawler hit, via Shotpipe. No headless Chrome in your build. Nothing new in CI. A thousand-page site adds nothing measurable to the build.
<meta property="og:image" content="{% ogImageUrl title, author, tag %}">Why not render at build time?
Most Eleventy og-image plugins run Satori or headless Chrome inside your build. That works, until it's the slowest thing in your deploy.
| | Build-time plugins (Satori / Puppeteer) | eleventy-plugin-shotpipe |
|---|---|---|
| Build cost per page | ~100ms–seconds, every page, every build | one HMAC (microseconds) |
| CI requirements | Chromium install, or font files for Satori | none, node:crypto only |
| CSS support | Satori: subset, no real CSS; Puppeteer: full | full (real Chrome, server-side) |
| Fonts & emoji | your problem | maintained server-side |
| Pages nobody shares | rendered and paid for anyway | never rendered at all |
| Renderer down during deploy | build fails | build unaffected, URLs sign offline |
| Dependencies | Satori/sharp/Puppeteer trees | zero |
The trade: images render on Shotpipe's servers, so you need an API key (free tier, no card). URLs are HMAC-signed, so nobody can render on your key.
Quick start
npm i eleventy-plugin-shotpipe
npx shotpipe-init # free key, no signup — writes it to .envshotpipe-init provisions a free key and writes SHOTPIPE_KEY / SHOTPIPE_SECRET
to your .env. No account, no email required (pass one — npx shotpipe-init [email protected] —
only if you want to attach the key for recovery and upgrades). Make sure your build
loads .env (via dotenv, or node --env-file=.env).
// .eleventy.js
module.exports = (eleventyConfig) => {
eleventyConfig.addPlugin(require('eleventy-plugin-shotpipe'), {
key: process.env.SHOTPIPE_KEY,
secret: process.env.SHOTPIPE_SECRET,
})
}{# in your base layout #}
<meta property="og:image" content="{% ogImageUrl title, 'Your Name', 'blog' %}">That's it. Every page gets a social card; none of them render until someone shares the page.
Using this in a starter kit
Safe to drop into a template repo. A missing key never breaks the build — if
SHOTPIPE_KEY / SHOTPIPE_SECRET aren't set, the ogImageUrl shortcode returns an
empty string and the plugin prints a one-line hint. Whoever clones the kit runs
npx shotpipe-init when they want OG images turned on, and nothing before that fails.
Templates
Hosted server-side, parameterized by query string. These previews are live renders from the API:
| | |
|---|---|
| terminal | gradient |
| minimal | default |
Every template takes title, author, tag, an accent color, and an optional logo.
Options
eleventyConfig.addPlugin(require('eleventy-plugin-shotpipe'), {
key: process.env.SHOTPIPE_KEY, // required. get one at shotpipe.io/signup
secret: process.env.SHOTPIPE_SECRET, // required
template: 'terminal', // default template for all pages
accent: '#0ea5a4', // brand color, recolors every template
logo: './src/assets/logo.png', // see "Your logo" below
baseUrl: 'https://shotpipe.io', // only for self-hosted instances
})Any option can be overridden per page by passing an object to the shortcode or to signedOgUrl:
{% ogImageUrl title %}
{% ogImageUrl title, author, tag %}// in a JS shortcode / computed data, full control
const { signedOgUrl } = require('eleventy-plugin-shotpipe')
signedOgUrl({ title, author, tag, template: 'terminal', accent: '#ff6600', w: 1200, h: 630 }, opts)Your logo
Point the plugin at a local PNG/JPG (see options above), then upload it once, and again only when it changes:
SHOTPIPE_KEY=... SHOTPIPE_SECRET=... npx shotpipe-upload-logo ./src/assets/logo.pngThe plugin references the logo by its content hash, computed locally (builds stay network-free), and the server embeds it at render time (never fetched). The logo is per-site, so one key can back many sites, each with its own.
How it works
- At build time the plugin HMAC-signs the template parameters into a URL. No network call.
- The URL sits in your
<meta og:image>tag doing nothing. - The first time a crawler (Twitter, Slack, Discord…) fetches it, Shotpipe renders the template and caches the PNG.
- Every fetch after that is a cache hit served from the edge.
Unsigned or tampered URLs are rejected, so nobody can render on your key. If the API is unreachable during your build, nothing happens; the build never talks to it.
Links
- Shotpipe: the API behind the plugin (docs, pricing)
- Get a free API key: 100 renders/month, no card, cached hits never count
