# Blog post template

> An Open Graph card for an article: category, title, excerpt, and byline. Render it on-brand from an AI agent or the REST API.

Canonical URL: https://vectorfast.ai/render/templates/blog-post
Markdown URL: https://vectorfast.ai/render/templates/blog-post.md
Last modified: 2026-10-30

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

## Summary
- Template id: `blog-post` (pin the major version as `blog-post@1`; current version 1.0.0)
- Sizes: 1200×630 (default 1200×630)
- Formats: PNG, JPEG, WebP
- Use it for: og:image for every blog post; Docs and changelog article previews; Newsletter issue covers

## Previews
- English: ![Blog post template rendered in English at 1200×630 with the built-in VectorFast brand kit.](https://vectorfast.ai/i/blog-post.png?author=Mia%20Chen&brand=default&category=Engineering&excerpt=Deterministic%20templates%2C%20one%20brand%20kit%2C%20and%20no%20designer%20in%20the%20loop%20for%20release-day%20assets.&h=630&readTime=6%20min%20read&title=Why%20we%20moved%20image%20generation%20into%20CI&w=1200&sig=z-gdgiWK5-SGlWEB5hQeu3gwpufAwMUTAhn5OZyNCEY)
- Chinese: ![Blog post template rendered in Chinese at 1200×630 with the built-in VectorFast brand kit.](https://vectorfast.ai/i/blog-post.png?author=%E9%99%88%E7%B1%B3%E5%A8%85&brand=default&category=%E5%B7%A5%E7%A8%8B&excerpt=%E7%A1%AE%E5%AE%9A%E6%80%A7%E7%9A%84%E6%A8%A1%E6%9D%BF%E3%80%81%E4%B8%80%E4%B8%AA%E5%93%81%E7%89%8C%E5%8C%85%EF%BC%8C%E5%8F%91%E7%89%88%E5%BD%93%E5%A4%A9%E7%9A%84%E7%B4%A0%E6%9D%90%E4%B8%8D%E5%86%8D%E9%9C%80%E8%A6%81%E8%AE%BE%E8%AE%A1%E5%B8%88%E6%8E%92%E9%98%9F%E3%80%82&h=630&readTime=%E9%98%85%E8%AF%BB%206%20%E5%88%86%E9%92%9F&title=%E4%B8%BA%E4%BB%80%E4%B9%88%E6%88%91%E4%BB%AC%E6%8A%8A%E5%9B%BE%E7%89%87%E7%94%9F%E6%88%90%E6%90%AC%E8%BF%9B%E4%BA%86%20CI&w=1200&sig=1_ZXEtOnmAwvp5wNS80BFO_eLaOAoF4PgpaVJojj248)

## Parameters
All string params are trimmed. Limits come from the schema `POST /v1/renders` validates.

| Param | Type | Required | Limit | Notes |
| --- | --- | --- | --- | --- |
| `title` | string | yes | ≤ 110 chars | Article title. |
| `excerpt` | string | no | ≤ 180 chars | One or two sentences from the intro. |
| `author` | string | no | ≤ 60 chars | Byline name. |
| `category` | string | no | ≤ 24 chars | Section label above the title. |
| `readTime` | string | no | ≤ 20 chars | Free text such as "6 min read". camelCase for historical reasons. |
| `coverImage` | image URL | no | — | Image URL. Remote images are not enabled yet (the allowlist is empty), so leave it out; the template draws a fallback. |

## Ask an agent
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.

The MCP `render` tool call it should become:

```json
{
  "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"
    }
  }
}
```

## REST
```bash
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"
  }
}'
```

## Signed URL (server-side Node.js)
Per-key signing secrets are not issued yet in early access; until then, reuse the signed `url` that `POST /v1/renders` returns. The algorithm below is what the server verifies. Keep the secret on your server.

```js
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"
  },
})
```

## 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.

## Related
- All templates: https://vectorfast.ai/render/templates
- Template reference: https://vectorfast.ai/render/docs/templates
- Connect Claude: https://vectorfast.ai/render/agents/claude
