JavaScript Navigator requestMIDIAccess() Method

Beginner
⏱️ 11 min read
📚 Updated: Jul 2026
🎯 5 Examples
🚀 5 Try-it labs
🔒 Secure context
Limited availability

What You’ll Learn

navigator.requestMIDIAccess() is the Web MIDI entry point for talking to MIDI keyboards and controllers in the browser. Learn the Promise result, inputs/outputs, sysex options, permissions, five examples, and try-it labs.

01

Kind

Method

02

Returns

Promise<MIDIAccess>

03

Status

Limited (not Baseline)

04

Context

Secure (HTTPS)

05

Options

sysex / software

06

Permission

midi

Introduction

MIDI (Musical Instrument Digital Interface) connects keyboards, pads, and synths. The Web MIDI API lets a webpage listen for notes and send MIDI messages without a native plugin.

Call navigator.requestMIDIAccess() (optionally with options). If the user allows access, you get a MIDIAccess object and can enumerate inputs and outputs.

💡
No Dep / Exp / Non-standard banner

MDN marks Limited availability and a secure context, but not Deprecated, Experimental, or Non-standard. Always feature-detect and handle permission denial.

Understanding the requestMIDIAccess() Method

  • Optional options object{ sysex, software }.
  • Promise result — fulfills with MIDIAccess.
  • Inputs / outputsMap-like collections of MIDI ports.
  • Permission — user prompt and/or midi Permissions Policy.
  • Secure context — HTTPS / localhost required where supported.
  • Hotplug — listen for statechange on MIDIAccess when devices connect/disconnect.

📝 Syntax

General forms of the method:

JavaScript
navigator.requestMIDIAccess()
navigator.requestMIDIAccess(MIDIOptions)

Parameters

  • MIDIOptions (optional) — object with:
    • sysextrue to allow System Exclusive messages (default false).
    • softwaretrue to allow software synthesizers (default false).

Return value

  • A Promise that fulfills with a MIDIAccess object.

Common exceptions / rejections

  • SecurityError — permission / policy denial.
  • NotSupportedError — feature or options not supported.
  • InvalidStateError — document closed / navigation issues.
  • AbortError — underlying system errors in some cases.

MDN-style usage

JavaScript
const access = await navigator.requestMIDIAccess();
const inputs = access.inputs.values();
const outputs = access.outputs.values();
for (const input of inputs) {
  console.log("input:", input.name);
}
for (const output of outputs) {
  console.log("output:", output.name);
}

⚡ Quick Reference

GoalCode
Feature detecttypeof navigator.requestMIDIAccess === "function"
Request accessawait navigator.requestMIDIAccess()
Allow sysexawait navigator.requestMIDIAccess({ sysex: true })
Count inputsaccess.inputs.size
Iterate portsfor (const p of access.inputs.values()) { … }
Query permissionnavigator.permissions.query({ name: "midi" })

🔍 At a Glance

Four facts to remember about navigator.requestMIDIAccess().

Returns
Promise

MIDIAccess

Status
Limited

Not Baseline

Context
HTTPS

Secure required

Ports
in / out

MIDI maps

📋 Without vs With Sysex

Default (sysex: false)With sysex: true
Typical messagesNotes, CC, program changePlus System Exclusive dumps / device setup
PermissionStandard MIDI accessOften stricter / separate sysex consideration
Beginner appsStart hereOnly when you need manufacturer sysex

Examples Gallery

Try It Yourself may prompt for MIDI permission on HTTPS. Without a connected controller you still get a valid MIDIAccess with empty (or system) port lists.

📚 Getting Started

Detect Web MIDI and request access.

Example 1 — Feature Detection

Check the method and secure context before prompting.

JavaScript
const lines = [
  "requestMIDIAccess: " +
    (typeof navigator.requestMIDIAccess === "function"
      ? "available"
      : "missing"),
  "isSecureContext: " + window.isSecureContext
];
console.log(lines.join("\n"));
Try It Yourself

How It Works

If either check fails, show a non-MIDI fallback (virtual keyboard UI).

Example 2 — Request Access & Count Ports (MDN)

Resolve MIDIAccess and report how many inputs and outputs exist.

JavaScript
async function countMidiPorts() {
  if (typeof navigator.requestMIDIAccess !== "function") {
    return "Web MIDI not supported";
  }
  try {
    const access = await navigator.requestMIDIAccess();
    return JSON.stringify({
      inputs: access.inputs.size,
      outputs: access.outputs.size,
      sysexEnabled: access.sysexEnabled
    });
  } catch (err) {
    return "Error: " + err.name;
  }
}

countMidiPorts().then(console.log);
Try It Yourself

How It Works

Empty counts are normal on a laptop without a MIDI controller plugged in.

📈 Practical Patterns

List port names, query permission, and wrap errors safely.

Example 3 — List Input / Output Names

Iterate inputs.values() and outputs.values() like the MDN sample.

JavaScript
async function listMidiPorts() {
  const access = await navigator.requestMIDIAccess();
  const inputNames = [];
  const outputNames = [];
  for (const input of access.inputs.values()) {
    inputNames.push(input.name || "(unnamed input)");
  }
  for (const output of access.outputs.values()) {
    outputNames.push(output.name || "(unnamed output)");
  }
  return JSON.stringify({ inputNames, outputNames });
}

listMidiPorts().then(console.log).catch((err) => {
  console.log("Error: " + err.name);
});
Try It Yourself

How It Works

Attach midimessage listeners on inputs once you know which port to use.

Example 4 — Query midi Permission

Check permission state when the Permissions API supports midi.

