Zvid
Editor
Pricing

Developer Tutorials

Generate Short-Form Videos from JSON for Reels, Shorts and TikTok

Run a complete Node.js example to turn three JSON messages into a 12-second vertical MP4, check render credits, recover interrupted jobs and review each social upload.

Mina RamzyBy Mina RamzyPublished Updated

Turn three short messages in JSON into a vertical MP4. This tutorial uses Node.js and the Zvid API to make a 12-second video you can review for Instagram Reels, YouTube Shorts or TikTok. The supplied code builds the scenes, checks the request, submits one render and downloads the finished file.

The example uses large text and simple graphics, with no footage or audio to prepare. Your JSON controls the message and timing; the code keeps the design consistent.

The video you will make

Three four-second scenes: start with one idea, show one useful step, and save for later. The clip is silent.

The output is 1080 × 1920 pixels, 9:16, at 30 frames per second. It is a finished video file, not an automatically published post. Review it inside each destination app before uploading, because interface overlays and cropping can differ.

1. Get the example and your API key

You need Node.js 22.9 or newer with npm, a Zvid account, an API key and enough render credits. Create the key at app.zvid.io/api-keys, then run the example on your computer or server where the key can stay private. See API-key authentication for optional background.

Budget 12 render credits for the supplied video. Validation does not consume render credits. The script checks the current estimate and stops if it exceeds the configured limit of 12; a longer version can require a higher limit.

Extract the ZIP, then open a terminal in its short-form-json folder, where package.json is located. Run:

node --version
npm ci

If PowerShell blocks npm.ps1, use npm.cmd instead of npm in these commands. You do not need to change your execution policy.

Copy .env.example to a new file named .env in that folder. In PowerShell, use Copy-Item .env.example .env. On macOS or Linux, use cp .env.example .env. Open .env and paste your key after ZVID_API_KEY=:

ZVID_API_KEY=
MAX_RENDER_CREDITS=12

The npm commands load this file automatically. Do not put your key in the JSON or commit .env to a repository.

2. Start with the supplied content

Open data/content.json. It holds the text and timing for all three scenes:

