Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
For a browser audio element, use canplay to detect when the browser believes playback can begin. That does not mean the entire file has downloaded. Use loadedmetadata for details such as duration, canplaythrough for the browser’s estimate that playback can continue to the end, and fetch() when you specifically need to consume the full response.
Choose the signal that matches what “loaded” means
Audio loading is not a single state. A browser can know a track’s duration before it has enough audio data to play, and it can begin playback before the complete file has arrived. The media events and readyState property describe these different stages. Their timing can vary with caching, network conditions, streaming, and browser settings. See MDN’s HTMLMediaElement reference.
| If you need to know… | Use | What it means |
|---|---|---|
| Whether loading has begun | loadstart |
The browser started loading; usable audio is not guaranteed. |
| Whether duration or other metadata is available | loadedmetadata |
Metadata is available, but playback may not yet be possible. |
| Whether initial media data is available | loadeddata |
Data for the current position is available. This event may not fire on some mobile devices in data-saving mode. |
| Whether playback can start | canplay |
The browser estimates it can begin playback, though more data may be needed later. |
| Whether playback can probably continue to the end without buffering | canplaythrough |
The browser estimates enough data is available. This is not proof that every byte has downloaded. |
| Whether a load failed | error |
The resource could not be loaded; inspect audio.error for the media error. |
For most players, canplay is the useful signal for enabling a Play button. For the event definitions, see MDN on canplay, canplaythrough, and loadeddata.
A robust pattern for a dynamically created audio element
Register listeners before assigning the source. This avoids application-level timing problems if a cached or very small file becomes ready quickly. Handle failure as well as success:
#1 Best Overall
- Pro performance with great pre-amps - Achieve a brighter recording thanks to the high performing mic pre-amps of the Scarlett 3rd Gen. A switchable Air mode will add extra clarity to your acoustic instruments when recording with your Solo 3rd Gen
- Get the perfect guitar and vocal take with - With two high-headroom instrument inputs to plug in your guitar or bass so that they shine through. Capture your voice and instruments without any unwanted clipping or distortion thanks to our Gain Halos
- Studio quality recording for your music & podcasts - Achieve pro sounding recordings with Scarlett 3rd Gen’s high-performance converters enabling you to record and mix at up to 24-bit/192kHz. Your recordings will retain all of their sonic qualities
- Low-noise for crystal clear listening - 2 low-noise balanced outputs provide clean audio playback with 3rd Gen. Hear all the nuances of your tracks or music from Spotify, Apple & Amazon Music. Plug-in headphones for private listening in high-fidelity
- Everything in the box: Includes Pro Tools Intro+, Ableton Live Lite, Cubase LE, and Hitmaker Expansion: a suite of essential effects, powerful software instruments, and easy-to-use mastering tools
function loadAudio(url) {
return new Promise((resolve, reject) => {
const audio = new Audio();
audio.preload = "auto";
const cleanup = () => {
audio.removeEventListener("canplay", onReady);
audio.removeEventListener("error", onError);
};
const onReady = () => {
cleanup();
resolve(audio);
};
const onError = () => {
cleanup();
reject(audio.error ?? new Error(`Unable to load ${url}`));
};
audio.addEventListener("canplay", onReady, { once: true });
audio.addEventListener("error", onError, { once: true });
audio.src = url;
audio.load();
});
}
loadAudio("/audio/effect.mp3")
.then((audio) => {
console.log("Ready to start");
return audio.play();
})
.catch((error) => {
console.error("Audio loading or playback failed:", error);
});
Readiness and permission to play are separate. A browser can allow the file to load but reject script-initiated playback under its autoplay rules. The promise returned by play() should therefore be handled; a NotAllowedError commonly means user interaction is needed. See MDN’s HTMLMediaElement documentation.
Using an audio element already in the page
If you need the duration for a timeline or track label, wait for loadedmetadata. Enable playback on canplay instead:
Rank #2
- The new generation of the songwriter's interface: Plug in your mic and guitar and let Scarlett Solo 4th Gen bring big studio sound to wherever you make music
- Studio-quality sound: With a huge 120dB dynamic range, the newest generation of Scarlett uses the same converters as Focusrite’s flagship interfaces, found in the world's biggest studios
- Find your signature sound: Scarlett 4th Gen's improved Air mode lifts vocals and guitars to the front of the mix, adding musical presence and rich harmonic drive to your recordings
- All you need to record, mix and master your music: Includes industry-leading recording software and a full collection of record-making plugins
- Everything in the box: Includes Pro Tools Intro+, Ableton Live Lite, Cubase LE, and Hitmaker Expansion: a suite of essential effects, powerful software instruments, and easy-to-use mastering tools
<audio id="player" preload="metadata">
<source src="/audio/theme.mp3" type="audio/mpeg">
</audio>
<button id="play" disabled>Play</button>
<script>
const player = document.querySelector("#player");
const playButton = document.querySelector("#play");
player.addEventListener("loadedmetadata", () => {
console.log(`Duration: ${player.duration} seconds`);
});
player.addEventListener("canplay", () => {
playButton.disabled = false;
});
player.addEventListener("error", () => {
console.error("Media error:", player.error?.code, player.error?.message);
});
</script>
preload="metadata" suits a page that needs media details but does not want to request the entire file eagerly. preload="auto" expresses a preference to preload more, while preload="none" asks the browser not to preload. These are hints, not guarantees that the browser will download a particular amount. See MDN on the preload property.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Creating the element directly
You can also create an element explicitly and set listeners before its source:
Rank #3
- PLUG IN AND HEAR SOUND IN SECONDS - USB Type-A connector with a 3.5mm stereo headphone output and a separate 3.5mm mono microphone input. No drivers, no software, no external power - the adapter is USB bus-powered and is recognized as a standard USB audio device.
- WORKS ON WINDOWS, MAC AND LINUX - Driverless on Windows 98SE/ME/2000/XP/Server 2003/Vista/7/8, Linux and Mac OSX, and compliant with the USB Audio Device Class 1.0 specification, so any system that supports class-compliant USB audio will see it. Select it as the sound output and input device after plugging it in.
- TWO JACKS, TWO JOBS - The green jack is stereo OUT for headphones or powered speakers; the pink jack is mono microphone IN for a 3.5mm mic. It does NOT support 4-pole headsets on a single combo plug, it does NOT power passive speakers, and it does NOT add surround sound - it is a stereo 2-channel adapter.
- FOR LAPTOPS AND DESKTOPS THAT NEED AN AUDIO PORT BACK - Adds a headphone and mic port to a laptop, desktop, or mini PC whose onboard jack has failed or was never there. Managed and work-issued computers can block new USB audio devices by policy - check with your IT department before ordering for a company machine.
- SABRENT SUPPORT AND WARRANTY - What is in the box: one USB audio sound adapter. Backed by a 1-year limited warranty, extended to 2 years when you register within 90 days on the manufacturer's website.
const audio = document.createElement("audio");
audio.preload = "auto";
audio.addEventListener("canplay", () => console.log("Ready"), { once: true });
audio.addEventListener("error", () => console.error("Load failed", audio.error), { once: true });
audio.src = "/audio/menu-click.mp3";
audio.load();
new Audio(url) is shorter, but passing a URL starts loading asynchronously, so attach listeners promptly. For maximum control, construct without a URL, set preload, add listeners, then assign src. The constructor creates an HTMLAudioElement; see MDN’s Audio() reference. Calling load() resets source selection and starts loading; if called during an active load, it interrupts that operation. Use it when changing a source, not as a routine extra call. See MDN on load().
Check the current state with readyState
If loading may already have started before your code runs, check the current value rather than waiting only for a future event:
Rank #4
- Podcast, Record, Live Stream, This Portable Audio Interface Covers it All - USB sound card for Mac or PC delivers 48kHz audio resolution for pristine recording every time
- Be ready for anything with this versatile M-AUDIO interface - Record guitar, vocals or line input signals with two combo XLR / Line / Instrument Inputs with phantom power
- Everything you Demand from an Audio Interface for Fuss-Free Monitoring - 1/4" headphone output and stereo 1/4" outputs for total monitoring flexibility; USB/Direct switch for zero latency monitoring
- Get the best out of your Microphones - M-Track Duo’s transparent Crystal Preamps guarantee optimal sound from all your microphones including condenser mics
- The MPC Production Experience - Includes MPC Beats Software complete with the essential production tools from Akai Professional
if (audio.readyState >= HTMLMediaElement.HAVE_FUTURE_DATA) {
console.log("Enough data is available to begin playback");
}
| Constant | Value | Meaning |
|---|---|---|
HAVE_NOTHING |
0 | No usable media information is available. |
HAVE_METADATA |
1 | Metadata is available. |
HAVE_CURRENT_DATA |
2 | Data is available for the current playback position. |
HAVE_FUTURE_DATA |
3 | Enough data exists to begin playback and continue briefly. |
HAVE_ENOUGH_DATA |
4 | The browser estimates it can play through without interruption. |
Use HAVE_FUTURE_DATA as the practical threshold for “ready to start”; HAVE_ENOUGH_DATA is the stronger browser estimate, not a guarantee. The state can change as playback and network conditions change. See MDN’s readyState reference.
Recommended Free Tools
If you truly need the entire response downloaded
Neither canplay nor canplaythrough proves byte-for-byte completion. If the app must process or retain the whole response—for example, for a short sound effect that it will hash or decode—fetch it and consume the body:
Best Value
- The new generation of the artist's interface: Connect your mic to Scarlett's 4th Gen mic pres. Plug in your guitar. Fire up the included software. Start making your first big hit
- Studio-quality sound: With a huge 120dB dynamic range, the newest generation of Scarlett uses the same converters as Focusrite’s flagship interfaces, found in the world's biggest studios
- Never lose a great take: Scarlett 4th Gen's Auto Gain sets the perfect level for your mic or guitar, and Clip Safe prevents clipping, so you can focus on the music
- Find your signature sound: Air mode lifts vocals and guitars to the front of the mix, adding musical presence and rich harmonic drive to your recordings
- With Scarlett 4th Gen, you have all you need to record, mix and master your music: Includes industry-leading recording software and a full collection of record-making plugins
async function fetchAudioCompletely(url) {
const response = await fetch(url);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.arrayBuffer();
}
const bytes = await fetchAudioCompletely("/audio/effect.mp3");
const blobUrl = URL.createObjectURL(new Blob([bytes], { type: "audio/mpeg" }));
const audio = new Audio(blobUrl);
await new Promise((resolve, reject) => {
audio.addEventListener("canplay", resolve, { once: true });
audio.addEventListener("error", () => reject(audio.error), { once: true });
});
Consuming arrayBuffer() means the fetch response body has been read to completion; the subsequent canplay confirms the media element can start playback. This approach holds the response in memory, which grows with file size, and cross-origin requests require suitable CORS permission. It is generally a poor fit for long tracks or streaming playback. If you need decoded samples for Web Audio rather than an audio element, pass the bytes to AudioContext.decodeAudioData(); successful decoding is a different condition from media-element readiness.
Preloading several effects
For a small set of game or interface sounds, resolve each promise only when that sound reaches the readiness level your app needs, and reject failures instead of leaving a loading screen waiting forever:
function preloadAudio(urls) {
return Promise.all(urls.map((url) => new Promise((resolve, reject) => {
const audio = new Audio();
audio.preload = "auto";
const cleanup = () => {
audio.removeEventListener("canplay", onReady);
audio.removeEventListener("error", onError);
};
const onReady = () => { cleanup(); resolve(audio); };
const onError = () => { cleanup(); reject(new Error(`Failed to load ${url}`)); };
audio.addEventListener("canplay", onReady, { once: true });
audio.addEventListener("error", onError, { once: true });
audio.src = url;
})));
}
preloadAudio(["/audio/click.mp3", "/audio/explosion.ogg", "/audio/jump.wav"])
.then((sounds) => console.log(`${sounds.length} sounds are ready`))
.catch(console.error);
Promise.all() rejects as soon as any one load fails. If the interface should keep usable sounds and report individual failures, catch per-file errors and collect results instead. For a visible progress count, increment once per settled file, whether it loaded or failed. Many preloaded elements can consume bandwidth and memory; avoid eagerly loading a large library, and provide cancellation or cleanup when a component is removed.
Troubleshooting when readiness never arrives
- Check the URL and response: a typo, 404, redirect, or authentication failure can prevent loading. Inspect the browser Network panel.
- Check format and encoding: the browser may not support the codec, or the file may be malformed. With multiple
<source>options, listen for the final error on the audio element; it fires after all source choices fail. See MDN’s audio element reference. - Check server headers and cross-origin access: a wrong MIME type can cause problems, and cross-origin access restrictions matter especially when using
fetch(). Verify the server’s response and CORS configuration. - Inspect the element: log
currentSrc,readyState,networkState,duration, anderrorto see what source was selected and what state it reached. - Do not wait on the wrong event:
loadedmetadatadoes not mean playable;loadeddatacan be absent under some mobile data-saving settings. Prefercanplayfor starting playback. - Check whether your code restarted loading: changing
srcor callingload()can abort the current operation and begin another. - Separate loading from playback: if
canplayfired butplay()rejects, inspect the rejected promise; autoplay restrictions are not load errors.
console.log({
currentSrc: audio.currentSrc,
readyState: audio.readyState,
networkState: audio.networkState,
duration: audio.duration,
error: audio.error
});
The browser’s usual event flow includes loadstart, loadedmetadata, loadeddata, progress, canplay, and possibly canplaythrough, but do not depend on every event arriving in one fixed sequence. Cached resources, interruptions, and browser policies affect the timing. See MDN’s cross-browser audio guide.
Quick Recap
Quick decision guide
- Need duration? Wait for
loadedmetadata. - Need to enable Play? Wait for
canplay, or check forHAVE_FUTURE_DATA. - Want the browser’s best estimate of uninterrupted playback? Use
canplaythrough, but do not treat it as a full-download guarantee. - Need the complete response body for processing? Use
fetch()and consume it, accounting for CORS and memory. - Need to know whether loading failed? Listen for
errorand inspectaudio.error.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

