<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: DemoVexa</title>
    <description>The latest articles on DEV Community by DemoVexa (@demovexa).</description>
    <link>https://dev.to/demovexa</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4186967%2Fee6e2864-e310-49c2-a9c5-27d1eb9e00b4.png</url>
      <title>DEV Community: DemoVexa</title>
      <link>https://dev.to/demovexa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/demovexa"/>
    <language>en</language>
    <item>
      <title>Normalize Voiceover Loudness With ffmpeg loudnorm: A Two-Pass Recipe</title>
      <dc:creator>DemoVexa</dc:creator>
      <pubDate>Mon, 02 Nov 2026 06:07:23 +0000</pubDate>
      <link>https://dev.to/demovexa/normalize-voiceover-loudness-with-ffmpeg-loudnorm-a-two-pass-recipe-2j0d</link>
      <guid>https://dev.to/demovexa/normalize-voiceover-loudness-with-ffmpeg-loudnorm-a-two-pass-recipe-2j0d</guid>
      <description>&lt;p&gt;To normalize voiceover loudness with ffmpeg, run the &lt;code&gt;loudnorm&lt;/code&gt; filter twice: once to measure the file, then again with those measurements fed back in so the filter can apply one clean, linear gain change. Pick a target in LUFS for where the video will play, cap the true peak a little below 0 dBTP, and check the output with a third measurement. The rest of this post is the commands and the reasons behind each number.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Loudness is measured in LUFS, which tracks how loud audio sounds, not how high the peaks go.&lt;/li&gt;
&lt;li&gt;Single-pass &lt;code&gt;loudnorm&lt;/code&gt; works, but it adjusts gain on the fly and can pump. Two passes give a steadier result.&lt;/li&gt;
&lt;li&gt;Normalize the narration track before mixing music under it, then normalize the final mix.&lt;/li&gt;
&lt;li&gt;Always measure the output. A filter that ran without errors is not proof of the level.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Why does voiceover loudness drift between videos?&lt;/li&gt;
&lt;li&gt;What do LUFS, LRA and true peak mean?&lt;/li&gt;
&lt;li&gt;How do you run loudnorm in two passes?&lt;/li&gt;
&lt;li&gt;Which target should you pick?&lt;/li&gt;
&lt;li&gt;How do you check the result automatically?&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why does voiceover loudness drift between videos?
&lt;/h2&gt;

&lt;p&gt;Because every source is different. A text to speech provider returns files at its own level, and a laptop mic recording sits somewhere else. Change the voice or the room and the next video is louder or quieter than the last.&lt;/p&gt;

&lt;p&gt;If someone watches two of your demos back to back and has to reach for the volume, that is a small tax on every video. I hit this when I swapped voices partway through a set of feature clips. Each file sounded fine alone. In sequence, one jumped out.&lt;/p&gt;

&lt;h2&gt;
  
  
  What do LUFS, LRA and true peak mean?
&lt;/h2&gt;

&lt;p&gt;These three numbers come from the EBU R128 and ITU BS.1770 standards, and &lt;code&gt;loudnorm&lt;/code&gt; reports all of them.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Measure&lt;/th&gt;
&lt;th&gt;What it describes&lt;/th&gt;
&lt;th&gt;Typical use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Integrated loudness (LUFS)&lt;/td&gt;
&lt;td&gt;Average perceived loudness over the whole file&lt;/td&gt;
&lt;td&gt;The main target you normalize to&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Loudness range (LRA, in LU)&lt;/td&gt;
&lt;td&gt;How much loudness varies between quiet and loud parts&lt;/td&gt;
&lt;td&gt;Keep it low for speech so nothing gets lost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;True peak (dBTP)&lt;/td&gt;
&lt;td&gt;The highest level, including peaks between samples&lt;/td&gt;
&lt;td&gt;Cap it below 0 to avoid clipping after encoding&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Peak normalization only looks at the loudest sample, so equal peaks can sound very different. LUFS weights the measurement toward how ears actually hear.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you run loudnorm in two passes?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pass one: measure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-hide_banner&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; voice.wav &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-af&lt;/span&gt; &lt;span class="nv"&gt;loudnorm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;I&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;-16&lt;/span&gt;:TP&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;-1&lt;/span&gt;.5:LRA&lt;span class="o"&gt;=&lt;/span&gt;11:print_format&lt;span class="o"&gt;=&lt;/span&gt;json &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-f&lt;/span&gt; null - 2&amp;gt; measure.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only the log is written. It ends with a JSON block holding &lt;code&gt;input_i&lt;/code&gt;, &lt;code&gt;input_tp&lt;/code&gt;, &lt;code&gt;input_lra&lt;/code&gt;, &lt;code&gt;input_thresh&lt;/code&gt; and &lt;code&gt;target_offset&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pass two: apply
&lt;/h3&gt;

&lt;p&gt;Feed those values back in and set &lt;code&gt;linear=true&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-hide_banner&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; voice.wav &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-af&lt;/span&gt; &lt;span class="nv"&gt;loudnorm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;I&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;-16&lt;/span&gt;:TP&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;-1&lt;/span&gt;.5:LRA&lt;span class="o"&gt;=&lt;/span&gt;11:measured_I&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;-23&lt;/span&gt;.4:measured_TP&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;-4&lt;/span&gt;.1:measured_LRA&lt;span class="o"&gt;=&lt;/span&gt;6.2:measured_thresh&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;-34&lt;/span&gt;.0:offset&lt;span class="o"&gt;=&lt;/span&gt;0.3:linear&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-ar&lt;/span&gt; 48000 voice-norm.wav
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;measured_&lt;/code&gt; numbers are placeholders; use your own. With them, the filter applies one gain change across the file instead of riding the level.&lt;/p&gt;

&lt;p&gt;Two notes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add &lt;code&gt;-ar 48000&lt;/code&gt;. &lt;code&gt;loudnorm&lt;/code&gt; upsamples internally, and without an explicit rate you can end up with a 192 kHz file.&lt;/li&gt;
&lt;li&gt;If the file needs more gain than the true peak cap allows, the filter falls back to dynamic mode. The output log will say so. Fixing a very quiet source beats forcing it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you script this, parse the JSON with &lt;code&gt;jq&lt;/code&gt; and pass the values through, so nobody copies numbers by hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which target should you pick?
&lt;/h2&gt;

&lt;p&gt;Pick by where the video plays, and keep it the same across your library.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Web embeds, docs and social feeds:&lt;/strong&gt; around -16 LUFS integrated is a common choice for speech heard on laptops and phones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Broadcast style delivery:&lt;/strong&gt; EBU R128 specifies -23 LUFS. You will rarely need this for product demos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Platforms that normalize on playback:&lt;/strong&gt; some turn loud uploads down. Check their current docs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For true peak, -1.5 or -1 dBTP leaves headroom for lossy encoders like AAC, which can push peaks slightly higher than the source.&lt;/p&gt;

&lt;p&gt;With music, normalize the narration first, mix the music under it, then run the final mix through both passes. I covered the export side, codecs and containers, in &lt;a href="https://demovexa.com/blog/product-demo-video-resolution-format?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=wk1102-01" rel="noopener noreferrer"&gt;choosing product demo video resolution and format&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you check the result automatically?
&lt;/h2&gt;

&lt;p&gt;Run pass one again on the output and fail the build if it is off target:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;out_i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;ffmpeg &lt;span class="nt"&gt;-hide_banner&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; voice-norm.wav &lt;span class="nt"&gt;-af&lt;/span&gt; &lt;span class="nv"&gt;loudnorm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;print_format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;json &lt;span class="nt"&gt;-f&lt;/span&gt; null - 2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s1"&gt;'/^{/,/^}/p'&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; .input_i&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$out_i&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s1"&gt;'BEGIN { exit (v &amp;lt; -17 || v &amp;gt; -15) }'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Loudness &lt;/span&gt;&lt;span class="nv"&gt;$out_i&lt;/span&gt;&lt;span class="s2"&gt; out of range"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A one LU window is tight enough that nobody hears a jump, and loose enough not to fail on rounding.&lt;/p&gt;

&lt;p&gt;At DemoVexa the narration comes from a connected voice provider or your own recording, exactly the mix of sources that drifts. The &lt;a href="https://demovexa.com/features?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=wk1102-01" rel="noopener noreferrer"&gt;voiceover, script and render features&lt;/a&gt; page shows how voiceover fits the rest of the pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is single-pass loudnorm good enough?
&lt;/h3&gt;

&lt;p&gt;For a preview, yes. For published files, two passes are steadier because the filter knows the whole file first.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I normalize before or after adding music?
&lt;/h3&gt;

&lt;p&gt;Both. Voice alone first, then the final mix.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why is my output file 192 kHz?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;loudnorm&lt;/code&gt; resamples internally. Set the output rate with &lt;code&gt;-ar 48000&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does AAC encoding change loudness?
&lt;/h3&gt;