{
  "series": "FIELD NOTES",
  "secondsPerScene": 4,
  "beats": [
    {
      "title": "Start with one idea",
Show full example · 18 linesCollapse example
{
  "series": "FIELD NOTES",
  "secondsPerScene": 4,
  "beats": [
    {
      "title": "Start with one idea",
      "detail": "Give this video one clear job."
    },
    {
      "title": "Show one useful step",
      "detail": "Make the next action easy to follow."
    },
    {
      "title": "Save for later",
      "detail": "Try it in your next video."
    }
  ]
}

A beat here is one short message shown in one scene. This is the example application's input format, not the JSON shape sent directly to Zvid. src/project.js converts it into a video project; src/index.js wraps that project in { "payload": ... } for the API.

Keep the supplied values for your first run. No template ID, media URL, soundtrack or separate project file is required.

3. Validate before rendering

Run the default command:

npm start

It writes the generated project to out/project.json, sends a validation request and saves the response in out/validation.json. For the supplied example, expect:

Valid: true. Estimated credits: 12.
No render submitted. Run npm run render when ready.

Read the estimate before proceeding. The script stops if the content fails its input checks, Zvid rejects the request, validation returns warnings, or the estimate exceeds MAX_RENDER_CREDITS. A valid response confirms the request passes validation; it does not prove the final text is readable.

4. Render and download the MP4

When the estimate is acceptable, run:

npm run render

This command spends render credits. It validates again, submits once, records the job ID in out/run.json, and checks the job until it finishes. A render is asynchronous: accepting the request and completing the video are separate events.

Wait for state: "completed". Progress can reach 100% while the job is still active. On success, the script downloads out/short-form.mp4 and prints its saved path. Open that file and watch all three scenes.

The complete implementation is included. These are its core API calls:

const quote = await zvid.authoring.validate(request);
checkQuote(quote, 12);
const accepted = await zvid.renders.create(request);
const job = await trackJob(zvid, accepted.jobId);
await downloadVideo(outputUrl(job), 'out/short-form.mp4');

The SDK calls POST /api/render/validate/api-key, POST /api/render/api-key and GET /api/jobs/{jobId} on https://api.zvid.io. The helpers handle the credit ceiling, waiting and downloading. The API key is sent to Zvid in x-api-key; it is not forwarded to the video download URL. The job-status reference explains the response fields.

If the connection drops or the job fails

To continue tracking or downloading the same saved job, run:

npm run resume

Resume does not submit another render. The script stops waiting after ten minutes, but the remote job may still be running; use the same resume command to check it again. If the job fails, inspect out/job.json for the failure reason.

If submission was interrupted before a job ID arrived, inspect Renders at app.zvid.io before retrying. The example records the submission attempt and blocks a second submission from that output folder. Once you have checked the previous job and deliberately want a new render, rename out/ to preserve its record, then run the render command again. Download completed media promptly because hosted outputs can expire.

How the JSON becomes a short-form video

The code maps each beat into a Zvid scene. Scenes play in array order, and each uses its own local timeline. This example uses hard cuts, so its timing is straightforward:

Video time Content Purpose
0 to 4 seconds Start with one idea Introduce the message
4 to 8 seconds Show one useful step Give the viewer an action
8 to 12 seconds Save for later Finish with a short prompt

Each scene uses TEXT elements for the series label, number, headline, supporting sentence and scene counter. The project sets the canvas and frame rate once. Editing a message in content.json changes the text without requiring you to reposition every layer.

The main headline uses a 780 × 430 pixel box at x: 120, y: 720. Here is the generated layer for the opening scene:

{
  "type": "TEXT",
  "text": "Start with one idea",
  "x": 120,
  "y": 720,
  "width": 780,
Show full example · 18 linesCollapse example
{
  "type": "TEXT",
  "text": "Start with one idea",
  "x": 120,
  "y": 720,
  "width": 780,
  "height": 430,
  "anchor": "top-left",
  "fitToBox": true,
  "style": {
    "fontFamily": "Inter",
    "fontSize": "128px",
    "fontWeight": 800,
    "color": "#F6EFE2",
    "lineHeight": 1.08,
    "textTransform": "uppercase"
  }
}

anchor: "top-left" makes the coordinates refer to the box's top-left corner. fitToBox: true can shrink text that would otherwise overflow; it is still better to shorten a headline than make it difficult to read on a phone.

Adapt the copy and check each destination

Change the messages in data/content.json, then validate again. This compact example accepts exactly three beats, headlines up to 40 characters, supporting sentences up to 64 characters, and scene durations between three and eight seconds. Those are example layout rules, not general Zvid limits. Change the builder and its checks if you need a different structure.

For example, changing secondsPerScene from 4 to 5 makes a 15-second video. Check the new estimate before raising the credit ceiling. Before submitting a new version, preserve the previous out/ folder as described above.

The design leaves space around the text: every text box sits between x: 120 and x: 900, and between y: 380 and y: 1520. These insets are a starting point for this design, not an official safe-area specification for any platform.

Before publishing, check the finished MP4 in the destination app's upload preview:

  • Read every headline at phone size. Shorten copy that shrinks too far or feels rushed.
  • Check that buttons, captions and other interface overlays do not cover important words. Adjust the positions in src/project.js when needed.
  • Review the crop and cover selection separately for Reels, Shorts and TikTok. One successful render does not guarantee every publishing surface displays it identically.
  • Add your post caption and any destination link in the platform's publishing controls. Text drawn inside an MP4 is not a clickable link.

The sample communicates without sound. If you later add narration, keep the words and their timing aligned; the separate timed-subtitles tutorial shows how to use prepared captions. Transcription and social publishing are separate steps.

Start with the supplied content, watch the finished MP4, then change one message and repeat the validation step. That gives you a repeatable short-form layout with a result you can inspect before posting.

Frequently asked questions

Can I generate Reels, YouTube Shorts and TikTok videos from JSON with Zvid?

Yes. Zvid can render a vertical MP4 from a JSON project, and this example creates a 1080 × 1920 video. Review the finished file against the current requirements and upload preview of each destination before publishing it.

Does this example automatically post the video to social media?

No. The example downloads an MP4 to your computer or server. Uploading, scheduling, post captions and platform permissions need a separate manual or integrated publishing step.

How many Zvid credits does the example use?

The supplied 12-second example has a validated estimate of 12 render credits. Validation does not consume render credits, and the script refuses to render above its configured ceiling. Recheck the estimate after changing the project.

Do I need AI-generated footage, music or a saved template?

No. This example builds all three scenes from text and graphics, so it requires no footage, music or stored template. The JSON supplies the copy; Zvid renders the supplied composition.

Why does the script say the job is active at 100%?

The job can report 100% progress before its final state becomes completed. Wait for completion before using its output URL. If local tracking stops, run npm run resume to check the saved job without submitting another render.

Are the example's text margins guaranteed safe areas for all three platforms?

No. The margins are design choices for this example, and platform overlays can vary. Inspect the actual upload preview and adjust text positions when important content is obscured.

Share