Skip to content

API in Capabilities

Web MIDI API

Published

The Web MIDI API gives a page access to MIDI input and output ports after permission is granted. navigator.requestMIDIAccess() returns a promise for a MIDIAccess object, whose inputs and outputs collections contain the available ports.

BCD records requestMIDIAccess() from Chrome 43 and Firefox 108 on desktop. Its Firefox entry requires a site-permission add-on; Firefox for Android and Safari are recorded as unsupported (BCD api.Navigator.requestMIDIAccess).

navigator.requestMIDIAccess()
navigator.requestMIDIAccess(options)

The method is exposed in secure contexts. It may prompt for permission or apply a previously stored choice, and its fulfilled promise contains a MIDIAccess object.

The optional options object controls access beyond ordinary hardware MIDI ports.

Member Type Default Meaning
sysex boolean false Request permission to send and receive system-exclusive messages.
software boolean false Request access to installed software synthesizers.

MIDIAccess.inputs and MIDIAccess.outputs are read-only maps of MIDIInput and MIDIOutput ports. Its statechange event reports a port connection or state change.

The returned promise can reject with these DOMException names, as documented for requestMIDIAccess() (MDN).

Exception Condition
AbortError Navigation closes the document or page.
InvalidStateError The underlying MIDI system reports an error.
NotSupportedError The system does not support the requested feature or options.
NotAllowedError The user or system denies access, or Permissions Policy does not allow it.

Check for the method before requesting access. Keep a non-MIDI control available when the method is absent or the request fails.

This snippet creates a MIDI button, status text, and an on-screen keyboard. The note buttons remain available without MIDI access.

const midiButton = document.body.appendChild(document.createElement("button"));
const status = document.body.appendChild(document.createElement("p"));
const keyboard = document.body.appendChild(document.createElement("div"));
midiButton.textContent = "Connect MIDI";
keyboard.setAttribute("role", "group");
keyboard.setAttribute("aria-label", "On-screen keyboard");
for (const note of ["C4", "D4", "E4", "F4", "G4"]) {
const key = keyboard.appendChild(document.createElement("button"));
key.textContent = note;
key.addEventListener("click", () => {
status.textContent = `On-screen note: ${note}`;
});
}
if (!("requestMIDIAccess" in navigator)) {
midiButton.disabled = true;
status.textContent = "MIDI is unavailable. Use the on-screen keyboard.";
} else {
midiButton.addEventListener("click", async () => {
midiButton.disabled = true;
try {
const access = await navigator.requestMIDIAccess();
status.textContent = `MIDI inputs: ${access.inputs.size}`;
} catch (error) {
status.textContent = `MIDI access failed: ${error.name}. Use the on-screen keyboard.`;
}
});
}

The unsupported and rejected paths both leave the note buttons enabled and disable the MIDI button.

After permission is granted, attach a listener to each input in the returned map. The event’s data value contains the MIDI message bytes.

async function listenForMidi(onMessage) {
if (!("requestMIDIAccess" in navigator)) return false;
const access = await navigator.requestMIDIAccess();
for (const input of access.inputs.values()) {
input.addEventListener("midimessage", (event) => onMessage(event.data));
}
return true;
}
listenForMidi((bytes) => console.log(Array.from(bytes))).catch(console.error);

The function returns false when the API is absent; callers can use that value to enable an on-screen instrument.

Specifications

SpecificationStatus
Web MIDI API: requestMIDIAccess()Community draft