&lt;p&gt;Integrated loudness barely moves, but peaks can rise a little. That is why the true peak cap sits below 0 dBTP.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Baltej Singh is the founder of DemoVexa, a desktop app and CLI that turns a local codebase into narrated product demo videos. He writes from Delaware, USA.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ffmpeg</category>
      <category>audio</category>
      <category>video</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>VideoObject Structured Data: Add It, Then Prove Google Reads It</title>
      <dc:creator>DemoVexa</dc:creator>
      <pubDate>Thu, 29 Oct 2026 06:05:30 +0000</pubDate>
      <link>https://dev.to/demovexa/videoobject-structured-data-add-it-then-prove-google-reads-it-2nk</link>
      <guid>https://dev.to/demovexa/videoobject-structured-data-add-it-then-prove-google-reads-it-2nk</guid>
      <description>&lt;p&gt;VideoObject structured data is a block of JSON-LD that tells Google what a video on your page is: its name, thumbnail, upload date, length and where the file lives. Adding it takes ten minutes. Proving that Google actually read it and indexed the video takes longer, and that second part is where most pages fall down. This post covers both.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Google needs three properties at minimum: &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;thumbnailUrl&lt;/code&gt; and &lt;code&gt;uploadDate&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;contentUrl&lt;/code&gt; or &lt;code&gt;embedUrl&lt;/code&gt; is what lets Google fetch the video itself. Add at least one.&lt;/li&gt;
&lt;li&gt;Valid markup is not the same as an indexed video. The video also has to be the main content of the page.&lt;/li&gt;
&lt;li&gt;Check in three places: the Rich Results Test, URL Inspection, and the Video indexing report.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What does VideoObject markup look like?&lt;/li&gt;
&lt;li&gt;Which properties actually matter?&lt;/li&gt;
&lt;li&gt;How do you add key moments?&lt;/li&gt;
&lt;li&gt;How do you confirm Google read it?&lt;/li&gt;
&lt;li&gt;Why is my video not indexed?&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What does VideoObject markup look like?
&lt;/h2&gt;

&lt;p&gt;It is a JSON-LD script tag in the page head or body. Here is the shape I use for a product demo page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"application/ld+json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@context&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://schema.org&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;VideoObject&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Exporting a release clip from the CLI&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;description&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A two minute walkthrough of rendering a release clip from a local repo.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;thumbnailUrl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com/media/release-clip-poster.jpg&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;uploadDate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-10-20T09:00:00-04:00&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;duration&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PT2M04S&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contentUrl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com/media/release-clip.mp4&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;embedUrl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://www.youtube.com/embed/VIDEO_ID&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details trip people up. &lt;code&gt;duration&lt;/code&gt; uses ISO 8601, so two minutes and four seconds is &lt;code&gt;PT2M04S&lt;/code&gt;, not &lt;code&gt;2:04&lt;/code&gt;. And &lt;code&gt;uploadDate&lt;/code&gt; should carry a timezone offset. Without one, Google has to guess.&lt;/p&gt;

&lt;p&gt;If you render pages with a framework, generate this block from the same data that renders the player. Hand-written JSON-LD drifts the moment someone swaps the video and forgets the markup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Which properties actually matter?
&lt;/h2&gt;

&lt;p&gt;Three are required, a few more change what Google can do with the video.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Required?&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Title shown in results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;thumbnailUrl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Image for the result; must be crawlable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;uploadDate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;When the video was first published&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Recommended&lt;/td&gt;
&lt;td&gt;Context for matching queries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;duration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Recommended&lt;/td&gt;
&lt;td&gt;Shown as a length badge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;contentUrl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Recommended&lt;/td&gt;
&lt;td&gt;Direct link to the video file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;embedUrl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Recommended&lt;/td&gt;
&lt;td&gt;Link to the player, such as a YouTube embed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;hasPart&lt;/code&gt; (Clip)&lt;/td&gt;
&lt;td&gt;Optional&lt;/td&gt;
&lt;td&gt;Key moments with timestamps&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The thumbnail has to be reachable by Googlebot. If your media folder is blocked in &lt;code&gt;robots.txt&lt;/code&gt;, or the image sits behind a signed URL that expires, the markup validates and the thumbnail still fails.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you add key moments?
&lt;/h2&gt;

&lt;p&gt;Add &lt;code&gt;hasPart&lt;/code&gt; with one &lt;code&gt;Clip&lt;/code&gt; per section. Each clip gets a name, a start offset and an end offset in seconds, plus a URL that jumps to that time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"hasPart"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Clip"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Pick the repo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"startOffset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"endOffset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/demo?t=0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Clip"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Render and export"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"startOffset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"endOffset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;124&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com/demo?t=35"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This only helps if your player honors the &lt;code&gt;t&lt;/code&gt; parameter. Test the URLs by hand before shipping. If the video is on YouTube, chapters in the description usually do this job for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you confirm Google read it?
&lt;/h2&gt;

&lt;p&gt;Run three checks, in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Rich Results Test.&lt;/strong&gt; Paste the live URL. It should detect a Video item with no errors. Warnings about optional fields are fine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;URL Inspection in Search Console.&lt;/strong&gt; Request indexing, then check the "Video indexing" section once the page has been crawled.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Video indexing report.&lt;/strong&gt; This lists pages where Google found a video and whether it indexed it, with a reason when it didn't.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first check only proves the syntax. The second and third tell you what Google decided.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is my video not indexed?
&lt;/h2&gt;

&lt;p&gt;The most common reason I see is "Video isn't on a watch page". Google indexes videos for pages where the video is the main content. A demo clip in the hero of a feature page, surrounded by marketing copy, often gets labeled this way even with perfect markup.&lt;/p&gt;

&lt;p&gt;Other reasons worth checking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The thumbnail URL returns an error or is blocked.&lt;/li&gt;
&lt;li&gt;The player loads only after a click or a consent banner, so Googlebot never sees a video element.&lt;/li&gt;
&lt;li&gt;The video is too small on the page or placed far below the fold.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The practical fix for product sites is a dedicated page per demo: one video, a short description, a transcript and the markup. I wrote up how that fits with &lt;a href="https://demovexa.com/blog/video-rich-results-google?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=wk1026-06" rel="noopener noreferrer"&gt;getting product videos into Google rich results&lt;/a&gt;, including which pages deserve their own watch page.&lt;/p&gt;

&lt;p&gt;At DemoVexa we render demo videos from a local codebase, so the script, timings and chapter names already exist as data. Feeding them into JSON-LD is a small step, and it is part of why I care about getting &lt;a href="https://demovexa.com/ai-product-demo-video-from-code?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=wk1026-06" rel="noopener noreferrer"&gt;code-generated product demo videos&lt;/a&gt; indexed properly.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Does VideoObject markup work for YouTube embeds?
&lt;/h3&gt;

&lt;p&gt;Yes. Use &lt;code&gt;embedUrl&lt;/code&gt; with the YouTube embed link. Google often finds YouTube videos without markup, but the markup ties the video to your page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is JSON-LD better than microdata for video?
&lt;/h3&gt;

&lt;p&gt;Google accepts both. JSON-LD is easier to generate and keep in sync because it sits in one block instead of being spread across HTML attributes.&lt;/p&gt;

&lt;h3&gt;
  
  
  How long does video indexing take?
&lt;/h3&gt;

&lt;p&gt;It varies by site and crawl frequency. Request indexing in URL Inspection and check the Video indexing report after the page is recrawled.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need a separate thumbnail for the markup?
&lt;/h3&gt;

&lt;p&gt;You need one crawlable image URL. Reusing the player's poster image works well and keeps the result consistent with what visitors see.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Baltej Singh is the founder of DemoVexa, a desktop app and CLI that turns a local codebase into narrated product demo videos. He writes from Delaware, USA.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Transparent Background Video Export: Alpha Channels, ProRes 4444 vs WebM VP9</title>
      <dc:creator>DemoVexa</dc:creator>
      <pubDate>Mon, 26 Oct 2026 06:16:14 +0000</pubDate>
      <link>https://dev.to/demovexa/transparent-background-video-export-alpha-channels-prores-4444-vs-webm-vp9-5991</link>
      <guid>https://dev.to/demovexa/transparent-background-video-export-alpha-channels-prores-4444-vs-webm-vp9-5991</guid>
      <description>&lt;p&gt;A transparent background video stores a fourth channel, alpha, next to the color data, so an editor or browser knows which pixels to show. In practice you choose between two files: ProRes 4444 in a MOV for editing, and VP9 in a WebM for the web. This post covers how alpha is stored, the ffmpeg commands I use to make and verify each file, and the mistakes that make transparency quietly disappear.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Alpha only survives if the pixel format carries it. Look for &lt;code&gt;yuva&lt;/code&gt;, not &lt;code&gt;yuv&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;ProRes 4444 is the editing format: high quality, very large files.&lt;/li&gt;
