<?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: Convertola</title>
    <description>The latest articles on DEV Community by Convertola (@convertola).</description>
    <link>https://dev.to/convertola</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%2F4198656%2Fc2c9bee6-d85c-4c6d-a40e-148d1e9984a0.png</url>
      <title>DEV Community: Convertola</title>
      <link>https://dev.to/convertola</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/convertola"/>
    <language>en</language>
    <item>
      <title>Converting video and audio to MP3 in the browser with ffmpeg.wasm: notes from building one</title>
      <dc:creator>Convertola</dc:creator>
      <pubDate>Wed, 21 Oct 2026 15:03:18 +0000</pubDate>
      <link>https://dev.to/convertola/converting-video-and-audio-to-mp3-in-the-browser-with-ffmpegwasm-notes-from-building-one-397l</link>
      <guid>https://dev.to/convertola/converting-video-and-audio-to-mp3-in-the-browser-with-ffmpegwasm-notes-from-building-one-397l</guid>
      <description>&lt;p&gt;Most "convert to MP3" websites follow the same pattern: you upload a file, a server runs FFmpeg on it, and you download the result. That works, but it means every recording, voice note or home video takes a trip to someone else's machine. While building Convertola (disclosure: it's our project), we went the other way and ran FFmpeg inside the browser with WebAssembly. Here are the parts that turned out to matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Pick the single-threaded core unless you really need threads
&lt;/h2&gt;

&lt;p&gt;ffmpeg.wasm ships a single-threaded core and a multi-threaded one. The multi-threaded build depends on &lt;code&gt;SharedArrayBuffer&lt;/code&gt;, which browsers only expose on cross-origin isolated pages. That means serving &lt;code&gt;Cross-Origin-Opener-Policy: same-origin&lt;/code&gt; and &lt;code&gt;Cross-Origin-Embedder-Policy: require-corp&lt;/code&gt;, and those headers can break third-party embeds, fonts or analytics that aren't served with the right CORP/CORS headers.&lt;/p&gt;

&lt;p&gt;For audio-only jobs the single-threaded core is usually fast enough, and it runs on a plain page with no special headers. We chose it and haven't regretted it.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Load the engine lazily
&lt;/h2&gt;

&lt;p&gt;The core &lt;code&gt;.wasm&lt;/code&gt; file is several megabytes. Loading it on page load slows down everyone, including visitors who only came to read. Load it when the user actually picks a file (or hovers the upload area), and show a clear "preparing converter" state so the first conversion doesn't look frozen.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. The FFmpeg command is the easy part
&lt;/h2&gt;

&lt;p&gt;Once a file is written to ffmpeg.wasm's in-memory file system, the conversion is the same command you'd run on a desktop:&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;-i&lt;/span&gt; input.mp4 &lt;span class="nt"&gt;-vn&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;:a libmp3lame &lt;span class="nt"&gt;-b&lt;/span&gt;:a 192k output.mp3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-vn&lt;/code&gt; drops the video stream, so a video becomes an audio-only MP3.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-c:a libmp3lame&lt;/code&gt; selects the MP3 encoder.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-b:a&lt;/code&gt; sets the bitrate. Offering a small set of choices (128, 192, 256, 320 kbps) is friendlier than a free-form field.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One gotcha: files with several audio tracks (common in MKV) will use FFmpeg's default stream selection. If you want predictable behaviour, map the first audio track explicitly with &lt;code&gt;-map 0:a:0&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Memory is your real limit
&lt;/h2&gt;

&lt;p&gt;Everything lives in the tab's memory: the input file, FFmpeg's working buffers and the output. Large inputs can crash a tab, especially on phones. Set an honest file-size cap, check &lt;code&gt;file.size&lt;/code&gt; before writing anything to the virtual file system, and delete files from it (&lt;code&gt;deleteFile&lt;/code&gt;) after each job so repeated conversions don't pile up.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Progress and cancel matter more than raw speed
&lt;/h2&gt;

&lt;p&gt;Users tolerate a conversion that takes a while if they can see it moving. ffmpeg.wasm emits progress events you can bind to a progress bar. Equally important is a working Cancel button: terminating the instance and reloading it is simpler and more reliable than trying to stop a running job halfway.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Be upfront about licensing
&lt;/h2&gt;

&lt;p&gt;FFmpeg and its builds carry GPL/LGPL obligations depending on how they're compiled. Credit FFmpeg and ffmpeg.wasm on the page, state the license of the core you ship, and link to the source.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. The privacy story is the product
&lt;/h2&gt;

&lt;p&gt;The biggest benefit isn't technical. When the file never leaves the device, there's nothing to delete later and nothing to explain in a retention policy. That's an easy promise to keep, and an easy one for users to understand.&lt;/p&gt;

&lt;p&gt;If you want to see how this feels in practice, &lt;a href="https://convertola.com/mp3-converter" rel="noopener noreferrer"&gt;Convertola's free MP3 converter&lt;/a&gt; is built exactly this way: pick a video or audio file, choose a bitrate, and the MP3 is created on your own device.&lt;/p&gt;

&lt;p&gt;Have you shipped ffmpeg.wasm in production? I'd be curious how others handle large files on mobile.&lt;/p&gt;

</description>
      <category>webassembly</category>
      <category>javascript</category>
      <category>ffmpeg</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
