Store the Vector, Render the Raster: Why an SVG Master Beats Committing WebPs

Date:

Keep one crisp SVG as the source of truth and render a raster only when something needs one. You get sharp images everywhere, tiny files, and a re-skin that costs one edit – without the social-preview blind spot.

The short answer: An SVG is the best master for a graphic – resolution-independent, tiny, and editable as text – but it is a poor delivery format for one job: social and link-preview scrapers cannot read it, so an SVG set as an og:image shows nothing. The fix is a two-layer pattern: store the vector as the master, and render a raster (WebP or PNG) on export, only for the surfaces that need one. The SVG stays the single source of truth; the raster is a disposable derivative you regenerate, never hand-maintain. To render SVG to WebP you rasterize it once with a headless browser at export time – no design tool, no manual step.

Why an SVG hero disappears from social previews

SVG is perfect on the page: it scales to any size without blurring, weighs a few kilobytes, and – once you handle embedding and optimizing it correctly – you can restyle it by editing text. So it is tempting to use one SVG everywhere, including as the image a post hands to Facebook, X, LinkedIn, or a chat unfurl. That is the one place it breaks.

Link-preview crawlers fetch the URL in your og:image tag and expect a raster – a JPG, PNG, or WebP with real pixel dimensions. The Open Graph protocol is built around raster images with width and height; an SVG has no intrinsic pixel size a crawler trusts, and most simply refuse it. The result: a beautiful vector hero on the page, and a blank card when the link is shared.

An SVG is a wonderful master and a broken social image – the crawler wants pixels, and the vector has none.

The pattern: store the vector, render the raster on export

The mistake is treating “the image” as one file. Split it into two layers with different jobs:

  • The master is the SVG. It is the source of truth, the thing you version, edit, and re-skin – whether hand-authored or generated as code with an AI coding agent. It never ships to a crawler.
  • The derivative is a raster rendered from the master, produced at export time for the surfaces that need pixels: the og:image, an email, a thumbnail, anywhere SVG is unwelcome.

This mirrors how mature pipelines already treat photos: they keep the full-resolution original untouched and shape delivery bytes on the way out. The vector track works the same way – the SVG is the original, the WebP is the shaped delivery copy. Store one, generate the other on demand.

One graphic, two layers: a versioned vector master and rasters rendered on exportStore the vector once; generate pixels only for surfaces that need them
1. SVG master

Versioned source of truth. Edit + re-skin by tokens. Never shipped to a crawler.

2. Render on export

Headless browser at the target width; height from the viewBox. WebP default.

3. Raster derivatives

og:image, email, thumbnail. Cached, disposable, regenerated from the master.

The raster is build output, not source — keep it out of version control and regenerate it. Render to verify: a missing <defs> renders black while every other check passes.

Where does the render happen – build, request, or export?

“On export” can mean three moments, and the right one depends on how often the master changes:

  • At build/publish time. Render the raster when you publish the page or asset. Best default: the work happens once, the crawler is served a static file, and nothing renders on the hot path.
  • On request, cached. Render the first time a size is asked for, then cache it. Good when you cannot predict which dimensions you will need – the same logic behind generating image sizes on the fly instead of pre-building twenty thumbnails.
  • At delivery/export. A CMS or asset store renders the raster as it hands the asset to a consumer, keeping the vector master in the vault untouched.

All three share one rule: the raster is derived, cached, and disposable – the SVG is authoritative.

How to render SVG to WebP (and to what)

Rasterizing is a one-liner conceptually: load the SVG in a headless browser at a target width, screenshot it, and encode. WebP is the default delivery format – markedly smaller than PNG or JPG at the same quality, and universally supported now. Reach for PNG only when you need lossless flat art or wide compatibility, and JPG for photographic derivatives.

Two sizing rules matter. Render at the size the surface actually uses – 1200×630 is the Open Graph sweet spot, and platforms downscale from there, so larger buys nothing and costs bytes. And derive the height from the SVG’s own viewBox aspect ratio rather than assuming one, so a square icon and a 16:9 hero both come out uncropped.

The vector is authored once at any size; the raster is rendered at exactly the size a surface needs, and thrown away after.

One master, many looks – recolor and re-render