&lt;li&gt;VP9 in WebM is the web format: small files, alpha in Chromium browsers, none in Safari.&lt;/li&gt;
&lt;li&gt;ffmpeg's built-in VP9 decoder ignores alpha, so force &lt;code&gt;libvpx-vp9&lt;/code&gt; when reading a transparent WebM.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is an alpha channel in a video file?&lt;/li&gt;
&lt;li&gt;Should you export ProRes 4444 or WebM VP9?&lt;/li&gt;
&lt;li&gt;How do you encode each format with ffmpeg?&lt;/li&gt;
&lt;li&gt;How do you check that the alpha survived?&lt;/li&gt;
&lt;li&gt;What goes wrong most often?&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is an alpha channel in a video file?
&lt;/h2&gt;

&lt;p&gt;An alpha channel is a per-pixel opacity value stored alongside the color. Zero is fully transparent, the maximum is fully opaque, and values in between give you soft edges and shadows.&lt;/p&gt;

&lt;p&gt;Most delivery video has no alpha at all. H.264 in an MP4 is normally encoded as &lt;code&gt;yuv420p&lt;/code&gt;: brightness plus two color channels and nothing else. So "export with transparency" is a question about codec and pixel format, not a checkbox.&lt;/p&gt;

&lt;p&gt;Alpha can be straight or premultiplied. If an editor reads it the wrong way, you get a dark or light fringe around anti-aliased edges, so check the clip's alpha interpretation setting before blaming the encoder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should you export ProRes 4444 or WebM VP9?
&lt;/h2&gt;

&lt;p&gt;Export ProRes 4444 when the file goes into an editor, and VP9 WebM when it goes onto a web page.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;ProRes 4444 (.mov)&lt;/th&gt;
&lt;th&gt;VP9 with alpha (.webm)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Compression&lt;/td&gt;
&lt;td&gt;Intraframe, near lossless&lt;/td&gt;
&lt;td&gt;Interframe, lossy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ffmpeg pixel format&lt;/td&gt;
&lt;td&gt;&lt;code&gt;yuva444p10le&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;yuva420p&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Color resolution&lt;/td&gt;
&lt;td&gt;Full (4:4:4)&lt;/td&gt;
&lt;td&gt;Subsampled (4:2:0)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;File size&lt;/td&gt;
&lt;td&gt;Very large&lt;/td&gt;
&lt;td&gt;Small&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best home&lt;/td&gt;
&lt;td&gt;Premiere, Final Cut, DaVinci Resolve&lt;/td&gt;
&lt;td&gt;Web pages in Chrome and Edge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weak spot&lt;/td&gt;
&lt;td&gt;Disk space and upload time&lt;/td&gt;
&lt;td&gt;No alpha in Safari or Final Cut&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For scale, Apple's ProRes white paper puts ProRes 4444 at 1080p and 29.97 fps at a target of about 330 Mbps, before alpha.&lt;/p&gt;

&lt;p&gt;The color resolution row matters for UI video. With 4:2:0, small colored labels get slightly soft, while white and gray text holds up well.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you encode each format with ffmpeg?
&lt;/h2&gt;

&lt;p&gt;Start from a transparent PNG sequence and encode it twice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ProRes 4444 with alpha&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-framerate&lt;/span&gt; 30 &lt;span class="nt"&gt;-i&lt;/span&gt; frames/%05d.png &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt;:v prores_ks &lt;span class="nt"&gt;-profile&lt;/span&gt;:v 4444 &lt;span class="nt"&gt;-pix_fmt&lt;/span&gt; yuva444p10le demo.mov

&lt;span class="c"&gt;# VP9 with alpha, constant quality mode&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-framerate&lt;/span&gt; 30 &lt;span class="nt"&gt;-i&lt;/span&gt; frames/%05d.png &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt;:v libvpx-vp9 &lt;span class="nt"&gt;-pix_fmt&lt;/span&gt; yuva420p &lt;span class="nt"&gt;-crf&lt;/span&gt; 30 &lt;span class="nt"&gt;-b&lt;/span&gt;:v 0 demo.webm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details matter:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;-pix_fmt&lt;/code&gt; flag is what keeps alpha. Leave it out and ffmpeg may pick a format without it.&lt;/li&gt;
&lt;li&gt;With &lt;code&gt;libvpx-vp9&lt;/code&gt;, &lt;code&gt;-b:v 0&lt;/code&gt; next to &lt;code&gt;-crf&lt;/code&gt; gives constant quality. Without it, a default bitrate acts as a ceiling.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How do you check that the alpha survived?
&lt;/h2&gt;

&lt;p&gt;Run ffprobe, and know that the two files report alpha differently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffprobe &lt;span class="nt"&gt;-v&lt;/span&gt; error &lt;span class="nt"&gt;-select_streams&lt;/span&gt; v:0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-show_entries&lt;/span&gt; &lt;span class="nv"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;codec_name,pix_fmt:stream_tags&lt;span class="o"&gt;=&lt;/span&gt;alpha_mode &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-of&lt;/span&gt; &lt;span class="nv"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;nw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 demo.webm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the MOV, you want a pixel format starting with &lt;code&gt;yuva&lt;/code&gt;. For the WebM, ffprobe usually reports &lt;code&gt;yuv420p&lt;/code&gt; even when alpha is present, because WebM stores alpha as extra data beside each frame. The real signal is &lt;code&gt;TAG:alpha_mode=1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then pull a frame and view it on a checkerboard:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-c&lt;/span&gt;:v libvpx-vp9 &lt;span class="nt"&gt;-i&lt;/span&gt; demo.webm &lt;span class="nt"&gt;-frames&lt;/span&gt;:v 1 check.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-c:v libvpx-vp9&lt;/code&gt; before &lt;code&gt;-i&lt;/code&gt; matters. Without it, ffmpeg's native VP9 decoder drops alpha and your PNG comes out on solid black.&lt;/p&gt;

&lt;h2&gt;
  
  
  What goes wrong most often?
&lt;/h2&gt;

&lt;p&gt;These are the failures I see most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expecting transparency from an H.264 MP4. If the target only takes MP4, export green screen and key it.&lt;/li&gt;
&lt;li&gt;A converter or upload pipeline that transcodes to &lt;code&gt;yuv420p&lt;/code&gt; and silently drops alpha.&lt;/li&gt;
&lt;li&gt;Previewing a WebM in Safari or Final Cut and deciding the file is broken.&lt;/li&gt;
&lt;li&gt;Trusting &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; order on the web. Safari needs a separate file, such as HEVC with alpha, so pick the file with a small script and test in each browser.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the app I build, the Export step offers a transparent MOV in ProRes 4444, a transparent WebM in VP9 and a green screen MP4. The walkthrough on &lt;a href="https://demovexa.com/blog/green-screen-product-demo-export?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=wk1026-01" rel="noopener noreferrer"&gt;exporting a product demo on green screen or with a transparent background&lt;/a&gt; covers the in-app steps, and the full list of &lt;a href="https://demovexa.com/features?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=wk1026-01" rel="noopener noreferrer"&gt;code-to-video export options and formats&lt;/a&gt; is on the features page.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Does MP4 support a transparent background?
&lt;/h3&gt;

&lt;p&gt;Not with H.264, which most MP4 files contain. Use ProRes 4444 for editing, VP9 WebM for Chromium browsers, or HEVC with alpha for Apple devices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why does my transparent WebM show a black background?
&lt;/h3&gt;

&lt;p&gt;Usually the decoder dropped alpha. In ffmpeg, put &lt;code&gt;-c:v libvpx-vp9&lt;/code&gt; before &lt;code&gt;-i&lt;/code&gt;. Safari doesn't support WebM alpha, so serve it a different file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is ProRes 4444 lossless?
&lt;/h3&gt;

&lt;p&gt;No. Its alpha channel is stored losslessly, but the color data is compressed. It is visually near lossless, so for editing the difference is rarely visible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which format should I send to a video editor?
&lt;/h3&gt;

