# Animated OG images: GIF and MP4 from an HTML template

> Render an animated GIF or MP4 from an HTML and CSS template with one API call — and where animation actually plays: og:image, posts, chat and email.

Published 2026-10-25 · https://shareglint.com/en/guides/animated-og-images-gif-mp4

A moving card stops the scroll better than a still one: a countdown that ticks, a number that counts up, a headline that types itself. With an HTML-template image API you do not need a video editor for that — the same template that renders your 1200×630 PNG can render a short **animated GIF or MP4**, from the same fields, in one request.

This guide covers where animated images actually play (fewer places than you would hope, and og:image is mostly not one of them), how to render one with Shareglint, how to write a template that works as a still and as a clip, and what it costs.

## Where animation plays, and where it does not

Start with the uncomfortable part. The `og:image` tag is defined by the [Open Graph protocol](https://ogp.me/) as "an image URL which should represent your object" — a picture, and crawlers treat it like one. X's card documentation states that for GIFs [only the first frame is used](https://web.archive.org/web/2025/https://developer.x.com/en/docs/twitter-for-websites/cards/overview/summary-card-with-large-image). Other networks do not promise animation in link previews either. So an animated GIF in `og:image` usually shows as its first frame — which, for most animations, is the emptiest moment of the clip.

Where animation does work is when **the file itself is the content**:

- **Social posts.** Upload the MP4 (or GIF) to X, LinkedIn, Instagram or Facebook as the post's media. That is a video post, not a link preview, and it plays in the feed.
- **Chat.** Slack and Discord play GIFs posted or uploaded into a channel. Discord's [link preview documentation](https://docs.discord.com/developers/link-previews/overview) also describes video embeds: point `og:video` at an `.mp4`, and `og:image` "becomes the preview frame".
- **Email.** GIF is the only animation that works broadly in email. [Can I email](https://www.caniemail.com/features/image-gif/) lists the exceptions: Outlook for Windows does not animate GIFs (with Microsoft 365 accounts it plays three times and stops). The HTML [`<video>` element](https://www.caniemail.com/features/html-video/) is far worse — Gmail strips it entirely.
- **Your own pages.** An MP4 in `<video autoplay muted loop playsinline>` is the lightest way to show the clip on a landing page or in a blog post.

So the practical pattern is: **a still PNG or JPEG in `og:image`, the GIF or MP4 for posts, chat and email** — all three from one template.

## Render a GIF or MP4 with one request

Pick a template and set `format` to `gif` or `mp4`. Two optional parameters shape the clip: `duration` in seconds (0.5 to 5, default 3) and `fps` (10 to 30; default 15 for GIF, 30 for MP4).

```bash
curl -X POST "https://shareglint.com/v1/images?wait=true" \
  -H "Authorization: Bearer sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "template": "animated-stat-counter",
    "format": "mp4",
    "duration": 3,
    "modifications": {
      "value": "1,240,000",
      "label": "images rendered last month",
      "site": "northwind.dev"
    }
  }'
```

The response is an ordinary render with one extra field:

```json
{
  "id": "img_01m08…",
  "status": "completed",
  "format": "mp4",
  "animation": { "duration": 3, "fps": 30, "frames": 90 },
  "url": "…/img_01m08….mp4"
}
```

The long edge is capped at 1080 px with even dimensions, so the 1200×630 `og` size comes out as a 1080×566 file and a 1080×1920 story as 608×1080 — plenty for a feed, and it keeps files small. `quality` and `scale` do not apply. `size` and `sizes` work as for stills, so one request can give you the landscape clip and the vertical story version together.

The GIF loops forever, with a palette computed for the clip; the MP4 is H.264 with `faststart` and no audio track, which every platform and browser plays. A 3-second GIF at 15 fps is roughly 0.1 to 3 MB, depending on how much of the frame moves; the same clip as MP4 is a fraction of that.

Without a server, use a **signed URL**: the extension picks the format, and `duration` and `fps` are signed like every other parameter, so nobody can change them on your quota.

```html
<img src="https://shareglint.com/i/acc_…/animated-countdown.gif?number=12&unit=days%20to%20go&duration=4&s=…" alt="12 days to go">
```

An animated render takes a few seconds rather than one, so `?wait=true` and the first request to a signed URL wait longer than for a still; later requests redirect to the cached file at once.

## Built-in animated templates

The template library has ready-made animated designs — countdown, stat counter, typing headline, product reveal, quote fade-in, sale pulse and more — with slugs starting with `animated-`. Like every built-in template they lay themselves out in all 6 sizes (og 1200×630, square 1080×1080, portrait 1080×1350, story 1080×1920, pinterest 1000×1500, youtube 1280×720) and take `accent` and `theme`. Rendered as PNG they show the finished frame, so the same slug serves your `og:image` and your post.

## Animating your own template

Animation is recorded, not filmed: the renderer pauses every CSS animation and transition and steps it to the exact time of each frame. The same fields therefore always give the same file — nothing depends on how busy the browser was — and anything CSS can animate works: `transform`, `opacity`, colours, `clip-path`, filters, keyframes with delays.

Two hooks make one template work as a still and as a clip. During a GIF or MP4 render the `<html>` element gets the class **`motion`** and the CSS variable **`--clip`** with the clip length (`3s` by default). A still render of the same template has no `motion` class. Put the animation under `.motion` and time it with `var(--clip)`:

```css
.title { opacity: 1; }                      /* the still: the finished design */
.motion .title { animation: rise var(--clip) ease-out both; }
@keyframes rise { from { opacity: 0; transform: translateY(40px); } }

.motion .badge { animation: pop calc(var(--clip) * 0.3) calc(var(--clip) * 0.5) both; }
@keyframes pop { from { transform: scale(0); } }
```

Timing everything as a fraction of `--clip` means a 2-second and a 5-second render both play the whole animation. Make the last frame the finished design, because a GIF loops back to the start and email clients that do not animate show only the first frame — so it is worth making the first frame readable too: fade the decoration in, not the headline.

Your templates cannot run scripts (they are removed when you save), so animate with CSS. Counting numbers and typed text in the built-in templates use a hook of our own that is not available to custom HTML.

Check the still without spending quota in the template preview in the dashboard, which renders the PNG version. For the motion, one GIF at a low `fps` is enough to judge the timing before you render the final MP4.

## What it costs

An animated render uses **5 renders** of your monthly quota instead of one, per size — capturing and encoding dozens of frames is that much more work. Everything else works as for stills: the same template with the same fields and the same `duration` and `fps` again returns the existing file for free, and a render that fails gives all 5 back. The Free plan (100 renders a month) includes animated formats, with the same watermark as stills. Bulk batches render still formats only; for a series of clips, call the API once per clip.

## Checklist

1. Keep a still PNG or JPEG in `og:image`; use the GIF or MP4 where the file itself is shown.
2. MP4 for social posts, Discord and web pages; GIF for email and image-only places.
3. Scope animations under `.motion`, time them with `var(--clip)`, end on the finished design.
4. Stay short: 2–4 seconds loops well and keeps GIFs small.
5. Use `size: "story"` or `sizes` for the vertical version from the same request.

## FAQ

### Does an animated GIF in og:image play in link previews?

Mostly not. X documents that only the first frame of a GIF is used in its cards, and most other crawlers treat og:image as a still picture. Put a still PNG or JPEG in og:image and use the GIF or MP4 where the file itself is posted: in a tweet, a Slack or Discord message, a newsletter.

### GIF or MP4 — which should I render?

MP4 is many times smaller and has full colour, so use it wherever video is accepted: social posts, ads, Discord, your own pages. Use GIF where only images are accepted, above all in email, where the video element is barely supported.

### How much does an animated render cost?

On Shareglint an animated render uses 5 renders of your monthly quota, per size. Requesting the same template with the same fields again returns the existing file at no cost, and a failed render gives all 5 back.

### Can my own HTML template be animated?

Yes. Write normal CSS animations and transitions, scoped under the motion class that is set on the html element only during GIF and MP4 renders, and use var(--clip) as the duration. The same template rendered as PNG then shows the finished design as a still.
