How to Destroy a Wavesurfer.js Instance to Free Up Memory

Destroying a Wavesurfer.js instance properly is essential to prevent memory leaks and free up browser resources when an audio visualization component unmounts or is no longer needed. To completely tear down an active instance, you must invoke the built-in destroy() method on your Wavesurfer object, clear audio buffer references, and remove any custom event listeners attached to the window or DOM.

Step 1: Call the Built-in destroy() Method

Wavesurfer.js provides a native destroy() method that handles core cleanup tasks automatically. Calling this method pauses playback, stops audio decoding, removes internally attached DOM elements (such as the canvas wave display), and detaches native event listeners created by the library.

// Initialize Wavesurfer instance
const wavesurfer = WaveSurfer.create({
  container: '#waveform',
  waveColor: '#4F46E5',
  progressColor: '#818CF8',
  url: '/path/to/audio.mp3',
});

// Tear down the instance when done
function cleanupWaveform() {
  if (wavesurfer) {
    wavesurfer.destroy();
  }
}

Step 2: Clear Custom Event Listeners and References

While wavesurfer.destroy() detaches Wavesurfer's internal listeners, any custom event listeners or external state bindings referencing the instance must be manually cleaned up. Nullifying the variable reference allows JavaScript's garbage collector to reclaim the allocated memory immediately.

// Remove custom global or DOM event listeners
window.removeEventListener('resize', handleResize);

// Nullify the variable reference for garbage collection
let wavesurferInstance = wavesurfer;
wavesurferInstance.destroy();
wavesurferInstance = null;

Step 3: Lifecycle Integration in Modern Frameworks

When using Wavesurfer.js inside component-based frameworks like React or Vue, perform the destruction within the appropriate lifecycle cleanup hook to avoid memory leaks when components unmount.

React Integration

import { useEffect, useRef } from 'react';
import WaveSurfer from 'wavesurfer.js';

function AudioPlayer({ audioUrl }) {
  const containerRef = useRef(null);
  const wavesurferRef = useRef(null);

  useEffect(() => {
    if (!containerRef.current) return;

    wavesurferRef.current = WaveSurfer.create({
      container: containerRef.current,
      url: audioUrl,
    });

    // Cleanup on unmount or URL change
    return () => {
      if (wavesurferRef.current) {
        wavesurferRef.current.destroy();
        wavesurferRef.current = null;
      }
    };
  }, [audioUrl]);

  return <div ref={containerRef} />;
}

Vue 3 Integration

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import WaveSurfer from 'wavesurfer.js';

const waveformRef = ref(null);
let wavesurfer = null;

onMounted(() => {
  wavesurfer = WaveSurfer.create({
    container: waveformRef.value,
    url: '/audio.mp3',
  });
});

onUnmounted(() => {
  if (wavesurfer) {
    wavesurfer.destroy();
    wavesurfer = null;
  }
});
</script>

<template>
  <div ref="waveformRef"></div>
</template>

By explicitly calling destroy(), unbinding custom listeners, and clearing object references, you ensure complete Web Audio API and canvas memory reclamation across all browsers.