&lt;p&gt;Ask what they edit in. ProRes 4444 suits Premiere, Final Cut and Resolve. If you don't know their setup, a green screen MP4 works almost everywhere.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Baltej Singh is the founder of DemoVexa, a desktop app and CLI that turns a local codebase into narrated product demo videos. He writes from Delaware, USA.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>video</category>
      <category>ffmpeg</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to Demo a Developer Tool, CLI or API on Video</title>
      <dc:creator>DemoVexa</dc:creator>
      <pubDate>Sat, 17 Oct 2026 06:00:40 +0000</pubDate>
      <link>https://dev.to/demovexa/how-to-demo-a-developer-tool-cli-or-api-on-video-1108</link>
      <guid>https://dev.to/demovexa/how-to-demo-a-developer-tool-cli-or-api-on-video-1108</guid>
      <description>&lt;p&gt;&lt;em&gt;Developer products are hard to show because the interesting part is often invisible. Here's how to make terminals, code and API calls readable on video, and what developers actually want to see.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A SaaS dashboard is easy to put on video. There are buttons, charts and something to click. A CLI, an SDK or an API is harder. The product is a command, a few lines of code or a JSON response, and the useful part (what it saves you from doing) doesn't appear on screen at all.&lt;/p&gt;

&lt;p&gt;This post covers how to plan and lay out a demo for a developer product so it's readable, honest and short.&lt;/p&gt;

&lt;p&gt;Disclosure: I build DemoVexa, a tool that can &lt;a href="https://demovexa.com" rel="noopener noreferrer"&gt;turn your code into product demo videos&lt;/a&gt;. Most of this post is about planning and readability, which applies whatever you use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Show the problem, the smallest working example and the result. Developers care about how few steps it takes.&lt;/li&gt;
&lt;li&gt;Terminal and code text must be readable on a phone: large font, short lines, and only the lines that matter.&lt;/li&gt;
&lt;li&gt;Show real commands and real output shapes, using sample data. Don't fake output your tool can't produce.&lt;/li&gt;
&lt;li&gt;Pair the video with copyable code in the post or README, because nobody can copy text out of a video.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Key takeaways&lt;/li&gt;
&lt;li&gt;What do developers want to see in a demo?&lt;/li&gt;
&lt;li&gt;How do you structure a developer tool demo?&lt;/li&gt;
&lt;li&gt;How do you make terminal and code text readable?&lt;/li&gt;
&lt;li&gt;How do you show an API, which has no UI?&lt;/li&gt;
&lt;li&gt;Should you record your terminal or animate it?&lt;/li&gt;
&lt;li&gt;What should go in the post or README alongside the video?&lt;/li&gt;
&lt;li&gt;A few common mistakes&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What do developers want to see in a demo?
&lt;/h2&gt;

&lt;p&gt;Developers watching a demo are usually asking a few practical questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How do I install it?&lt;/strong&gt; One command, or a long setup?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What's the smallest thing that works?&lt;/strong&gt; The "hello world" of your tool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What does the output look like?&lt;/strong&gt; Real shapes, real errors, real formats.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How does it fit my stack?&lt;/strong&gt; Language, framework, CI, editor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What does it replace?&lt;/strong&gt; The script or manual step they do today.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A good developer demo answers three or four of these and skips the marketing.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you structure a developer tool demo?
&lt;/h2&gt;

&lt;p&gt;A simple structure that works for most CLIs, SDKs and APIs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Part&lt;/th&gt;
&lt;th&gt;What's on screen&lt;/th&gt;
&lt;th&gt;Rough share of the video&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;The problem&lt;/td&gt;
&lt;td&gt;The manual way, or the error people hit today&lt;/td&gt;
&lt;td&gt;10 to 15%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Install or setup&lt;/td&gt;
&lt;td&gt;One command or one config block&lt;/td&gt;
&lt;td&gt;10 to 15%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The smallest example&lt;/td&gt;
&lt;td&gt;The core command or a few lines of code&lt;/td&gt;
&lt;td&gt;30 to 40%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The result&lt;/td&gt;
&lt;td&gt;Output, a file created, a dashboard updated&lt;/td&gt;
&lt;td&gt;20 to 30%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Where to go next&lt;/td&gt;
&lt;td&gt;Docs link, repo, a more advanced example&lt;/td&gt;
&lt;td&gt;5 to 10%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Keep it short. A 60 to 90 second demo of one task usually beats a ten minute tour.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you make terminal and code text readable?
&lt;/h2&gt;

&lt;p&gt;Most developer demos fail on readability, not content. Text that's fine on your monitor is unreadable on a phone or in a small embedded player.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Large font.&lt;/strong&gt; Bigger than you think. Test by watching the video on your phone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Short lines.&lt;/strong&gt; Wrap long commands, or use shorter example paths and names.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fewer lines.&lt;/strong&gt; Show the five lines that matter, not the whole file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Highlight the change.&lt;/strong&gt; When one line matters, highlight or zoom on it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High contrast.&lt;/strong&gt; A plain dark or light theme, not a busy custom one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slow typing, or none.&lt;/strong&gt; Real typing speed is too fast to follow. Either type slowly or show the command appearing line by line.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How do you show an API, which has no UI?
&lt;/h2&gt;

&lt;p&gt;An API demo needs something visible on both sides of the call. Common options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Request and response side by side.&lt;/strong&gt; The request on the left, the formatted JSON response on the right.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code, then effect.&lt;/strong&gt; A few lines of SDK code, then the thing it changes, such as a record appearing in a dashboard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A sequence diagram.&lt;/strong&gt; For flows like authentication, a simple animated diagram of who talks to whom.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Use sample keys and sample data. Never show real tokens, even expired ones. The &lt;a href="https://demovexa.com/blog/api-authentication-demo" rel="noopener noreferrer"&gt;API authentication demo guide&lt;/a&gt; on the DemoVexa blog goes deeper into showing auth flows without exposing secrets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should you record your terminal or animate it?
&lt;/h2&gt;

&lt;p&gt;Both are reasonable, and the choice depends on the tool:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Record&lt;/strong&gt; when the real behaviour is the point: timing, streaming output, an interactive prompt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use a terminal recorder&lt;/strong&gt; that saves text rather than pixels when you want sharp, resizable output for docs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Animate&lt;/strong&gt; when you want a polished, narrated video that matches a script line by line and survives UI or output changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For animated videos, some tools turn your code into product demo videos instead of recording anything. For a developer product, that means recreating the terminal and output as animated scenes with sample data, then timing them to a voiceover. The tradeoff is that the output on screen is a recreation, so check that it matches what your tool really prints.&lt;/p&gt;

&lt;p&gt;There's a longer walkthrough of how to &lt;a href="https://demovexa.com/blog/cli-tool-demo-video" rel="noopener noreferrer"&gt;make a demo video for a CLI tool&lt;/a&gt; on the DemoVexa blog.&lt;/p&gt;

&lt;h2&gt;
  
  
  What should go in the post or README alongside the video?
&lt;/h2&gt;

&lt;p&gt;The video gets attention. The text gets people to actually try it. Next to the video, include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The install command as a copyable code block.&lt;/li&gt;
&lt;li&gt;The smallest working example from the video, exactly as shown.&lt;/li&gt;
&lt;li&gt;A link to the full docs.&lt;/li&gt;
&lt;li&gt;Version numbers for anything version sensitive.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A few common mistakes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Starting with the architecture instead of the result.&lt;/li&gt;
&lt;li&gt;Using a real project with long, messy paths on screen.&lt;/li&gt;
&lt;li&gt;Showing output your tool doesn't actually produce, or hiding errors it does produce.&lt;/li&gt;
&lt;li&gt;Talking over a silent, static terminal for 20 seconds.&lt;/li&gt;
&lt;li&gt;Forgetting that viewers can't copy anything from a video.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How long should a developer tool demo video be?
&lt;/h3&gt;

&lt;p&gt;For one task, 60 to 90 seconds is usually enough. Longer tutorials work on YouTube or in docs, but a short demo of the core workflow is better for a README or landing page.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I make terminal text readable in a demo video?
&lt;/h3&gt;

&lt;p&gt;Use a large font, a high contrast theme and short lines, and show only the lines that matter. Watch the result on a phone before publishing.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do you demo an API that has no user interface?
&lt;/h3&gt;

&lt;p&gt;Show the request and response side by side, or a few lines of SDK code followed by the visible effect. For auth flows, an animated sequence diagram can explain who talks to whom.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I show real API keys in a demo?
&lt;/h3&gt;

&lt;p&gt;No. Use sample or obviously fake keys and sample data, even if a real key is expired or scoped.&lt;/p&gt;

</description>
      <category>devtools</category>
      <category>api</category>
      <category>cli</category>
      <category>devrel</category>
    </item>
    <item>
      <title>How to Make a Product Demo Video with Remotion (and When Not to Build It Yourself)</title>
      <dc:creator>DemoVexa</dc:creator>
      <pubDate>Sat, 17 Oct 2026 05:57:26 +0000</pubDate>
      <link>https://dev.to/demovexa/how-to-make-a-product-demo-video-with-remotion-and-when-not-to-build-it-yourself-2mhm</link>
      <guid>https://dev.to/demovexa/how-to-make-a-product-demo-video-with-remotion-and-when-not-to-build-it-yourself-2mhm</guid>
      <description>&lt;p&gt;&lt;em&gt;Remotion lets you write videos as React components. Here's how a product demo maps onto it, what the hard parts are, and what to check in the license before you start.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you build a React app, there's an appealing idea: why not make the product demo in React too? Your components already exist. Remotion is a framework that renders React components frame by frame into video, so in principle you can reuse your UI, animate it and export an MP4.&lt;/p&gt;

