Skip to content
Template · blog-post@1

Blog post template

The blog-post template renders an Open Graph card for an article: category, title, excerpt, and byline. Send JSON parameters through the remote MCP server, POST /v1/renders, or a signed /i/blog-post.png URL; the default size is 1200×630.

Sizes
1200×630
Formats
PNG · JPEG · WebP
Version
1.0.0

VectorFast Render is in early access. Billing is not connected yet, and API keys are issued to waitlist members as access opens. Join the waitlist

Preview

Rendered by VectorFast Render from this template's English and Chinese example parameters, through the same signed URLs your own pages would use.

Preview images are signed on the server and are not available in this environment.

Ask your agent

Paste the prompt into Claude, Cursor, or another agent connected to the VectorFast Render MCP server. The JSON is the render tool call it should turn into.
Prompt
Make the Open Graph image for Mia Chen's new Engineering post "Why we moved image generation into CI". It is a 6 minute read; use the first sentence of the intro as the excerpt.
MCP render call
{
  "name": "render",
  "arguments": {
    "template": "blog-post",
    "params": {
      "title": "Why we moved image generation into CI",
      "excerpt": "Deterministic templates, one brand kit, and no designer in the loop for release-day assets.",
      "author": "Mia Chen",
      "category": "Engineering",
      "readTime": "6 min read"
    }
  }
}

Connect Claude to VectorFast Render

Parameters

Read from the schema that POST /v1/renders validates. String values are trimmed; anything over a limit is rejected with invalid_params.
Blog post template parameters
ParamTypeRequiredLimitNotes
titlestringYes≤ 110 charsArticle title.
excerptstringNo≤ 180 charsOne or two sentences from the intro.
authorstringNo≤ 60 charsByline name.
categorystringNo≤ 24 charsSection label above the title.
readTimestringNo≤ 20 charsFree text such as "6 min read". camelCase for historical reasons.
coverImageimage URLNo—Image URL. Remote images are not enabled yet (the allowlist is empty), so leave it out; the template draws a fallback.

Render it from code

The REST call needs an API key in Authorization: Bearer. Its response includes a signed url you can store and reuse as an og:image. The Node.js function shows the signing algorithm the server verifies; per-key signing secrets are not issued yet in early access, and the secret must stay on your server.
curl · POST /v1/renders
curl https://vectorfast.ai/v1/renders \
  -H "Authorization: Bearer $VECTORFAST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "template": "blog-post@1",
  "format": "png",
  "width": 1200,
  "height": 630,
  "params": {
    "title": "Why we moved image generation into CI",
    "excerpt": "Deterministic templates, one brand kit, and no designer in the loop for release-day assets.",
    "author": "Mia Chen",
    "category": "Engineering",
    "readTime": "6 min read"
  }
}'
Node.js · signed URL (server-side only)
import { createHmac } from 'node:crypto'

// Server-side only. Never ship the signing secret to a browser, a mobile app or a repo.
const SIGNING_SECRET = process.env.VECTORFAST_SIGNING_SECRET

function encode(value) {
  return encodeURIComponent(value).replace(/[!'()*]/g, c => '%' + c.charCodeAt(0).toString(16).toUpperCase())
}

export function signRenderUrl({ template, format = 'png', params, brand, width, height, keyId }, secret = SIGNING_SECRET) {
  const query = {}
  for (const [key, value] of Object.entries(params)) {
    if (value === undefined || value === null)
      continue
    query[key] = typeof value === 'string' ? value : Array.isArray(value) ? JSON.stringify(value) : String(value)
  }
  if (brand) query.brand = brand
  if (keyId) query.k = keyId
  if (width) query.w = String(width)
  if (height) query.h = String(height)

  const canonical = Object.entries(query)
    .map(([key, value]) => [encode(key), encode(value)])
    .sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : 0))
    .map(([key, value]) => key + '=' + value)
    .join('&')
  const path = '/i/' + template + '.' + format
  const sig = createHmac('sha256', secret).update(path + '?' + canonical).digest('base64url')
  return 'https://vectorfast.ai' + path + '?' + (canonical ? canonical + '&' : '') + 'sig=' + sig
}

const url = signRenderUrl({
  template: 'blog-post',
  format: 'png',
  width: 1200,
  height: 630,
  params: {
    "title": "Why we moved image generation into CI",
    "excerpt": "Deterministic templates, one brand kit, and no designer in the loop for release-day assets.",
    "author": "Mia Chen",
    "category": "Engineering",
    "readTime": "6 min read"
  },
})

How signed URLs work

Blog post template FAQ

Which sizes does the blog-post template support?
1200×630. The default is 1200×630; pass width and height to pick another supported size.
Which parameters are required?
title. Every other parameter is optional and has a rendering default.
Does rendering the same parameters twice cost twice?
No. The same template version, parameters, brand kit version, format, and size produce the same cache key, so a repeat request is served from cache instead of rendering again. Billing is not connected yet in early access.