How-to

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.

Restaurant Daily Special Video: One Render Every Morning

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.

The card rendered from the payload in step 5.

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:

FieldSceneComes from
dish_name2, 3, 4The POS item name
dish_description3The item's short description
price4The item price, preformatted with its symbol
availability4, 5How long it is on
date_label1, 6Today, as "Thursday · 17 September"
venue_name1, 4, 6Static per site
venue_address1, 4, 6Static per site
venue_date_line2Venue and date, as one string
venue_address_line5Venue and address, as one string
dish_photo_11, 2, 4, 6The plate
dish_photo_23Optional, falls back to photo 1
dish_photo_35Optional, 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:

FieldBoxHoldsBreaks at
price880px, 340px serif4 characters"$24" and "19 EUR" both fit; "$24.50" does not
dish_name880px, 124px serif~34 characters"Slow-braised lamb shoulder with anchovy" - loses a line
dish_description880x359, 86px serif3 lines, ~78 charactersa 4th line clips against the footer rule
availability832px, 104px serif~40 characters"Thursday lunch and dinner, while it lasts" is at the edge
venue_name880x216, 180px serifone linea 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 monthCreditsPlanCost
30 - one venue, every day15Creator, $29/moincluded
10050Creator, $29/moincluded
360 - a 12-site group, every day180Creator, $29/moincluded
1,000500Business, $99/moincluded
3,000 - 100 sites, every day1,500Business + 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?
No, and that is the category line worth drawing. Runway, Vivideo, Opus and Seedance all take a dish photo or a menu line and generate a video around it, so each day's output is a new piece of creative. Renderly renders one fixed design from strings you supply. The words and the photo are yours, and the 200th card looks exactly like the first. If you want a machine to invent the video, this is the wrong tool.
What if the kitchen only sends one photo?
That is the normal case and the template is built for it. dish_photo_2 and dish_photo_3 are optional and fall back to dish_photo_1. The three slots crop differently - one full-bleed, one matted into paper at a slight rotation, one behind a scrim - so the same plate does not read as a repeat. The template chooses the crop, never the venue, which is why a phone photo taken on a dim pass still lands.
Why does my video still show the old venue name?
Because venue_date_line and venue_address_line are separate fields. Scenes 2 and 5 set the venue and the date as one typographic run, so they are stored as one string rather than composed at render time. Change venue_name and date_label without changing them and two scenes keep saying Fiorella. Build all four in the same mapping function.
Can I use my own colours, fonts and logo?
Not through replacements. The twelve fields carry text and photos; the board green, Instrument Serif and the venue wordmark are baked in. The logo is deliberately not a variable - it is the same mark on all 365 renders for one venue, so it is swapped once per brand rather than sent per request. For full control, send the whole composition as inputProps instead of templateId, or clone the template into a project and edit it once.
Does it work for a bar, or only for plated food?
There is a bar cut. Last Call takes the same twelve field names and runs oxblood and near-black in Bebas Neue, built for neon, candlelight and a phone at ISO 6400 - no text ever sits directly on a photo. Switching is one word in templateId, because dish_name holds a cocktail just as well as a pasta. Note the tighter ceilings: about 13 characters per line on dish_name, and three characters on price.
How does the video actually get onto Instagram?
Renderly returns an MP4 URL on the render.completed webhook and stops there. Posting is your scheduler's job - hand the URL to whatever already posts for the venue. The file is 1080x1920, which is the native size for Stories and Reels, so nothing re-encodes it on the way up.