&lt;p&gt;That idea works. It's also more work than it first looks. This post walks through how a demo maps onto Remotion, the parts that take the most time, and when it makes sense to use a tool instead of writing it all yourself.&lt;/p&gt;

&lt;p&gt;Disclosure: I build DemoVexa, which is &lt;a href="https://demovexa.com" rel="noopener noreferrer"&gt;product demo video software that writes the Remotion code for you&lt;/a&gt;. Everything in the first part of this post applies whether you use it or not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Remotion renders React components into video, so a product demo becomes a set of components animated over time.&lt;/li&gt;
&lt;li&gt;The hard parts are not rendering. They're the story, recreating screens with sample data, and timing animation to narration.&lt;/li&gt;
&lt;li&gt;Check Remotion's license: it's free for individuals and for profit companies with up to 3 employees, and larger companies need a Company License.&lt;/li&gt;
&lt;li&gt;Build it yourself for full control. Use a tool if you want the script, voice and timing handled for you.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Key takeaways&lt;/li&gt;
&lt;li&gt;How does a demo map onto Remotion?&lt;/li&gt;
&lt;li&gt;Can you reuse your real components?&lt;/li&gt;
&lt;li&gt;What are the hard parts?&lt;/li&gt;
&lt;li&gt;What should you check in the license?&lt;/li&gt;
&lt;li&gt;When does it make sense to build it yourself?&lt;/li&gt;
&lt;li&gt;What does a tool add on top of Remotion?&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How does a demo map onto Remotion?
&lt;/h2&gt;

&lt;p&gt;In Remotion, a video is a React component that receives the current frame. You decide what's on screen at each frame. A demo usually breaks down like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A composition&lt;/strong&gt; for the whole video, with a width, height, frame rate and duration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A sequence per scene&lt;/strong&gt;, placed at a start frame with a length.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Screen components&lt;/strong&gt; that look like your app: a sidebar, a table, a form.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Animation helpers&lt;/strong&gt; that move a cursor, type text or highlight a button based on the frame.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audio&lt;/strong&gt; for narration and music.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A minimal scene might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AbsoluteFill&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useCurrentFrame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;interpolate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;remotion&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Demo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AbsoluteFill&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Sequence&lt;/span&gt; &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;durationInFrames&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;InvoicesScene&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;AbsoluteFill&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;InvoicesScene&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;frame&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCurrentFrame&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;opacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;interpolate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;opacity&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* your invoices table */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You preview it in Remotion's studio in the browser and render with the Remotion CLI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can you reuse your real components?
&lt;/h2&gt;

&lt;p&gt;Sometimes, but often not directly. Real components tend to depend on things a video doesn't have:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dependency&lt;/th&gt;
&lt;th&gt;Why it's a problem in a video&lt;/th&gt;
&lt;th&gt;Common fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;API calls and data fetching&lt;/td&gt;
&lt;td&gt;No backend while rendering&lt;/td&gt;
&lt;td&gt;Pass sample data as props&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth and user context&lt;/td&gt;
&lt;td&gt;No logged in user&lt;/td&gt;
&lt;td&gt;Wrap in a fake provider&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Global CSS and theme setup&lt;/td&gt;
&lt;td&gt;Styles may not load the same way&lt;/td&gt;
&lt;td&gt;Import the theme into the video project&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Animation libraries tied to real time&lt;/td&gt;
&lt;td&gt;Remotion renders by frame, not by clock&lt;/td&gt;
&lt;td&gt;Drive animation from the current frame&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser only APIs&lt;/td&gt;
&lt;td&gt;Rendering happens in a headless browser, but some APIs still behave differently&lt;/td&gt;
&lt;td&gt;Stub them in the video project&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Many people end up writing simplified "video versions" of their screens that look the same but take plain props. That's fine, and it's often faster than making real components render cleanly outside the app.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the hard parts?
&lt;/h2&gt;

&lt;p&gt;Rendering is the easy part. The time goes into:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The story.&lt;/strong&gt; Deciding which screens to show, in what order, and why. No framework helps here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sample data.&lt;/strong&gt; Believable names and numbers for every table and chart.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timing to narration.&lt;/strong&gt; If there's a voiceover, each click and caption should land on the right word. That means knowing where each word starts in the audio and converting it to frames.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Formats.&lt;/strong&gt; A 16:9 layout doesn't work as 9:16. Each format needs its own arrangement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maintenance.&lt;/strong&gt; When the real UI changes, the video version of each screen has to change too.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What should you check in the license?
&lt;/h2&gt;

&lt;p&gt;Remotion is not MIT licensed. According to its license page (checked October 2026), the Free License covers individuals, for profit organisations with up to 3 employees, non profits, and evaluation before commercial use, and it allows commercial videos. Other companies need a Company License, sold through remotion.pro. The page also notes that the license will change slightly in Remotion 5.0, and it has an FAQ for edge cases. Read the current terms before you build anything for a company.&lt;/p&gt;

&lt;h2&gt;
  
  
  When does it make sense to build it yourself?
&lt;/h2&gt;

&lt;p&gt;Building a demo in Remotion yourself makes sense when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want full control over every frame and animation.&lt;/li&gt;
&lt;li&gt;You'll make a small number of videos and maintain them like code.&lt;/li&gt;
&lt;li&gt;You have someone who enjoys this kind of work and has time for it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It makes less sense when you need many videos, several languages, or frequent updates, and nobody has time to keep the video project in sync with the app.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does a tool add on top of Remotion?
&lt;/h2&gt;

&lt;p&gt;Some tools use Remotion underneath and automate the parts above. DemoVexa is one: it's product demo video software that writes the Remotion code for you. Claude reads your app's code, writes the script, and a build agent recreates your screens in React and animates them with Remotion, timing each move to the voiceover. You review the brief, script and scene plan instead of writing components.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is Remotion?
&lt;/h3&gt;

&lt;p&gt;Remotion is a framework for making videos with React. You write components that render based on the current frame, preview them in a browser studio and render them to video files.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Remotion free to use?
&lt;/h3&gt;

&lt;p&gt;According to Remotion's license page, it's free for individuals, for profit organisations with up to 3 employees, non profits and evaluation, including commercial videos. Other companies need a Company License. Check the current terms, since the page says they change slightly in Remotion 5.0.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use my app's real React components in a Remotion video?
&lt;/h3&gt;

&lt;p&gt;Sometimes. Components that fetch data, need a logged in user or animate on real time usually need sample data props, fake providers or frame based animation before they render cleanly in a video.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need to know Remotion to make code-generated demo videos?
&lt;/h3&gt;

&lt;p&gt;Not with every tool. In DemoVexa, Claude builds the video in React with Remotion, and you change it by editing the brief and script or by asking for the change in plain words. The &lt;a href="https://demovexa.com/faq" rel="noopener noreferrer"&gt;DemoVexa FAQ on making demo videos from code&lt;/a&gt; covers what else you need.&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>video</category>
    </item>
    <item>
      <title>Screen Recorder or Code-Generated Demo: Which Should You Use?</title>
      <dc:creator>DemoVexa</dc:creator>
      <pubDate>Thu, 15 Oct 2026 17:53:06 +0000</pubDate>
      <link>https://dev.to/demovexa/screen-recorder-or-code-generated-demo-which-should-you-use-2ijj</link>
      <guid>https://dev.to/demovexa/screen-recorder-or-code-generated-demo-which-should-you-use-2ijj</guid>
      <description>&lt;p&gt;&lt;em&gt;An honest side by side of recording your screen and rebuilding your UI from code, with the cases where each one is the better choice.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There are now two very different ways to make a product demo video. You can record your screen while you use the app, or you can have a tool rebuild the app's screens from its source code and animate them. Both produce an MP4. They get there in completely different ways, and that changes what each one is good at.&lt;/p&gt;

&lt;p&gt;This isn't a post that ends with "always use code". Screen recorders are the right tool for a lot of jobs. The goal is to make the choice on purpose.&lt;/p&gt;

