How to record videos with puppeter
Published: 2022-12-05 20:40:32

<div class="crayons-article__main">

          <div class="crayons-article__body text-styles spec__body" data-article-id="1284849" id="article-body">
            <p>I gathered everything you need to know about how to record videos with Puppeteer in one place. Enjoy!</p>

<h2>
  <a name="a-quickstart" href="#a-quickstart">
  </a>
  A quickstart
</h2>

<p>To generate a video with Puppeteer for page, we are going to use the <a href="https://www.npmjs.com/package/puppeteer-screen-recorder">puppeteer-screen-recorder</a> library:<br>
</p>

<div class="highlight js-code-highlight">
<pre class="highlight shell"><code>npm i puppeteer-screen-recorder
</code></pre>
<div class="highlight__panel js-actions-panel">
<div class="highlight__panel-action js-fullscreen-code-action">
    <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewBox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title>
    <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path>
</svg>

    <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewBox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title>
    <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path>
</svg>

</div>
</div>
</div>



<p>Let's start with a simple example by generating a video for loading the landing page of <a href="https://tailwindcss.com/">Tailwind CSS</a> and opening their pricing page:<br>
</p>

<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="dl">'</span><span class="s1">use strict</span><span class="dl">'</span><span class="p">;</span>

<span class="kd">const</span> <span class="nx">puppeteer</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">puppeteer</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">PuppeteerScreenRecorder</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">puppeteer-screen-recorder</span><span class="dl">'</span><span class="p">);</span>