The quiet superpower of an SVG master is that its palette lives in a few color tokens at the top of the file. Change those codes and the whole graphic re-skins – no shape is touched – and a fresh render produces a new raster in that palette. One drawing becomes a cool variant, a warm one, or a per-category theme, each exported to its own WebP, all from a single source.

A committed raster cannot do this. To recolor a PNG you open an editor and redraw; to recolor an SVG master you edit one line and re-render. That is what makes the master-plus-render pattern scale to a whole library: dozens of on-brand images from a handful of source files, each rendered to whatever format and palette a surface asks for.

The discipline: never commit the derivative

The pattern only stays clean if you hold one line: the rendered raster is build output, not source. Keep it out of version control (a .gitignore entry) and regenerate it from the master. Committing the WebP invites the classic drift – someone edits the master, forgets to re-render, and the shipped image no longer matches its source. If a derivative must live somewhere durable, put it in an asset store or CDN keyed to the master, not beside it in the repo.

One check saves most of the pain: render to verify, never trust a parse. An SVG that references gradients or filters it forgot to define still parses as valid XML and passes a color check – but renders with a black background, because the missing definitions resolve to nothing. Only an actual render exposes it, so the raster step is the test: a flat or near-black export means a broken reference, not a dark design.

The short version

An SVG is the ideal master – crisp at any size, tiny, editable as text – but link-preview crawlers cannot read it, so it fails as an og:image. Keep the vector as the single source of truth and render a raster (WebP by default, PNG or JPG when needed) on export, only for surfaces that need pixels, at the size they use – 1200×630 for Open Graph. Never commit the derivative; regenerate it from the master, and render to verify, because a missing definition renders black while every other check passes. One source file, every format and palette on demand.

Frequently Asked Questions

Why doesn’t my SVG show up as a social share image?

Because link-preview crawlers expect a raster og:image – a JPG, PNG, or WebP with real pixel dimensions – and most refuse SVG, which has no intrinsic pixel size they trust. The page can display the SVG fine; the social card cannot. Render a raster copy of the SVG and point og:image at that.

How do I render an SVG to WebP?

Load the SVG in a headless browser (such as headless Chromium) at your target width, take a screenshot, and encode it as WebP. Derive the height from the SVG’s viewBox aspect ratio so it is not cropped. This runs at build or export time with no design tool and no manual step, and the SVG stays your master.

Should I commit the rendered raster to the repository?

No. Treat the raster as build output: keep it out of version control and regenerate it from the SVG master. Committing it invites drift, where the master is edited but the stale raster ships. If a derivative must persist, store it in an asset store or CDN keyed to the master, not beside it in git.

What size should the exported image be?

Render at the size the surface actually uses. For social and link previews, 1200×630 is the Open Graph sweet spot – platforms downscale from there, so a larger render only wastes bytes. For an in-page raster, match the layout’s display size (times your pixel ratio), not the master’s arbitrary authored size.

Why does my rendered SVG come out with a black background?

Almost always a missing <defs> block: the SVG references gradients or filters by id but never defines them, so those references resolve to nothing and the background renders black while solid-fill shapes still show. The markup parses as valid and the colors check out, so only an actual render reveals it. Include the definitions and always render to verify.

Share post:

Subscribe

Popular

More like this
Related

How to Merge Spreadsheets by URL (and Why Our Tool Reported 5 Misses That Weren’t)

Matching two spreadsheets on a URL column is the same job as matching a stock list to a price list by product code. It goes wrong in the same two places: how you clean the code, and how you count what didn't match.

Many-to-One: Why a Mapping Backlog Outgrows Its Target Taxonomy

You're mapping a messy source vocabulary onto a clean target taxonomy. The target has about 5,600 slots, so the job must be roughly 5,600 decisions — right? The backlog is already past 8,900, and still climbing.

The Fix That Didn’t Take: When a Content-Hash Gate Skips Your Code Change

You shipped a fix to how one field is computed, re-ran the pipeline across everything, and it reported a clean run. Then the consistency check still flags those records as wrong. The fix is in the code, the rebuild "ran" — and the records never changed. Your own optimisation skipped them.

Your Dedup Scan Is Over-Counting — Because It Forgot What You Already Fixed

The report said 80 duplicate groups still to resolve. You'd been resolving them for days. You run it again after a big batch and it *still* says 80-ish. The backlog isn't stubborn — the scan is counting work you already finished.