Restaurant Daily Special Video: One Render Every Morning
Render a 20-second vertical Story card for tonight's dish from twelve fields in your POS. One video a day, the same card every time, half a credit each, posted before service.

A restaurant daily special video is one render a morning, not a design job. Map twelve fields from the POS onto a 20-second vertical template, POST one request when the special is set, and the card is in Stories before service. Each render costs half a credit.
The finished video
This guide renders Daily Special Card - a 20-second 9:16 Story card in six scenes: a chalk board carrying the venue and the date, the dish full-bleed, the ingredients set like a menu line, the price once and big, the availability over a dim pass shot, and a close on the venue wordmark.
Twelve fields drive 60 overlays. The green, the type, the crops and the timing are identical in every render, which is the entire point.
What you need
- A Renderly API key. Create one in the dashboard under Settings → API keys.
- Somewhere the special already lives: a POS item, a "special of the day" row in a sheet, or the cron that updates the menu board.
- One photo of the plate at a URL that serves the file directly. A phone shot is fine.
Step 1 - Decide whether the card should change every day, or only the words
Search this query and the video results are all generators - Runway, Vivideo, Opus and Seedance each build something new from a dish photo, so each day's output is a fresh piece of creative.
A daily special is the strongest case there is for a template, because of who sees it: the same few hundred local followers, 365 times a year. After a fortnight they recognise the card in the quarter second before they read it, and that recognition is the only compounding asset daily posting builds. A generator that invents a fresh look every morning spends it.
So the question is not which tool makes the better single video. It is whether the 200th post should look like the first.
Step 2 - Map tonight's special onto twelve fields
Twelve fields cover the whole 20 seconds:
| Field | Scene | Comes from |
|---|---|---|
dish_name | 2, 3, 4 | The POS item name |
dish_description | 3 | The item's short description |
price | 4 | The item price, preformatted with its symbol |
availability | 4, 5 | How long it is on |
date_label | 1, 6 | Today, as "Thursday · 17 September" |
venue_name | 1, 4, 6 | Static per site |
venue_address | 1, 4, 6 | Static per site |
venue_date_line | 2 | Venue and date, as one string |
venue_address_line | 5 | Venue and address, as one string |
dish_photo_1 | 1, 2, 4, 6 | The plate |
dish_photo_2 | 3 | Optional, falls back to photo 1 |
dish_photo_3 | 5 | Optional, falls back to photo 1 |
Only five change with the dish; four are venue constants set once, and two of
the three photos are optional. dish_photo_1 alone appears in four scenes at
four sizes - full-bleed 9:16, a 1080x660 band, a 430x466 print and a 360x362
inset. The template picks the crop, so one upload carries the whole video.
Step 3 - Send the two composite lines, not just their parts
venue_date_line and venue_address_line look derived. They are not. Scenes 2
and 5 set the venue beside the date or the address as one typographic run, so
each is its own string and nothing composes it at render time. Change
venue_name alone and the render succeeds with two scenes still showing
Fiorella, the template's default restaurant. Build all four in the same mapping
function so they cannot drift:
const venue = { name: "Sorrel", address: "41 Wharf Road" };
const dateLabel = "Thursday · 17 September";
const fields = {
venue_name: venue.name,
venue_address: venue.address,
date_label: dateLabel,
venue_date_line: `${venue.name} · ${dateLabel.replace(" · ", " ")}`,
venue_address_line: `${venue.name} · ${venue.address}`,
};Step 4 - Keep the price, the dish name and the availability inside their boxes
Every text field sets fontSizeFixed, so nothing shrinks to fit. An overrun does
not fail the render - it publishes a card with a line missing. Make these limits
a validation rule, not a thing you notice in Stories:
| Field | Box | Holds | Breaks at |
|---|---|---|---|
price | 880px, 340px serif | 4 characters | "$24" and "19 EUR" both fit; "$24.50" does not |
dish_name | 880px, 124px serif | ~34 characters | "Slow-braised lamb shoulder with anchovy" - loses a line |
dish_description | 880x359, 86px serif | 3 lines, ~78 characters | a 4th line clips against the footer rule |
availability | 832px, 104px serif | ~40 characters | "Thursday lunch and dinner, while it lasts" is at the edge |
venue_name | 880x216, 180px serif | one line | a name long enough to wrap loses the second line |
Check price first, because a POS is the thing most likely to hand it to you
badly. Pass it preformatted with its symbol and strip trailing cents.
availability is worth writing rather than generating: it carries the whole of
scene 5 at 104px. "Til 9pm, or until it's gone." reads as scarcity, where
"Available Thursday" reads as a label.
Step 5 - Fire one render each morning from the POS
One special becomes one POST. The template's API id is
restaurant-daily-special, which is not the same string as its gallery URL.
curl -X POST https://renderly.video/api/v1/renders \
-H "Authorization: Bearer $RENDERLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"templateId": "restaurant-daily-special",
"replacements": {
"dish_name": "Salt-baked celeriac",
"dish_description": "Brown butter, hazelnut, sage - and far too much parmesan.",
"price": "$19",
"availability": "Til 9pm, or until it'\''s gone.",
"date_label": "Thursday · 17 September",
"venue_name": "Sorrel",
"venue_address": "41 Wharf Road",
"venue_date_line": "Sorrel · Thursday 17 September",
"venue_address_line": "Sorrel · 41 Wharf Road",
"dish_photo_1": "https://cdn.example.com/specials/2026-09-17-celeriac.jpg"
},
"webhookUrl": "https://your-app.com/hooks/renderly"
}'dish_photo_2 and dish_photo_3 are left out here, so both fall back to
dish_photo_1. Any other omitted field keeps the template default, and those
defaults belong to a restaurant called Fiorella - a missing venue_name does
not fail the render, it posts somebody else's name. Validate the row before the
request, not the file after it.
The call returns a job id immediately and the finished URL arrives on the
render.completed webhook, signed with HMAC-SHA256 - the
webhooks guide covers verifying
it.
What this costs at scale
Renderly bills 1 credit per minute of 1080p output, rounded up to the nearest half credit. At 20 seconds this card is 0.33 minutes, which rounds to half a credit, and a 1080x1920 vertical is the same pixel count as 1080p, so it bills at the base rate.
| Renders per month | Credits | Plan | Cost |
|---|---|---|---|
| 30 - one venue, every day | 15 | Creator, $29/mo | included |
| 100 | 50 | Creator, $29/mo | included |
| 360 - a 12-site group, every day | 180 | Creator, $29/mo | included |
| 1,000 | 500 | Business, $99/mo | included |
| 3,000 - 100 sites, every day | 1,500 | Business + 500 extra at $0.12 | $159/mo |
A single restaurant posting every day of the year spends 183 credits, which fits inside one month of the entry plan, and a hundred-site group still lands near five cents a video. The constraint here has never been the rendering; it is getting the kitchen to send one photo before noon.
Where to go next
The argument behind step 1 is set out at length in template-based video versus AI-generated video. If the specials rota lives in a spreadsheet, the trigger in the Google Sheets guide fires the render off a row edit, and the Instagram Reels guide covers the posting cadence once the MP4 exists.
Frequently asked
Does Renderly write the special from my menu?
What if the kitchen only sends one photo?
Why does my video still show the old venue name?
Can I use my own colours, fonts and logo?
Does it work for a bar, or only for plated food?
How does the video actually get onto Instagram?
Related guides
Google Sheets to Video: Automate Video Creation from a Sheet
Turn spreadsheet rows into finished videos. Connect a Google Sheet to the Renderly API with Apps Script, map columns to variables, and render every row.
Automate Instagram Reels: One Template, One Row per Post
Run a Reels account off a spreadsheet. Lock one format, keep a row per post, and render the week in a single pass for half a credit a video.