<span class="p">(</span><span class="k">async</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">browser</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">puppeteer</span><span class="p">.</span><span class="nx">launch</span><span class="p">();</span>
    <span class="k">try</span> <span class="p">{</span>
        <span class="kd">const</span> <span class="nx">page</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">browser</span><span class="p">.</span><span class="nx">newPage</span><span class="p">();</span>
        <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">setViewport</span><span class="p">({</span> <span class="na">width</span><span class="p">:</span> <span class="mi">1920</span><span class="p">,</span> <span class="na">height</span><span class="p">:</span> <span class="mi">1080</span><span class="p">,</span> <span class="na">deviceScaleFactor</span><span class="p">:</span> <span class="mi">2</span> <span class="p">});</span>

        <span class="kd">const</span> <span class="nx">recorder</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PuppeteerScreenRecorder</span><span class="p">(</span><span class="nx">page</span><span class="p">);</span>

        <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">goto</span><span class="p">(</span><span class="dl">'</span><span class="s1">https://tailwindcss.com/</span><span class="dl">'</span><span class="p">);</span>

        <span class="k">await</span> <span class="nx">recorder</span><span class="p">.</span><span class="nx">start</span><span class="p">(</span><span class="dl">'</span><span class="s1">video.mp4</span><span class="dl">'</span><span class="p">);</span>
        <span class="k">await</span> <span class="nx">animate</span><span class="p">(</span><span class="nx">page</span><span class="p">);</span>
        <span class="k">await</span> <span class="nx">recorder</span><span class="p">.</span><span class="nx">stop</span><span class="p">();</span>
    <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span>
    <span class="p">}</span> <span class="k">finally</span> <span class="p">{</span>
        <span class="k">await</span> <span class="nx">browser</span><span class="p">.</span><span class="nx">close</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">})();</span>

<span class="kd">const</span> <span class="nx">animate</span> <span class="o">=</span> <span class="k">async</span> <span class="p">(</span><span class="nx">page</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="k">await</span> <span class="nx">wait</span><span class="p">(</span><span class="mi">500</span><span class="p">);</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">evaluate</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="p">{</span> <span class="nb">window</span><span class="p">.</span><span class="nx">scrollBy</span><span class="p">({</span> <span class="na">top</span><span class="p">:</span> <span class="mi">500</span><span class="p">,</span> <span class="na">left</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="na">behavior</span><span class="p">:</span> <span class="dl">'</span><span class="s1">smooth</span><span class="dl">'</span> <span class="p">});</span> <span class="p">});</span>
    <span class="k">await</span> <span class="nx">wait</span><span class="p">(</span><span class="mi">500</span><span class="p">);</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">evaluate</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="p">{</span> <span class="nb">window</span><span class="p">.</span><span class="nx">scrollBy</span><span class="p">({</span> <span class="na">top</span><span class="p">:</span> <span class="mi">1000</span><span class="p">,</span> <span class="na">left</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="na">behavior</span><span class="p">:</span> <span class="dl">'</span><span class="s1">smooth</span><span class="dl">'</span> <span class="p">});</span> <span class="p">});</span>
    <span class="k">await</span> <span class="nx">wait</span><span class="p">(</span><span class="mi">1000</span><span class="p">);</span>
<span class="p">};</span>

<span class="kd">const</span> <span class="nx">wait</span> <span class="o">=</span> <span class="p">(</span><span class="nx">ms</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="k">new</span> <span class="nb">Promise</span><span class="p">(</span><span class="nx">res</span> <span class="o">=&gt;</span> <span class="nx">setTimeout</span><span class="p">(</span><span class="nx">res</span><span class="p">,</span> <span class="nx">ms</span><span class="p">));</span>
</code></pre>
<div class="highlight__panel js-actions-panel">
<div class="highlight__panel-action js-fullscreen-code-action">
    <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewBox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title>
    <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path>
</svg>

    <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewBox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title>
    <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path>
</svg>

</div>
</div>
</div>



<p>I added a simple one-time scroll to make the video interactive. Look at the result, how beautiful it is:</p>

<p><div class="ff-container ff-ready ff-active"><button type="button" class="c-btn gif-button fs-s gap-2" aria-label="Pause animation playback" aria-pressed="false"><svg class="crayons-icon gif-play" width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10ZM10.622 8.415a.4.4 0 0 0-.622.332v6.506a.4.4 0 0 0 .622.332l4.879-3.252a.4.4 0 0 0 0-.666l-4.88-3.252h.001Z"></path></svg><svg class="crayons-icon gif-pause" width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10ZM9 9v6h2V9H9Zm4 0v6h2V9h-2Z"></path></svg>GIF</button>
<canvas class="ff-canvas ff-canvas-ready" width="678" height="382">
</canvas><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FdlJRy8X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://screenshotone.com/blog/how-to-record-videos-with-puppeteer/animated.gif" alt="An animated screenshot" loading="lazy" width="880" height="495" data-animated="true" id="animated-0" class="ff-image"></div></p>

<blockquote>
<p>It is not an MP4 video, but GIF for demonstration because dev.to doesn't support direct upload of videos. </p>
</blockquote>

<p>You can generate videos in AVI, MP4, MOV, or WebM formats. You can use <a href="https://caniuse.com/webm">WebM format if you target the latest versions of modern browsers, but not everyone supports it</a>.</p>

<p>If you need to generate GIF (an image format, not video) for animated screenshots, you can use the <a href="https://ffmpeg.org/">FFmpeg</a> library to convert MP4 to GIF. Make sure it is installed locally. And then you can upgrade your script to generate GIFs on demand:<br>
</p>

<div class="highlight js-code-highlight">
<pre class="highlight javascript"><code><span class="dl">'</span><span class="s1">use strict</span><span class="dl">'</span><span class="p">;</span>

<span class="kd">const</span> <span class="nx">puppeteer</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">puppeteer</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">PuppeteerScreenRecorder</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">puppeteer-screen-recorder</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">util</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">util</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">exec</span> <span class="o">=</span> <span class="nx">util</span><span class="p">.</span><span class="nx">promisify</span><span class="p">(</span><span class="nx">require</span><span class="p">(</span><span class="dl">'</span><span class="s1">child_process</span><span class="dl">'</span><span class="p">).</span><span class="nx">exec</span><span class="p">);</span>

<span class="p">(</span><span class="k">async</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="kd">const</span> <span class="nx">browser</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">puppeteer</span><span class="p">.</span><span class="nx">launch</span><span class="p">();</span>
    <span class="k">try</span> <span class="p">{</span>
        <span class="kd">const</span> <span class="nx">page</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">browser</span><span class="p">.</span><span class="nx">newPage</span><span class="p">();</span>
        <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">setViewport</span><span class="p">({</span> <span class="na">width</span><span class="p">:</span> <span class="mi">1920</span><span class="p">,</span> <span class="na">height</span><span class="p">:</span> <span class="mi">1080</span><span class="p">,</span> <span class="na">deviceScaleFactor</span><span class="p">:</span> <span class="mi">2</span> <span class="p">});</span>

        <span class="kd">const</span> <span class="nx">recorder</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">PuppeteerScreenRecorder</span><span class="p">(</span><span class="nx">page</span><span class="p">);</span>

        <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">goto</span><span class="p">(</span><span class="dl">'</span><span class="s1">https://tailwindcss.com/</span><span class="dl">'</span><span class="p">);</span>

        <span class="k">await</span> <span class="nx">recorder</span><span class="p">.</span><span class="nx">start</span><span class="p">(</span><span class="dl">'</span><span class="s1">video.mp4</span><span class="dl">'</span><span class="p">);</span>
        <span class="k">await</span> <span class="nx">animate</span><span class="p">(</span><span class="nx">page</span><span class="p">);</span>
        <span class="k">await</span> <span class="nx">recorder</span><span class="p">.</span><span class="nx">stop</span><span class="p">();</span>

        <span class="k">await</span> <span class="nx">exec</span><span class="p">(</span><span class="dl">"</span><span class="s2">ffmpeg -i video.mp4 -qscale 0 animated.gif</span><span class="dl">"</span><span class="p">);</span>
    <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span>
    <span class="p">}</span> <span class="k">finally</span> <span class="p">{</span>
        <span class="k">await</span> <span class="nx">browser</span><span class="p">.</span><span class="nx">close</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">})();</span>

<span class="kd">const</span> <span class="nx">animate</span> <span class="o">=</span> <span class="k">async</span> <span class="p">(</span><span class="nx">page</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="k">await</span> <span class="nx">wait</span><span class="p">(</span><span class="mi">500</span><span class="p">);</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">evaluate</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="p">{</span> <span class="nb">window</span><span class="p">.</span><span class="nx">scrollBy</span><span class="p">({</span> <span class="na">top</span><span class="p">:</span> <span class="mi">500</span><span class="p">,</span> <span class="na">left</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="na">behavior</span><span class="p">:</span> <span class="dl">'</span><span class="s1">smooth</span><span class="dl">'</span> <span class="p">});</span> <span class="p">});</span>
    <span class="k">await</span> <span class="nx">wait</span><span class="p">(</span><span class="mi">500</span><span class="p">);</span>
    <span class="k">await</span> <span class="nx">page</span><span class="p">.</span><span class="nx">evaluate</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="p">{</span> <span class="nb">window</span><span class="p">.</span><span class="nx">scrollBy</span><span class="p">({</span> <span class="na">top</span><span class="p">:</span> <span class="mi">1000</span><span class="p">,</span> <span class="na">left</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="na">behavior</span><span class="p">:</span> <span class="dl">'</span><span class="s1">smooth</span><span class="dl">'</span> <span class="p">});</span> <span class="p">});</span>
    <span class="k">await</span> <span class="nx">wait</span><span class="p">(</span><span class="mi">1000</span><span class="p">);</span>
<span class="p">};</span>

<span class="kd">const</span> <span class="nx">wait</span> <span class="o">=</span> <span class="p">(</span><span class="nx">ms</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="k">new</span> <span class="nb">Promise</span><span class="p">(</span><span class="nx">res</span> <span class="o">=&gt;</span> <span class="nx">setTimeout</span><span class="p">(</span><span class="nx">res</span><span class="p">,</span> <span class="nx">ms</span><span class="p">));</span>
</code></pre>
<div class="highlight__panel js-actions-panel">
<div class="highlight__panel-action js-fullscreen-code-action">
    <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewBox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title>
    <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path>
</svg>

    <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewBox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title>
    <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path>
</svg>

</div>
</div>
</div>



<p>Imagine how far you can go with animating screenshots. You can record movies and generate interactive mockups. It opens a new level of marketing for you. It is also a new level of debugging and generating reports for developers and QA automation engineers.</p>

<h2>
  <a name="use-cases" href="#use-cases">
  </a>
  Use cases
</h2>

<h3>
  <a name="improve-your-marketing-with-animated-screenshots" href="#improve-your-marketing-with-animated-screenshots">
  </a>
  Improve your marketing with animated screenshots
</h3>

<p>You can generate scrollable screenshots of the sites and apply them in many areas of your marketing:</p>

<ul>
<li>send personalized emails with animated screenshots of the lead site;</li>
<li>place screenshots of parts of your site on your landing page;</li>
<li>make your blog posts interactive with scrollable preview screenshots of the sites you share;</li>
<li>And many more.</li>
</ul>

<h3>
  <a name="debug" href="#debug">
  </a>
  Debug
</h3>

<p>In complex cases, if you run Puppetteer at production, you might want to debug what happens and record a video.</p>

<p>Imagine you scrape a site with a complex scenario by navigating through many pages. Something happens, and the script fails to scrape one of the pages.</p>

<p>Of course, the best way to debug is to reproduce the error locally, but if your environments are different, you can record a video of what happens in the script and review them.</p>

<p>But please, always synchronize your environments and ensure they are identical.</p>

<h3>
  <a name="automate-testing-reports" href="#automate-testing-reports">
  </a>
  Automate testing reports
</h3>

<p>One of the most beautiful use cases, for me, is to generate a video on how automated tests are executed and then, if the test fails, attach videos to the report.<br>
It might shorten communication time between the QA team and developers and improve the overall R&amp;D velocity.</p>
<h3>
  <a name="interactive-mockups-and-programmatic-movies" href="#interactive-mockups-and-programmatic-movies">
  </a>
  Interactive mockups and programmatic movies
</h3>

<p>You can write simple scripts to make your site interactive. Scroll through it. And record the footage with Puppeteer.</p>

<p>And even more. You can generate cartoons and movies by using JavaScript and CSS! Only your imagination is the limit.</p>
<h2>
  <a name="use-api-to-save-time-and-energy" href="#use-api-to-save-time-and-energy">
  </a>
  Use API to save time and energy
</h2>

<p>If you don't have time to implement and generate animated screenshots and deal with video streaming infrastructure, you can rely on <a href="https://screenshotone.com/">ScreenshotOne API</a>.</p>

<p>It supports <a href="https://screenshotone.com/docs/animated-screenshots/">animated (including scrollable) screenshots</a> of different types, caching based on the world's fastest and most potent CDN (Cloudflare) and blocking ads, cookie banners, and chats.</p>

<p>In just one API request, you can quickly generate animated screenshots. And if you need more, a variety of options and use cases are covered.</p>

<p>Grasp how simple it is:<br>
</p>

<div class="highlight js-code-highlight">
<pre class="highlight plaintext"><code>https://api.screenshotone.com/animate?url=https://tailwindcss.com&amp;access_key=&lt;your access key&gt;
</code></pre>
<div class="highlight__panel js-actions-panel">
<div class="highlight__panel-action js-fullscreen-code-action">
    <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewBox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title>
    <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path>
</svg>

    <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewBox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title>
    <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path>
</svg>

</div>
</div>
</div>



<p>The result might differ a bit in case default options are changed, but as for now, it is similar to what I have shown in the video.</p>

<p>And the result is the same:</p>

<p><div class="ff-container ff-ready ff-active"><button type="button" class="c-btn gif-button fs-s gap-2" aria-label="Pause animation playback" aria-pressed="false"><svg class="crayons-icon gif-play" width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10ZM10.622 8.415a.4.4 0 0 0-.622.332v6.506a.4.4 0 0 0 .622.332l4.879-3.252a.4.4 0 0 0 0-.666l-4.88-3.252h.001Z"></path></svg><svg class="crayons-icon gif-pause" width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10ZM9 9v6h2V9H9Zm4 0v6h2V9h-2Z"></path></svg>GIF</button>
<canvas class="ff-canvas ff-canvas-ready" width="678" height="382">
</canvas><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FdlJRy8X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://screenshotone.com/blog/how-to-record-videos-with-puppeteer/animated.gif" alt="An animated screenshot" loading="lazy" width="880" height="495" data-animated="true" id="animated-1" class="ff-image"></div></p>

<h2>
  <a name="summary" href="#summary">
  </a>
  Summary
</h2>

<p>Don't waste your time and jump on an opportunity. Level up your marketing and improve your R&amp;D communication.</p>


          </div>

        </div>