// cornerstone

TailwindCSS OG image — real Chromium, no Satori subset

Linkshot supports TailwindCSS in two layers. Your live page renders in real headless Chromium — whatever TailwindCSS your site already uses works in your OG image because the OG image is a screenshot of your real site. For capture-only tweaks, Linkshot ships a curated linkshot:-prefixed utility set that is injected at screenshot time. No install, no plugin, no config edit.

Try Linkshot free7-day trial, no credit card required

Two layers of TailwindCSS support

Layer 1

Your live page (unrestricted)

Real headless Chromium renders your page during capture. Any TailwindCSS feature your site already uses works because Chrome supports it: any version, any plugin, any arbitrary value, any custom config, container queries, JavaScript-driven layouts. Linkshot has zero opinion about how your live page is built.

Layer 2

The linkshot: prefix (curated, capture-only)

A static, prebuilt CSS file Linkshot injects at capture time. Standard utilities at the standard preset scale, full color palette. Use it for tweaks that should happen only in the screenshot — hide the navbar, hide cookie banners, enlarge the hero heading. No install, no config.

Why Satori-based generators struggle with TailwindCSS

Satori — the library @vercel/og is built on — converts JSX to SVG and then to PNG using its own CSS engine. That engine implements a small subset of what real browsers do. The biggest gaps:

  • Flexbox only — display: grid is not supported, period.
  • TailwindCSS arbitrary values like w-[42rem] frequently fail; you have to use named utilities.
  • TailwindCSS plugins (@tailwindcss/typography, @tailwindcss/forms) are unsupported.
  • CSS variables work in many contexts but break in others, with no clear rules.
  • Backdrop filters, complex pseudo-elements, container queries — none of them.
  • Fonts must be fetched manually as ArrayBuffers and registered per weight.

The Satori subset restricts what your real page can use if you want it to render in your OG image. Linkshot side-steps this entirely by capturing the page in real Chromium — nothing on your live site is restricted.

What your real page can use — Satori vs Linkshot

This table compares what TailwindCSS / CSS features can appear on your live page and still render correctly in your OG image. Linkshot wins because it screenshots in real Chromium; Satori restricts because it implements its own CSS engine.

This is about your live page, not the linkshot: prefix.

The rows below describe what features your existing site can use and still render correctly when Linkshot screenshots it. The linkshot: capture-only prefix is a separate, curated utility set covered in the section below — arbitrary values, Tailwind plugins, and custom variants are not available there.

Feature on your live pageSatori (@vercel/og)Linkshot
CSS Grid (display: grid)
Container queries
Backdrop filters (backdrop-blur, etc.)limited
Pseudo-elements (::before, ::after)limited
CSS variables / custom propertieslimited
Your site's Tailwind arbitrary values (w-[42rem], etc.)partial
Your site's Tailwind plugins (typography, forms, etc.)
Your site's custom Tailwind variants
Your site's dark-mode classesmanual
Any TailwindCSS version your site uses (v3, v4, etc.)partial
Custom fonts via @font-facemanual
Variable fonts (axes)limited
Emoji + non-Latin scriptsmanual
JavaScript-driven layouts

The linkshot: prefix — capture-only utilities

The linkshot: prefix is a curated TailwindCSS utility set baked into a static CSS file Linkshot injects at screenshot time. You write the classes on your real markup; the injected CSS provides the rules during capture. Outside capture the classes are inert.

{/* Hide the navbar in the screenshot only */}
<nav className="linkshot:hidden">…</nav>

{/* Hide cookie banner and chat widget at capture only */}
<div className="cookie-banner linkshot:hidden">…</div>
<div className="intercom-launcher linkshot:hidden">…</div>

{/* Enlarge and center the hero only at capture */}
<h1 className="text-3xl font-bold linkshot:text-6xl linkshot:text-center">
  {post.title}
</h1>

{/* Swap a background only in the screenshot */}
<section className="bg-white linkshot:bg-gradient-to-br linkshot:from-violet-500 linkshot:to-fuchsia-500">
  …
</section>

What's in the linkshot: utility set

The prefix covers the standard TailwindCSS preset utilities at the preset scale, plus the full color palette. No additional install or config required.

Layout

linkshot:hidden, linkshot:block, linkshot:flex, linkshot:grid, linkshot:flex-row, linkshot:flex-col, linkshot:grid-cols-{1–12}, linkshot:col-span-{1–12}, linkshot:items-{start,center,end}, linkshot:justify-{start,center,between,around}

Spacing

linkshot:p-{0–96}, linkshot:m-{0–96}, linkshot:gap-{0–96}, linkshot:space-{x,y}-{0–96} — preset scale only (no arbitrary values)

Sizing

linkshot:w-{0–96, full, screen, fit, 1/2, 1/3, …}, linkshot:h-{…}, linkshot:min-w-{…}, linkshot:max-w-{…}

Typography

linkshot:text-{xs–9xl}, linkshot:font-{thin–black}, linkshot:font-{sans,serif,mono}, linkshot:text-{left,center,right}, linkshot:tracking-{tight–widest}, linkshot:leading-{none–loose,3–10}

Color (full palette × 50–950)

linkshot:text-{slate,gray,red,orange,…,rose}-{50–950}, linkshot:bg-{…}, linkshot:border-{…}, linkshot:ring-{…}, linkshot:divide-{…}

Borders & shape

linkshot:border, linkshot:border-{2,4,8}, linkshot:rounded-{none,sm,md,lg,xl,2xl,3xl,full}, linkshot:shadow-{sm,md,lg,xl,2xl}