&lt;p&gt;Disclosure: I make DemoVexa, which is &lt;a href="https://demovexa.com" rel="noopener noreferrer"&gt;demo video software that rebuilds your UI from code&lt;/a&gt;, so I have a side in this. I've tried to be fair about where a screen recorder is the better choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Screen recorders capture exactly what's on screen, quickly, with almost no setup.&lt;/li&gt;
&lt;li&gt;Code-generated demos rebuild the UI from source, which makes them easier to update and keeps real data off screen.&lt;/li&gt;
&lt;li&gt;Recorders win for quick, informal and one off videos. Code-generated demos win for videos you'll keep and update.&lt;/li&gt;
&lt;li&gt;Many teams will use both, for different kinds of video.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Key takeaways&lt;/li&gt;
&lt;li&gt;How does each approach work?&lt;/li&gt;
&lt;li&gt;How do they compare side by side?&lt;/li&gt;
&lt;li&gt;When is a screen recorder the better choice?&lt;/li&gt;
&lt;li&gt;When is a code generated demo the better choice?&lt;/li&gt;
&lt;li&gt;What does each one cost you?&lt;/li&gt;
&lt;li&gt;Where does DemoVexa sit?&lt;/li&gt;
&lt;li&gt;A simple way to decide&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How does each approach work?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A screen recorder&lt;/strong&gt; captures pixels from your display, usually with your voice and sometimes your webcam. What you do is what the viewer sees. Tools range from the recorder built into your operating system to dedicated apps with editing, captions and sharing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A code-generated demo&lt;/strong&gt; starts from the product's code. A tool reads it, writes or takes a script, adds a voice, and recreates the screens as animation. Nothing is captured from a display. The output looks like the app because it's built from the same components, labels and styles.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do they compare side by side?
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Screen recorder&lt;/th&gt;
&lt;th&gt;Code-generated demo&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Setup&lt;/td&gt;
&lt;td&gt;Install and press record&lt;/td&gt;
&lt;td&gt;Point the tool at the code, write a brief&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;First video&lt;/td&gt;
&lt;td&gt;Minutes, if the take goes well&lt;/td&gt;
&lt;td&gt;Longer, because it builds the scenes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What's on screen&lt;/td&gt;
&lt;td&gt;Whatever was on your screen&lt;/td&gt;
&lt;td&gt;Recreated screens with sample data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mistakes in a take&lt;/td&gt;
&lt;td&gt;Re-record or edit around them&lt;/td&gt;
&lt;td&gt;Fix the script or scene plan and rebuild&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;After a UI change&lt;/td&gt;
&lt;td&gt;Record again&lt;/td&gt;
&lt;td&gt;Rebuild from the latest code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sharpness&lt;/td&gt;
&lt;td&gt;Depends on your display and zoom&lt;/td&gt;
&lt;td&gt;Drawn at the output size&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Live behaviour&lt;/td&gt;
&lt;td&gt;Shows real responses and real data&lt;/td&gt;
&lt;td&gt;Shows a recreation, not live responses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Your face on camera&lt;/td&gt;
&lt;td&gt;Usually supported&lt;/td&gt;
&lt;td&gt;Usually not the point&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skills needed&lt;/td&gt;
&lt;td&gt;Presenting, editing&lt;/td&gt;
&lt;td&gt;Reviewing a script and scenes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Neither column is better everywhere. The rows that matter depend on the video you're making.&lt;/p&gt;

&lt;h2&gt;
  
  
  When is a screen recorder the better choice?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quick, informal videos.&lt;/strong&gt; Explaining a bug to a teammate, answering a support question, giving feedback on a design.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anything with your face.&lt;/strong&gt; A founder update or a personal sales follow up works better with a real person on camera.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live behaviour.&lt;/strong&gt; If the point is that a real integration responds, or real data loads, a recording shows that honestly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One off videos.&lt;/strong&gt; If nobody will watch it after this week, the update cost doesn't matter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No access to the code.&lt;/strong&gt; If you can't get the code or a good description of the product, recording is the practical option.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When is a code generated demo the better choice?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Videos you'll keep.&lt;/strong&gt; Landing page demos, docs videos and onboarding clips stay useful for months, so the cost of updating them matters most.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Products that change often.&lt;/strong&gt; If the UI changes every few weeks, rebuilding from code is easier than re-recording.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Several formats.&lt;/strong&gt; When you need 16:9, 9:16 and 1:1, a tool that lays out each format separately avoids awkward crops.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Several languages.&lt;/strong&gt; Rewriting a script and voice per language is easier than recording a person in each one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy.&lt;/strong&gt; When your real environment holds customer data you can't show, recreated screens with sample data avoid the problem.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What does each one cost you?
&lt;/h2&gt;

&lt;p&gt;Not in money, which varies by tool, but in time and attention:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Screen recording&lt;/strong&gt; costs most in the recording and editing session, and again every time the product changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code-generated demos&lt;/strong&gt; cost most in setup and review: pointing the tool at the right code, reading the script, checking the scene plan and the final video.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a video will be redone many times, the second pattern usually ends up cheaper. If it's made once, the first one usually is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where does DemoVexa sit?
&lt;/h2&gt;

&lt;p&gt;DemoVexa is product demo video software that rebuilds your UI from code instead of recording it. It's a desktop app for macOS, Windows and Linux, with a CLI. It reads a local code folder, Claude writes the script, ElevenLabs can voice it (or you record your own voice, or use captions only), and the screens are recreated as animated React components and rendered as MP4s in 16:9, 9:16 and 1:1. The page on &lt;a href="https://demovexa.com/why-demovexa" rel="noopener noreferrer"&gt;why it makes videos from code instead of screen recordings&lt;/a&gt; explains the reasoning in more detail.&lt;/p&gt;

&lt;p&gt;It's not a screen recorder, and it doesn't try to replace one for quick, personal videos.&lt;/p&gt;

&lt;h2&gt;
  
  
  A simple way to decide
&lt;/h2&gt;

&lt;p&gt;Ask two questions about the video:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Will anyone still watch it in three months?&lt;/li&gt;
&lt;li&gt;Will the screens it shows change before then?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If both answers are yes, a code-generated demo is worth trying. If either answer is no, a screen recorder is probably the faster choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is a code-generated demo better than a screen recording?
&lt;/h3&gt;

&lt;p&gt;Not in general. It's better for videos you'll keep and update, and for avoiding real data on screen. A screen recording is better for quick, personal and one off videos, and for showing live behaviour.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use both approaches in the same product?
&lt;/h3&gt;

&lt;p&gt;Yes. A common split is code-generated demos for landing pages, docs and launches, and screen recordings for support replies, internal updates and anything with a person on camera.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do code-generated demos look like the real app?
&lt;/h3&gt;

&lt;p&gt;They're built to. Because they use the app's own labels, layout and styles, they look like the product, but they're a recreation, so it's worth comparing them to the real app before publishing.&lt;/p&gt;

&lt;h3&gt;
  
  
  What do I need to make a code-generated demo with DemoVexa?
&lt;/h3&gt;

