Faceless YouTube Shorts Automation: Render a Month of Uploads
Run a faceless Shorts channel from a spreadsheet. Lock one format, write a batch of facts, add an AI voiceover, and render a month of uploads in one pass.

A faceless Shorts channel is a format plus a content queue. Lock the format in a template, keep the queue in a spreadsheet, and one request per row renders the whole month - narration included, because an AI voiceover is one more field. A daily channel costs 15 to 30 credits a month.
The finished video
This guide renders Science Fact of the Day - a 24-second 9:16 short built to loop: a full-bleed hook question, the fact, a white break card holding the big number, a payoff, and a channel sign-off that dissolves back toward the opening frame. A cyan progress rail fills across the top so the viewer always sees how much is left.
Eighteen fields change per row. Watch the output on the template page before you write anything.
What you need
- A Renderly API key. Create one in the dashboard under Settings → API keys.
- A spreadsheet with one row per upload.
- Two landscape photographs per short, at URLs that serve the file directly.
image_1is reused at three focal crops, so two cover the whole 24 seconds.
Step 1 - Lock the format before the content
A faceless channel is not thirty videos. It is one video played thirty times with different words in it.
So pick a template and stop editing it. Every upload then shares the same colour, type, pacing and progress rail, and the fourth short a viewer sees is recognisable as yours. That recognition is the asset, and a per-video editing session destroys it without anyone noticing. From here you are not designing - you are writing rows.
Step 2 - Write a batch of facts, one row per short
One column per template variable, one row per upload:
| hook_question | fact_headline | stat_value | stat_unit | fact_number | image_1 |
|---|---|---|---|---|---|
| Which came first: sharks or trees? | Sharks are older than trees. | 450M | years of sharks. | 047 | https://cdn.example.com/shark.jpg |
| How deep does sound travel? | Whale song crosses oceans. | 1,600 | kilometres, in the deep channel. | 048 | https://cdn.example.com/whale.jpg |
channel_name and source_label stay the same on every row - write them once
and fill down. fact_number increments, which is what makes the run feel like a
series rather than a pile.
Line breaks matter here. hook_question, fact_headline and payoff_line sit
in fixed boxes at display sizes, so put a real newline where you want the line to
wrap rather than letting a long value find its own break.
Step 3 - Split each narration line into a lead and an accent
The narration burned onto each footage frame is not one variable. It is two:
{
"caption_1_lead": "You have this",
"caption_1_accent": " backwards.",
"caption_2_lead": "Wood is the",
"caption_2_accent": "newer invention."
}The lead half sets in white and the accent half in cyan, so the pair puts the emphasis exactly where the sentence lands rather than colouring a whole line. There are four pairs - scenes 1, 2, 4 and 5.
Write the accent as the shortest phrase that carries the surprise, usually the
last two or three words. Mind the leading space: " backwards." keeps the gap
after the white half, and dropping it joins the two words together on screen.
Step 4 - Add an AI voiceover with one field
The template ships a fixed music bed - its sound overlay is not marked dynamic -
so enable narration once in your own copy. Duplicate the template into a project,
select the sound overlay, set Name to narration, and tick Dynamic in the
overlay panel. Render that project by projectId from then on.
The narration is then one replacement value:
{
"narration": {
"tts": { "text": "Sharks are older than trees. The first shark appeared 450 million years ago.", "voice": "jordan", "speed": 1 }
}
}Twelve curated voices are available: claudette, emily, geffenv1, henry
(the default), hugh_32, jacob, jordan, julie, monica, nick, phil
and ruby - plus any voice id from Speechify's full catalogue of 992 voices
across 36 locales. Pick one and keep it - the voice is part of the channel,
like the colours.
Two limits worth knowing before a batch of thirty.
The narration sets the length. Renderly stretches the sound overlay to the real
audio duration, and if that runs past the end of the composition it extends the
video to fit - before the credit math. A script that overruns quietly produces a
longer, dearer short and breaks the fixed 24-second format. Keep it to about 60
words, or raise speed.
Second, a render accepts at most three tts values. Past that it returns a 400
telling you to pre-generate instead, with POST /api/v1/ai/voiceover - that
takes { "text", "voice", "speed" } and returns an MP3 URL and its duration,
which you then pass as the plain replacement value.
Templates with caption overlays can go further:
{"transcribe": {"source": "narration"}} word-times captions against the
narration - and since the timings ride along with the tts audio, this pass is
free.
Step 5 - Render the batch with one request per row
One row becomes one POST:
curl -X POST https://renderly.video/api/v1/renders \
-H "Authorization: Bearer $RENDERLY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"templateId": "science-fact-of-the-day",
"replacements": {
"hook_question": "Which came first:\nsharks or trees?",
"fact_headline": "Sharks are older\nthan trees.",
"stat_value": "450M",
"stat_unit": "years of sharks. The first tree\ngrew 60 million years later.",
"payoff_line": "Every forest is\nyounger than a\nshark.",
"caption_1_lead": "You have this",
"caption_1_accent": " backwards.",
"source_label": "Fossil record · Devonian",
"fact_number": "047",
"channel_name": "Strange But True",
"image_1": "https://cdn.example.com/shark.jpg",
"image_2": "https://cdn.example.com/forest.jpg"
},
"webhookUrl": "https://your-app.com/hooks/renderly"
}'If you enabled narration in Step 4, swap templateId for your projectId and
add the narration key alongside the rest. Everything else is unchanged.
Any field you leave out keeps the template's default, so a row with a missing photograph still renders. That is convenient and it hides mistakes, so check the batch before the run rather than in the finished videos.
Loop the spreadsheet and send thirty of these. The request returns a job ID immediately, because rendering is asynchronous. The Google Sheets guide has the loop as an Apps Script, and the CSV guide has it as a resumable script for a file on disk.
Step 6 - Collect the finished shorts and queue the uploads
Because webhookUrl was included, Renderly posts back per job:
{
"event": "render.completed",
"data": {
"jobId": "cm9x2k4p10001qw8r7a3b2c1d",
"status": "COMPLETED",
"outputUrl": "https://cdn.renderly.video/renders/cm9x2k4p10001qw8r7a3b2c1d.mp4",
"creditsUsed": 0.5,
"durationInFrames": 720,
"fps": 30
},
"timestamp": "2026-08-14T09:12:44.110Z"
}Write outputUrl back to the row. Uploading is a separate job - the YouTube
Data API, or a scheduler that takes a file and a publish time - and separating
the two is the point: render the month in one pass, release one a day.
Payloads are signed with HMAC-SHA256. Verify the signature before you trust the body - the webhooks guide covers the check.
What this costs at scale
Renderly bills 1 credit per minute of 1080p output, rounded up to the nearest half credit. This short runs 24 seconds, so each upload costs half a credit.
A voiceover is charged on top at half a credit per 1,000 characters, and a 24-second script is around 400 - so narration doubles a short to one credit.
| Shorts per month | Silent | Narrated | Plan |
|---|---|---|---|
| 30 - one channel, daily | 15 credits | 30 credits | Creator, $29/mo |
| 300 - ten channels, daily | 150 credits | 300 credits | Creator silent, Business narrated |
| 1,000 | 500 credits | 1,000 credits | Business, $99/mo |
A daily narrated channel uses 15% of the Creator plan, which is the number worth sitting with: the cost of running a faceless channel is not the rendering. It is finding thirty facts worth watching.
Where to go next
The queue is the hard part, and it lives in a spreadsheet. Wire it up with the Google Sheets guide for a list you keep editing, or the CSV guide for a batch you export once.
For why a fixed template beats generating each video from scratch, read template-based vs AI-generated video.
Frequently asked
Does this generate the facts as well as the videos?
Do I need a voiceover at all?
How much does the AI voiceover cost?
Will 30 videos that look identical get flagged as spam?
Does Renderly upload to YouTube for me?
Can I run more than one channel from the same setup?
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.
Bulk Video from CSV: Generate One Video per Row
Turn a CSV export into finished videos. Map headers to template variables, send one render request per row from a resumable script, and collect every result.