Visual effects

linkshot:opacity-{0–100}, linkshot:blur-{sm–3xl}, linkshot:brightness-{0–200}, linkshot:contrast-{…}, linkshot:grayscale, linkshot:backdrop-blur-{…}, linkshot:bg-gradient-to-{direction}, linkshot:from-{color}, linkshot:via-{color}, linkshot:to-{color}

Position & overflow

linkshot:{static,fixed,absolute,relative,sticky}, linkshot:z-{0,10,20,30,40,50,auto}, linkshot:inset-{…}, linkshot:overflow-{auto,hidden,visible,scroll}

What the linkshot: prefix does NOT support

The prefix is intentionally a curated static set, not a build-time extension of your TailwindCSS config. The trade-off is simplicity (no install, no config) vs flexibility.

  • Arbitrary values like linkshot:w-[42rem] or linkshot:text-[#abc]
  • TailwindCSS plugins (typography, forms, aspect-ratio, etc.)
  • Container queries
  • State or responsive variants composed with linkshot: (e.g. linkshot:hover:hidden, linkshot:md:text-6xl)
  • Custom Tailwind variants
  • CSS variables / arbitrary CSS as a utility

Workaround for unsupported cases

If you need an arbitrary value, a Tailwind plugin output, or a custom variant at capture time, apply that styling on the live page itself. Linkshot captures whatever your real page renders — the linkshot: prefix is only needed when the styling should differ between the live page and the screenshot.

Setup

There is nothing to install. There is no tailwind.config edit. The full setup is:

  1. 01Register your domain in Linkshot

    Add the domain you want OG images generated from in the dashboard. Takes 30 seconds.

  2. 02Drop one meta tag

    Put the Linkshot URL in your og:image meta tag with the page URL as a parameter.

  3. 03(Optional) Sprinkle linkshot: classes

    Add capture-only utilities to elements you want hidden or restyled at capture. The classes have no effect on your live site because nothing in your build matches them — Linkshot's injected CSS provides the rules at screenshot time only.

Compare to other approaches

Frequently asked questions

How does Linkshot support TailwindCSS?

Two ways. (1) Your live page renders in real headless Chromium, so whatever TailwindCSS your site already uses — any version, any plugin, any arbitrary value, any custom config — appears in the OG image because the OG image is a screenshot of your real page. (2) For capture-only tweaks, Linkshot ships a curated `linkshot:`-prefixed utility set (a static CSS file injected at screenshot time). You write `linkshot:hidden` on your real elements; Linkshot's CSS makes those classes do something during capture only.

Do I need to install a TailwindCSS plugin?

No. There is no npm package, no `tailwind.config` edit, no plugin. You just write `linkshot:hidden` (or any other curated utility) on your real markup. Your build does not need to know about it — Linkshot injects the matching CSS rule at capture time. Outside capture the class names are inert.

What utilities does the `linkshot:` prefix include?

The standard TailwindCSS preset utilities at the standard preset scale: display/flex/grid basics, spacing 0–96, sizing fractions, position, z-index, text size xs–9xl, alignment, weight, family, line height, letter spacing, the full color palette (50–950 shades) for text/bg/border/ring/divide/decoration/fill/stroke, borders (width 0/2/4/8), radius, opacity, shadow, overflow, visibility, object-fit, aspect-{auto,square,video}, filters, backdrop filters, ring, divide, space-between, outline, list, table, columns, gradients, mix blend, isolation, appearance.

What does `linkshot:` NOT support?

Arbitrary values like `linkshot:w-[42rem]` or `linkshot:text-[#abc]` are not supported — the prefix utility set is static. TailwindCSS plugins (typography, forms, aspect-ratio), container queries, custom variants, CSS variables as utilities, and state/responsive variants composed with `linkshot:` (like `linkshot:hover:hidden` or `linkshot:md:text-6xl`) are also not supported. If you need any of those at capture time, the workaround is to apply the styling on the live page itself — Linkshot will capture whatever you render.

Why use `linkshot:` instead of just styling my live page?

Most of the time you should style the live page directly. The `linkshot:` prefix is for tweaks that should happen ONLY at capture and not on the live site — hiding the navbar, hiding cookie banners and chat widgets, enlarging a hero heading for the screenshot, swapping a background color so the unfurled card pops. These changes would be wrong on the live page but right in the OG image.

How do I hide a cookie banner / chat widget at capture only?

Add `class="linkshot:hidden"` to the element you want hidden. Outside capture, that class matches no CSS rule and the element is visible as normal. During Linkshot capture, the injected CSS makes `linkshot:hidden` map to `display: none !important` and the element vanishes only in the screenshot.

Will my live page work with `linkshot:` classes?

Yes. The class strings sit harmlessly in your HTML. TailwindCSS does not generate matching CSS for them in your build (because your config does not know about the `linkshot:` prefix), so they have no visual effect on the live site. Linkshot provides the rules at capture time only.

Does this work with TailwindCSS v3 or v4?

It works with both because the `linkshot:` rules are a separate static CSS file Linkshot injects — independent of your project's TailwindCSS version or build pipeline. Your project can be on Tailwind v3, v4, no Tailwind, plain CSS, anything. The `linkshot:`-prefixed class strings just need to be in the HTML; the injected CSS does the rest.

Real Chromium for your page, curated linkshot: for capture

No install. No plugin. No tailwind.config edit. Drop one meta tag, optionally add linkshot: classes for capture-only tweaks.

7-day free trial · no credit card required