JavaScript
async function queryMidiPermission() {
  if (!navigator.permissions || !navigator.permissions.query) {
    return "Permissions API missing";
  }
  try {
    const result = await navigator.permissions.query({ name: "midi", sysex: false });
    return "midi permission: " + result.state;
  } catch (err) {
    return "Error: " + err.name + " (midi permission may be unsupported here)";
  }
}

queryMidiPermission().then(console.log);
Try It Yourself

How It Works

Use this to decide whether to show a “Enable MIDI” button before calling the API.

Example 5 — Safe Access Helper

Feature-detect, request on a user gesture path, and return structured errors.

JavaScript
async function requestMidiAccessSafe(options) {
  if (typeof navigator.requestMIDIAccess !== "function") {
    return { ok: false, access: null, reason: "unsupported" };
  }
  if (!window.isSecureContext) {
    return { ok: false, access: null, reason: "insecure-context" };
  }
  try {
    const access = await navigator.requestMIDIAccess(options || {});
    return {
      ok: true,
      access: access,
      reason: "ok",
      inputs: access.inputs.size,
      outputs: access.outputs.size
    };
  } catch (err) {
    return { ok: false, access: null, reason: err.name };
  }
}

requestMidiAccessSafe({ sysex: false }).then((result) => {
  console.log(JSON.stringify({
    ok: result.ok,
    reason: result.reason,
    inputs: result.inputs || 0,
    outputs: result.outputs || 0
  }));
});
Try It Yourself

How It Works

Prefer calling this from a button click so the permission prompt feels intentional.

🚀 Common Use Cases

  • Browser synths — play Web Audio oscillators from a MIDI keyboard.
  • DAW-lite tools — map pads and knobs to on-page controls.
  • Education — teach note numbers, velocity, and CC messages visually.
  • Controller apps — send program changes / notes to hardware outputs.
  • Live visuals — drive animations from MIDI beat / note events.

🧠 How requestMIDIAccess() Works

1

Call on HTTPS

Optionally pass { sysex, software }.

Request
2

User / policy gate

Permission prompt or previous choice; policy may deny.

Permission
3

Receive MIDIAccess

Inspect inputs and outputs maps.

Access
4

Listen or send

Handle midimessage or output.send([...]).

📝 Notes

  • Limited availability (not Baseline) — feature-detect always.
  • Not Deprecated, Experimental, or Non-standard — no status banner required.
  • Requires a secure context; gated by midi permission / policy.
  • Prefer a user gesture before the first request.
  • Related: sendBeacon(), requestMediaKeySystemAccess(), getGamepads(), Window.

Limited Browser Support

navigator.requestMIDIAccess() is part of the Web MIDI API and is not Baseline. Support is strongest in Chromium-based browsers on HTTPS. Always feature-detect, request permission intentionally, and provide a virtual-keyboard fallback.

Limited · Not Baseline

Navigator.requestMIDIAccess()

Promise → MIDIAccess for MIDI inputs and outputs.

Limited Not Baseline
Google Chrome Web MIDI on HTTPS with permission
Supported
Microsoft Edge Follow Chromium Web MIDI support
Supported
Opera Follow Chromium where available
Supported
Mozilla Firefox Check current compatibility — feature-detect
Limited
Apple Safari Typically unavailable — feature-detect
Unavailable
Internet Explorer No Web MIDI requestMIDIAccess
Unavailable
requestMIDIAccess() Limited

Bottom line: Detect the method on a secure page, request access from a button click, list inputs/outputs, and catch SecurityError when permission is denied.

Conclusion

navigator.requestMIDIAccess() opens the Web MIDI API. Request it on HTTPS, handle permission carefully, then enumerate inputs and outputs to build interactive music tools — with a non-MIDI fallback when the API is missing.

Continue with sendBeacon(), getGamepads(), or the JavaScript hub.

💡 Best Practices

✅ Do

  • Feature-detect before requesting
  • Call from a clear user gesture
  • Start with sysex: false unless needed
  • Listen for statechange when devices plug in
  • Provide an on-screen keyboard fallback

❌ Don’t

  • Assume Baseline support in every browser
  • Request sysex without explaining why
  • Ignore SecurityError denials
  • Assume ports exist without checking size
  • Spam permission prompts on load

Key Takeaways

Knowledge Unlocked

Five things to remember about requestMIDIAccess()

Limited Web MIDI entry point — request access, then use inputs and outputs.

5
Core concepts
📊 02

Support

Limited

Not Baseline
🔒 03

Needs

HTTPS + permission

midi
🔀 04

Ports

inputs / outputs

Maps
05

Option

sysex

Opt-in

❓ Frequently Asked Questions

It asks the browser for access to MIDI devices (keyboards, controllers, synthesizers). If permission is granted, the Promise resolves to a MIDIAccess object with inputs and outputs maps.
No. MDN does not mark it Deprecated, Experimental, or Non-standard. It is Limited availability (not Baseline) and requires a secure context. No status banner is required.
If MIDIOptions.sysex is true, the app may send and receive System Exclusive messages. The default is false. Sysex often needs extra permission scrutiny.
Usually yes on first use (or the browser reuses a previous choice). Access can also be blocked by the midi Permissions Policy.
After access resolves, iterate access.inputs.values() and access.outputs.values() to read MIDIInput / MIDIOutput ports (name, manufacturer, state, and more).
Often yes via navigator.permissions.query({ name: "midi", sysex: true|false }) when the Permissions API supports the midi permission in that browser.
Did you know?

MIDI messages are tiny binary packets (often three bytes for a note-on). Web MIDI delivers them as Uint8Array data on midimessage events — perfect for pairing with the Web Audio API.

Explore sendBeacon() Next

Send reliable analytics on page hide without slowing navigation.

sendBeacon() →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

8 people found this page helpful