&lt;p&gt;A copy of the code on your computer (or the product's website and documents), Claude Code with a Claude Pro or Max plan or an Anthropic API key, and optionally an ElevenLabs key for AI voices. The page on &lt;a href="https://demovexa.com/faq" rel="noopener noreferrer"&gt;requirements for making demo videos from code&lt;/a&gt; lists them in full.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>saas</category>
      <category>video</category>
    </item>
    <item>
      <title>Why Most Features Ship Without a Demo Video (and What Actually Helps)</title>
      <dc:creator>DemoVexa</dc:creator>
      <pubDate>Thu, 15 Oct 2026 17:36:53 +0000</pubDate>
      <link>https://dev.to/demovexa/why-most-features-ship-without-a-demo-video-and-what-actually-helps-4o2g</link>
      <guid>https://dev.to/demovexa/why-most-features-ship-without-a-demo-video-and-what-actually-helps-4o2g</guid>
      <description>&lt;p&gt;&lt;em&gt;It's not laziness. A demo video is a five job pipeline, and developers only signed up for one of those jobs.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A feature gets merged. Someone says "we should make a quick demo for this." A week goes by. Then the next release goes out. Then the UI changes, and the demo you never made would have been out of date anyway.&lt;/p&gt;

&lt;p&gt;If you build software, you've probably seen this happen. The feature is in the changelog and maybe in the docs, but there's no video showing it working, so plenty of users never find it.&lt;/p&gt;

&lt;p&gt;I don't think this happens because developers don't care. I think it happens because a demo video looks like one task and is actually five.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A demo video looks like one task, but it's really five: story, script, voice, footage, and editing with formats.&lt;/li&gt;
&lt;li&gt;Screen recordings go stale with every release, so the real cost is remaking the video, not making it once.&lt;/li&gt;
&lt;li&gt;Writing the story and script as text before recording, and keeping each video to one feature, makes demos cheaper to redo.&lt;/li&gt;
&lt;li&gt;Treat demos like docs: when a release changes a screen, the demo for that screen goes on the update list.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Key takeaways&lt;/li&gt;
&lt;li&gt;A "quick demo" is five jobs&lt;/li&gt;
&lt;li&gt;The screen recording trap&lt;/li&gt;
&lt;li&gt;What actually helps&lt;/li&gt;
&lt;li&gt;Where DemoVexa fits&lt;/li&gt;
&lt;li&gt;A quick checklist for your next feature&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A "quick demo" is five jobs
&lt;/h2&gt;

&lt;p&gt;Here's what a decent product demo actually needs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A story.&lt;/strong&gt; What problem is this feature solving, for whom, and in what order should the screens appear? This is product marketing work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A script.&lt;/strong&gt; Words that match each scene, short enough that people don't drop off.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A voice.&lt;/strong&gt; Either you record yourself, which most of us hate, or you find someone who will.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The footage.&lt;/strong&gt; Usually a screen recording. Which means clean sample data, a clean browser, no notifications, and a cursor that doesn't wander.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Editing and formats.&lt;/strong&gt; Cuts, zooms, captions, and then a 16:9 version for YouTube, a vertical one for Shorts or Reels, and maybe a square one for LinkedIn.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each of these is a separate skill. A developer can do all five, but they'll be slow at three of them, and the whole thing competes with the next ticket. So the demo slips.&lt;/p&gt;

&lt;h2&gt;
  
  
  The screen recording trap
&lt;/h2&gt;

&lt;p&gt;Most of us start with step 4 because it feels like the "real" work. Open the app, hit record, click through the feature.&lt;/p&gt;

&lt;p&gt;Then the problems show up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You fumble a click on take three, so you restart.&lt;/li&gt;
&lt;li&gt;Your local database has test rows called "asdf" and "test test 2" that you don't want on camera.&lt;/li&gt;
&lt;li&gt;Someone's real email address is visible in a table.&lt;/li&gt;
&lt;li&gt;You finish recording and realise you never explained why the feature matters.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these has a fix that you can set up once:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A fumbled click ruins the take&lt;/td&gt;
&lt;td&gt;Record scenes separately, so one mistake costs one scene&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test rows like "asdf" on camera&lt;/td&gt;
&lt;td&gt;A seed script or demo account with believable data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real customer data visible&lt;/td&gt;
&lt;td&gt;A demo account that never holds real data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The "why" never gets explained&lt;/td&gt;
&lt;td&gt;Write who, before and the one moment before recording&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The video shows an old UI after a release&lt;/td&gt;
&lt;td&gt;Put the demo on the list of things to update when that screen changes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And the biggest one: &lt;strong&gt;the recording goes stale with every release.&lt;/strong&gt; You rename a button or move a menu, and now the video shows something that doesn't exist. You either re-record, or you leave an outdated video up and hope nobody notices. Usually it's the second.&lt;/p&gt;

&lt;p&gt;This is why I think a lot of teams quietly give up on demos after the first few. The cost isn't just making the video once. It's making it again every time the product changes. That repeat cost is the main argument for &lt;a href="https://demovexa.com/why-demovexa" rel="noopener noreferrer"&gt;making product videos from code instead of screen recordings&lt;/a&gt;, which I'll come back to below.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually helps
&lt;/h2&gt;

&lt;p&gt;Here are habits that help, whatever tools you use.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write the story before you touch the app
&lt;/h3&gt;

&lt;p&gt;Before recording anything, write three lines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who is this for?&lt;/li&gt;
&lt;li&gt;What were they doing before this feature existed?&lt;/li&gt;
&lt;li&gt;What is the one moment that shows the feature working?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That third line is your video. Everything else is setup. If you can't write it down, a recording won't fix it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep it short and about one thing
&lt;/h3&gt;

&lt;p&gt;In my view, a demo for a single feature should usually be under a minute or two. One feature, one flow, one result. If you need to show five things, make five videos. Short videos are also much easier to keep current, because when one screen changes you only redo one of them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use sample data on purpose
&lt;/h3&gt;

&lt;p&gt;Make a seed script or a demo account with believable data: realistic names, realistic numbers, nothing private. You'll reuse it for every demo, screenshot and docs page. It's a small piece of work that saves you from blurring things out later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Separate the script from the footage
&lt;/h3&gt;

&lt;p&gt;If the voiceover and the visuals are recorded together, any change means redoing both. Write the script as text first. Then the visuals can be redone without re-recording your voice, and the voice can be fixed without touching the visuals.&lt;/p&gt;

&lt;h3&gt;
  
  
  Plan for every format at the start
&lt;/h3&gt;

&lt;p&gt;If you know you need a vertical version, design for it from the start. Cropping a 16:9 recording to 9:16 almost always cuts off the thing you're trying to show.&lt;/p&gt;

&lt;h3&gt;
  
  
  Treat demos like code that needs maintenance
&lt;/h3&gt;

&lt;p&gt;This is the mindset shift that matters most, in my opinion. A demo is not a one off asset. It's tied to your product the same way docs are. When a release changes a screen, the demo for that screen should be on the list, the same way a docs update would be.&lt;/p&gt;

&lt;p&gt;If that sounds like too much work, it's a sign the way you make demos is too expensive to repeat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where DemoVexa fits
&lt;/h2&gt;

&lt;p&gt;That last point is the idea behind DemoVexa, &lt;a href="https://demovexa.com" rel="noopener noreferrer"&gt;product demo video software&lt;/a&gt; built around rebuilding a video after a release instead of re-recording it. It's a desktop app (and a CLI) that reads your code and docs, writes a script, adds a voiceover, and rebuilds your UI as animated React components instead of recording the screen. Since version 0.3.5 it can also start from a product's website and uploaded documents, though screens recreated that way are less exact than when it reads the code. When the product changes, you rebuild the video from the latest code.&lt;/p&gt;

&lt;p&gt;I'm not saying you need a tool for this. The habits above work with a plain screen recorder too. The point is that the cost of a demo has to be low enough that you'll actually make the next one.&lt;/p&gt;

&lt;h2&gt;
  
  
  A quick checklist for your next feature
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Three lines written: who, before, the one moment&lt;/li&gt;
&lt;li&gt;[ ] Demo account or seed data ready, nothing private on screen&lt;/li&gt;
&lt;li&gt;[ ] Script written as text before recording&lt;/li&gt;
&lt;li&gt;[ ] Under two minutes, one feature only&lt;/li&gt;
&lt;li&gt;[ ] Formats decided up front (16:9, 9:16, 1:1)&lt;/li&gt;
&lt;li&gt;[ ] Added to the "update when this screen changes" list&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your team has a way of keeping demos current that works, I'd like to hear it in the comments.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you want to see what rebuilding a demo from code looks like, DemoVexa has a 14 day free trial, no card needed.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why do product demo videos go out of date so quickly?
&lt;/h3&gt;

&lt;p&gt;A screen recording captures the UI exactly as it was on the day you recorded it. Any renamed button, moved menu or changed flow makes the video show something users can't find. Unless updating demos is part of the release routine, old videos tend to stay up.&lt;/p&gt;

&lt;h3&gt;
  
  
  How long should a single feature demo be?
&lt;/h3&gt;

&lt;p&gt;There's no fixed rule. In my view, one feature should usually fit in under a minute or two, showing one flow and one result. If you need longer, it's often a sign the video covers more than one feature.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I have to record my own voice for a product demo?
&lt;/h3&gt;

&lt;p&gt;No. You can record yourself, use a text to speech voice, or skip narration and rely on captions and music. Whichever you pick, writing the script as text first makes it easier to change later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I just crop a 16:9 demo into a vertical video?
&lt;/h3&gt;

&lt;p&gt;You can, but cropping a wide recording to 9:16 usually cuts off part of the screen you're trying to show. A vertical version works better when each scene is laid out for the taller frame, with the important part of the screen larger and centred.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is there a way to make a demo video without screen recording?
&lt;/h3&gt;

&lt;p&gt;Yes. Some tools rebuild the interface instead of capturing it. DemoVexa, for example, reads your app's code and recreates the screens as animated React components with sample data, so there is no recording step. The &lt;a href="https://demovexa.com/faq" rel="noopener noreferrer"&gt;FAQ on making demo videos from code&lt;/a&gt; covers requirements and pricing.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>startup</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Treat Your Demo Environment Like a Test Fixture</title>
      <dc:creator>DemoVexa</dc:creator>
      <pubDate>Thu, 15 Oct 2026 15:11:46 +0000</pubDate>
      <link>https://dev.to/demovexa/treat-your-demo-environment-like-a-test-fixture-45dj</link>
      <guid>https://dev.to/demovexa/treat-your-demo-environment-like-a-test-fixture-45dj</guid>
      <description>&lt;p&gt;When a feature demo takes far more takes than it should, the cause is often the app, not the person recording it. A toast from a background job slides in. A table sorts differently than it did last time. A timestamp says "3 minutes ago" in one take and "11 minutes ago" in the next. A dev overlay sits in the corner of every frame.&lt;/p&gt;

&lt;p&gt;Developers already know this kind of problem. It's the same thing that makes tests flaky: state you don't control. So the fix is the same too. Treat the demo environment like a test fixture: known data, a known starting point, and nothing that changes between runs.&lt;/p&gt;

&lt;p&gt;This post is about that setup. It helps a lot if you record your screen, and most of it still helps if you &lt;a href="https://demovexa.com" rel="noopener noreferrer"&gt;create demo videos from code&lt;/a&gt; instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Most demo retakes come from app state you don't control, the same thing that makes tests flaky.&lt;/li&gt;
&lt;li&gt;A seed script plus a reset command means every take starts from exactly the same state.&lt;/li&gt;
&lt;li&gt;Fixed dates, a fixed clock, a production build and a fixed window size remove most surprises on screen.&lt;/li&gt;
&lt;li&gt;Demo the feature flags your users actually have, and check the flow with a scripted walk through before recording.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Key takeaways&lt;/li&gt;
&lt;li&gt;What "deterministic" means for a demo&lt;/li&gt;
&lt;li&gt;1. A seed script you can run in one command&lt;/li&gt;
&lt;li&gt;2. A reset command&lt;/li&gt;
&lt;li&gt;3. Pin the screen&lt;/li&gt;
&lt;li&gt;4. Freeze time and quiet the background&lt;/li&gt;
&lt;li&gt;5. Match feature flags to what users will see&lt;/li&gt;
&lt;li&gt;6. Check it like a test&lt;/li&gt;
&lt;li&gt;If you don't record at all&lt;/li&gt;
&lt;li&gt;FAQ&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What "deterministic" means for a demo
&lt;/h2&gt;

&lt;p&gt;A test is deterministic when the same input gives the same output every run. For a demo, that means the same data, the same screen and the same timing every time. Things that commonly break it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Relative times ("2 hours ago") and today's date&lt;/li&gt;
&lt;li&gt;Random IDs, avatars or colours generated per user&lt;/li&gt;
&lt;li&gt;Sort orders that depend on when rows were inserted&lt;/li&gt;
&lt;li&gt;Background jobs, websockets and polling that push updates mid take&lt;/li&gt;
&lt;li&gt;Feature flags that differ between your machine and production&lt;/li&gt;
&lt;li&gt;UI that only exists in development: error overlays, devtools buttons, debug banners&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click through your flow once and write down every one of these you see. That list is your to do list for the rest of this post.&lt;/p&gt;

&lt;p&gt;Here's how each one maps to a fix covered below:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source of flakiness&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Relative times and today's date&lt;/td&gt;
&lt;td&gt;Fixed demo day in the seed data, plus a fixed clock&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Random IDs, avatars or colours&lt;/td&gt;
&lt;td&gt;Fixed values in the seed script&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Insert order sorting&lt;/td&gt;
&lt;td&gt;Explicit positions or created dates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Background jobs, websockets, polling&lt;/td&gt;
&lt;td&gt;A demo mode that turns live updates off&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flags that differ from production&lt;/td&gt;
&lt;td&gt;Flag values checked in with the demo config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Development only UI&lt;/td&gt;
&lt;td&gt;A production build run locally&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  1. A seed script you can run in one command
&lt;/h2&gt;

&lt;p&gt;Create the demo data in code, not by clicking around in the app. A seed script is reviewable, repeatable and safe to commit, as long as it holds no real customer data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// scripts/seed-demo.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DEMO_DAY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-03-02T10:00:00Z&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;companies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Northwind Studio&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Team&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Harbor and Pine&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Solo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Lumen Labs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Team&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;daysBefore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;days&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DEMO_DAY&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;days&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;86400000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few rules that make seed data look right on camera:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Believable names.&lt;/strong&gt; "Test Co" and "asdf" pull attention away from the feature. Made up but plausible names don't.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fixed dates.&lt;/strong&gt; Build every date from one fixed demo day, so "last week" means the same thing every time you run it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stable order.&lt;/strong&gt; Give rows explicit positions or created dates, so lists don't reshuffle between takes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nothing real.&lt;/strong&gt; No customer names, emails or internal URLs, even ones that look harmless.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. A reset command
&lt;/h2&gt;

&lt;p&gt;The seed script gets you a good starting state once. The reset command gets you back to it after every take.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"demo:reset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node scripts/reset-demo.js &amp;amp;&amp;amp; node scripts/seed-demo.js"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scope the reset to a demo account or tenant, and make it refuse to run against production. The whole point is that take two starts exactly like take one, without you undoing by hand whatever the last take changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Pin the screen
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Run a production build locally.&lt;/strong&gt; Development builds often show framework overlays and indicators. A production build looks like what users see.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix the window size.&lt;/strong&gt; If you automate the flow with Playwright, set the viewport in the config. If you click by hand, keep one browser profile just for demos: no extensions, no bookmarks bar, no personal logins.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick one zoom level&lt;/strong&gt; and keep it for every scene and every video.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quiet the OS.&lt;/strong&gt; Turn on Do Not Disturb or Focus, close chat apps, and hide anything on the desktop.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Freeze time and quiet the background
&lt;/h2&gt;

&lt;p&gt;Relative timestamps are the classic flaky demo problem. If you drive the flow with Playwright, its clock API can pin the time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFixedTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-03-02T10:00:00Z&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you click by hand, add a demo mode to the app that reads a fixed "now" from an environment variable. While you're there, turn off the things that push surprise updates into the frame:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEMO_MODE&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// fixed clock, no live updates, no onboarding tours&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stub slow third party calls with fixed responses too, so a spinner never hangs in the middle of a scene.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Match feature flags to what users will see
&lt;/h2&gt;

&lt;p&gt;Demo the state your users actually get. If a flag is on locally but off for customers, the video promises something they can't find. Write the flag values the demo depends on into the demo config, so they're checked in next to the seed data and not living in someone's local settings.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Check it like a test
&lt;/h2&gt;

&lt;p&gt;Before you record, walk the flow once with a script. A short Playwright test that clicks through each step and takes a screenshot will catch most surprises: a missing row, a wrong label, a banner you forgot about. Playwright can also record video of a test run, which is meant for debugging, so check whether the quality is good enough for your use before you rely on it.&lt;/p&gt;

&lt;p&gt;A short checklist for the day you record:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;code&gt;npm run demo:reset&lt;/code&gt; ran without errors&lt;/li&gt;
&lt;li&gt;[ ] Production build, fixed window size, one zoom level&lt;/li&gt;
&lt;li&gt;[ ] Clock fixed, live updates off&lt;/li&gt;
&lt;li&gt;[ ] Flags match production&lt;/li&gt;
&lt;li&gt;[ ] Screenshot walk through looked right&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  If you don't record at all
&lt;/h2&gt;

&lt;p&gt;Some tools skip screen capture entirely. DemoVexa is one of them: it reads your code and rebuilds the screens as animated React components with sample data, so there's no recording session to stabilise. I wrote a separate guide on &lt;a href="https://demovexa.com/blog/software-demo-without-screen-recording" rel="noopener noreferrer"&gt;creating software demo videos without screen recording&lt;/a&gt; on the DemoVexa blog, which covers that workflow from planning to export.&lt;/p&gt;

&lt;p&gt;The fixture mindset still applies there. Clear, consistent labels in your UI, realistic sample data and docs that describe each task in order make any demo easier to get right, whether a person or a tool is putting it together.&lt;/p&gt;

&lt;p&gt;What usually breaks your demo takes? I'm curious which items people would add to the list above.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How do I make demo data look realistic?
&lt;/h3&gt;

&lt;p&gt;Create it with a seed script instead of by hand. Use plausible made up names and numbers, build every date from one fixed demo day, and give rows a fixed order. Keep real customer names, emails and internal URLs out of it completely.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I stop timestamps changing between demo takes?
&lt;/h3&gt;

&lt;p&gt;Fix the clock. If you drive the flow with Playwright, &lt;code&gt;page.clock.setFixedTime()&lt;/code&gt; pins the time the page sees. If you click by hand, add a demo mode to your app that reads a fixed "now" from an environment variable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I record a demo on a development build or a production build?
&lt;/h3&gt;

&lt;p&gt;A production build, run locally against your demo data. Development builds often show framework overlays, indicators and debug UI that users never see.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can Playwright record video of a test run?
&lt;/h3&gt;

&lt;p&gt;Yes. Playwright can save a video of each test run, set through the video option in its config or the recordVideo option when creating a browser context. It's designed for debugging, so check whether the quality suits your use before relying on it for a public demo.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I keep customer data out of a product demo video?
&lt;/h3&gt;

&lt;p&gt;Use a separate demo account or tenant filled only by your seed script, and check every screen before you record. Tools that rebuild the UI rather than recording it, such as DemoVexa, show sample data instead of your real customers.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>testing</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
