One API Call, Branded OG Images for Every Page
The OG Image Generator is a Varosity AI skill that turns a page title and a brand style into a hosted Open Graph image URL — one synchronous API call, no job polling, ready to drop straight into your <meta property="og:image"> tag. It lives in the Varosity public skill library, works over MCP or REST, and runs on your one vsk_ key. That's the whole thing.
I built this because I kept running into the same stupid friction. You launch a new page, write a solid piece, and then you need a share image. So you open Figma, duplicate a template, swap the text, export it, upload it somewhere, grab the URL, paste it into the meta tag. Fifteen minutes gone. Multiply that by twenty blog posts and a few dozen landing pages and it's not a workflow anymore — it's a tax on shipping.
What I actually wanted was to describe my brand once and have an agent handle the rest. Title goes in, image URL comes out. That's it.
The real problem with OG images and AI
Most diffusion models mangle text. You ask for a card that reads "How we cut render costs 40%" and you get a beautiful image with "Hew wee cut rendeer coastts 40&." Completely useless for an OG card where the headline is the whole point.
This is the thing most people miss when they try to DIY this with a generic image model. The model choice isn't aesthetic — it's functional. If the headline has to appear inside the image, you need a model with actual text rendering. On Varosity, that's gemini-3-pro-image. It handles multilingual text cleanly, it reasons about layout, it goes up to 4K. ideogram-v3 is a solid open-weight alternative if you want to mix it up.
If you're overlaying text in CSS or HTML on top of the image — like a background card where your frontend handles the typography — you can use flux-1.1-pro instead. Richer, cheaper. For throwaway drafts or quick checks, flux-1-schnell is the default and costs almost nothing.
One thing worth knowing now: imagen-4 and imagen-4-fast are being retired by Google on August 17, 2026. Don't start new flows on those. Use gemini-3-pro-image.
What you actually get
You tell the skill your brand — background color, accent color, tone, vibe — and your list of page titles. You say whether the headline text needs to render inside the image or not. The skill engineers a prompt per page, calls POST /api/v1/images, and returns a hosted imageUrl from Varosity's CDN plus the paste-ready meta tags.
Looks like this:
<meta property="og:image" content="https://cdn.varosity.ai/img/og-xyz.png" /> <meta property="og:image:width" content="1200" /> <meta property="og:image:height" content="675" /> <meta name="twitter:card" content="summary_large_image" />
You copy that block into your <head>. Done. Facebook, LinkedIn, X, Slack, iMessage — they all pick it up.
The aspect ratio is 16:9 (1200×675). The OG spec technically wants 1200×630, which is a ≈1.91:1 ratio. The difference is 45 pixels of height. Every major crawler center-crops, so 16:9 renders fine everywhere. If you need pixel-exact 1200×630 for some reason, crop or pad the returned image by 45px. That's the only gotcha there.
Here's exactly how it runs
Let me walk through a real example — the reference run I used when I was testing this.
Request: "OG image for my blog post 'How we cut render costs 40%'. Brand: deep navy background, electric-cyan accent, clean modern. Put the title in the image."
The skill confirms the brief: text-in-image, so model will be gemini-3-pro-image. Then it engineers the prompt:
> "Social share card, 16:9. Deep navy (#0B1020) background with a subtle electric-cyan (#22D3EE) gradient glow in the top-right. Bold white headline text reading \"How we cut render costs 40%\" left-aligned with generous margins, clean modern sans-serif. Minimal, high-contrast, professional developer-blog aesthetic. No clutter."
Then it calls:
POST https://varosity.ai/api/v1/images Authorization: Bearer vsk_... Content-Type: application/json
{ "prompt": "<engineered prompt>", "model": "gemini-3-pro-image", "aspect_ratio": "16:9" } ```
Response comes back synchronous — no job ID, no polling:
{ "imageUrl": "https://cdn.varosity.ai/img/og-rendercosts.png" }The skill hands you that URL and the full meta block. That's one round-trip.
For a batch — say, twenty blog posts — the skill loops Stages 1 and 2 for each page sequentially, then returns a table mapping every title to its imageUrl. Sequential matters here. There's a global rate limit of roughly 3 generations per window. If you fire them all in parallel you'll hit 429s. The skill handles backoff on 429 automatically, but you should know that's happening under the hood.
The prompt template the skill uses
This is the reusable structure it fills in from your brief:
Social share card, 16:9. {background_color} background with a subtle {accent_color}
{accent_treatment}. Bold {text_color} headline reading "{page_title}" left-aligned
with generous margins, {font_style}. {overall_vibe}. No clutter.Keep the scene simple. Busy backgrounds fall apart at thumbnail size — which is what OG images actually are most of the time. A strong color field with a subtle accent and clean type reads far better than something photorealistic and detailed.
On cost
One gemini-3-pro-image image runs about $0.13 in Varosity Credits. ideogram-v3 is roughly $0.05–0.08. Visual-only flux-1.1-pro is cheaper than that. Draft-quality flux-1-schnell is about $0.01. Failed generations don't get billed — ever.
For a 50-page site with full text-in-image on gemini-3-pro-image, you're looking at around $6.50. One-time. After that you only regenerate when a page title changes.
Speaking of which — there's no seed parameter, so re-running produces an equivalent image, not a bit-identical one. If you find a card you love, persist the imageUrl and reuse it. Don't regenerate unless you need to.
Logo on the card
If you want your actual logo anchored in the image — not just a color palette — pass its public URL as referenceImageUrl and set the model to nano-banana. That model is specifically good at preserving a supplied element while restyling the composition around it. Useful if brand consistency is tight.
Authentication and scope
All calls use a vsk_ API key from your Varosity dashboard (varosity.ai → API Keys). The key needs the generate:image scope. Over REST it goes in the Authorization: Bearer header. Over MCP, you set it once on the connection to https://varosity.ai/api/mcp and it propagates to every call. BYOK works too — if you've saved a provider key in your account, it routes through that at zero markup.
Installing and running the skill
The skill lives in the Varosity public skill library. To pull it:
curl -s https://varosity.ai/api/v1/skills/og-image-generator > ~/.varosity/skills/og-image-generator.md
It's set to auto_update: true, which means the Varosity MCP server can pull the latest version automatically. At the start of a session, call the refresh_skills MCP tool and you'll always be on the current version. This matters — model availability shifts, and the skill tracks those changes so you don't have to.
Once it's loaded, you trigger it the same way you'd prompt any agent:
"Make OG images for my site. Brand: <colors / vibe>. Pages: <list of titles>. Render the title text in the image? yes."
The agent confirms the brief, then runs. You get back URLs and meta tags. No Figma, no uploads, no manual anything.
If you're building a deploy pipeline — say, generating OG images as part of a CI step when new content goes live — the REST path is straightforward to wire in. POST /api/v1/images with prompt, model, and aspect_ratio. Response is synchronous. No webhooks, no polling loops to manage.
That's the skill. It does one thing and it does it in one call.