# WebMIDI.js publishes three build formats and keeps its API reference off the repository

> webmidi is an Apache-2.0 JavaScript library that wraps the browser Web MIDI API and a Node.js equivalent with named functions like playNote() and sendPitchBend(), plus event listeners for noteon and pitchbend. It is a good fit for browser MIDI applications, and a poor fit if you need the documentation to live in the repository you depend on.

**djipco/webmidi** — Tame the Web MIDI API. Send and receive MIDI messages with ease. Control instruments with user-friendly functions (playNote, sendPitchBend, etc.). React to MIDI input with simple event listeners (noteon, pitchbend, controlchange, etc.).

- Repository: https://github.com/djipco/webmidi
- Stars: 1,721 · Forks: 130
- Language: JavaScript
- License: Apache-2.0
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/djipco-webmidi

## A wrapper over a byte protocol, not a MIDI implementation

MIDI at the hardware level is a stream of status bytes and data bytes on a channel. The Web MIDI API in the browser already exposes ports, sending and receiving messages. What webmidi does is put a vocabulary on top of it.

The README names the functions the library adds: `playNote()`, `sendPitchBend()`, `sendControlChange()`. On the receive side it replaces raw callbacks with named events you can listen for, `noteon`, `pitchbend` and `programchange`, and the package description in package.json adds `songposition` to that list.

That is the whole design in one sentence. Instead of building a status byte and filling two data fields, you call a named function; instead of switching on a status nibble, you attach a listener. Both are real reductions in boilerplate for anyone who has written MIDI parsing by hand.

What the library does not do is change the protocol underneath. Anything about device behaviour, port enumeration or driver quirks belongs to the browser's Web MIDI implementation, and this layer cannot paper over it. The repository topics list `sysex` and `midi-messages` alongside `web-midi-api`, so System Exclusive is in scope, but the README does not describe how it is handled.

## Browser and Node.js from one package, with two entry formats

The package is named `webmidi` and describes itself as making it easy to talk to MIDI instruments from a browser or from Node.js. The repository is JavaScript with a typescript/ directory and .d.ts files in the published output.

The exports map in package.json shows the packaging clearly:

```json
"exports": {
  ".": {
    "require": {
      "types": "./dist/cjs/webmidi.cjs.d.ts",
      "default": "./dist/cjs/webmidi.cjs.min.js"
    },
    "import": {
      "types": "./dist/esm/webmidi.esm.d.ts",
      "default": "./dist/esm/webmidi.esm.js"
    }
  }
}
```

A CommonJS require gets a minified .cjs build, an ES import gets the unminified .esm build, and each has its own declaration file. `main` points at the minified CommonJS file and `types` at its declaration file, so older resolvers still work.

The build scripts go further. `library:build-all` chains lint, then three separate builds named for the three output formats, CJS, ESM and an IIFE build. The IIFE target is the one that matters for a plain script tag on a page with no bundler. All three come from the same source, so a behavioural difference between them would be a build bug rather than a design decision.

## Getting started means leaving the repository

The README is short and largely a set of pointers. It directs readers to webmidijs.org as the best place to get started, and names two resources there: documentation at webmidijs.org/docs/ and the API reference at webmidijs.org/api/.

There is no install command in the README and no getting-started code sample in it either. The package name, `webmidi`, is established by the npm and jsDelivr badges in the README header and by the name field in package.json, which is what you would pass to your package manager, but the README itself does not spell out the installation step.

For a quick orientation, the repository does ship an examples/ directory with named subdirectories: quick-start, react, next.js, typescript, p5.js and electron. That list is the most useful structural hint in the whole repository, because it maps the frameworks the author expects people to use the library with. An Electron example alongside the browser examples is a reminder that the Node.js path exists for desktop and server-side use, not just for tests.

If you want the API surface, the documentation site is where it is. The repository's own README will not get you a first message sent.

## Release cadence and the Node.js version floor

The repository is not archived. The last push was on 2026-10-12, and the release history is dense: v3.3.0 on 2026-09-14, v3.3.1 on 2026-09-15, and v3.1.16 on 2026-03-31 before that. The two releases a day apart in September suggest patch-level fixes landing quickly after a minor.

The package declares `node` `>=8.5` in its engines field. That floor is old enough to be worth noting rather than repeating, since it tells you the library avoids modern Node-only APIs in its own code, but the surrounding toolchain in devDependencies is not visible in what is shown here. The practical question for a modern project is not the floor but whether your bundler resolves the exports map correctly.

Only `/dist` is published, since the files array contains just that entry. Source maps, tests and examples stay in the repository. That keeps installs small and means debugging lands you in minified output unless you work from the repository.

The build is Babel-based, with .babelrc and .eslintrc.cjs at the root, and coverage is configured through .nycrc.

## Where the library does not help

The first limitation is structural. Everything is delegated to the Web MIDI implementation the browser ships, so the set of devices you can reach, the timing of incoming messages and the handling of System Exclusive are all outside this library's control. If a specific controller misbehaves, the debugging starts in the browser and the operating system, not in webmidi.

The second is that the convenience stops at your code. `playNote()` names the operation, but a musical application still has to manage channel allocation, voice allocation across a polyphonic device, and what happens when a note is never released because the page reloaded mid-press. Those are application concerns the library is not claiming to solve.

The third is documentation locality. There is no specification in this repository, and the README's API reference link points off-site. If your team needs the reference to be versioned alongside the code or available offline, that is a real gap, and it applies to a library you would otherwise be happy with.

The fourth is that a browser MIDI application needs a secure context and explicit user permission. The README does not discuss that at all, and it is the first thing that determines whether your page works when you try it.

## Against talking to the Web MIDI API directly

The Web MIDI API is a browser built-in. Using it directly means calling `navigator.requestMIDIAccess()`, iterating over `inputs` and `outputs`, and writing the byte assembly yourself. For a proof of concept that reads a controller value and moves something on screen, that is often the right amount of code.

What direct use costs is the layer you would otherwise maintain. Every message type becomes a case in a switch, every convenience becomes a helper you write, and any application that grows past one instrument ends up with the same abstraction webmidi already provides. The test is whether you expect more than one screen or one device. One device and one message type argues for the raw API.

A second alternative is a native toolchain. Writing a plugin in a DAW or a desktop MIDI application gives you tighter timing and no browser permission model, at the cost of leaving the web entirely. For an installation that runs full time, that is often the better engineering choice; for something a user opens in a browser, it is not available.

WebMIDI.js is the middle path: web delivery, named functions instead of byte handling. The cost of that middle position is the off-site documentation and the reliance on the browser's implementation.

## Apache-2.0, one maintainer, sponsorship

The licence is Apache-2.0, declared in package.json and with LICENSE.txt at the repository root, plus a SECURITY.md for reporting issues. Apache-2.0 is permissive and includes an explicit patent grant, which for a library embedded in commercial products is a meaningful difference from a bare MIT grant. This is a licensing note and not legal advice.

The governance is thinner. The author field names a single person, Jean-Philippe Cô, and the README describes the project as a passion project that still takes time, effort and money, with a sponsors section and a GitHub Sponsors link. That framing is honest and also tells you something about concentration of decisions: the repository has CODE_OF_CONDUCT.md and CONTRIBUTING.md, but the direction is one person's.

The feature request process is documented and unusual enough to note. The README asks you to check a planned enhancements page at webmidijs.org/docs/future-versions/next first, then discuss in a dedicated Enhancement Proposals category on GitHub Discussions. Requests are therefore filtered through a published roadmap rather than an open issue pile, which suits a single maintainer and means you should read the roadmap before spending time on a proposal.

## Conclusion

Use webmidi if you are writing a browser application that talks to MIDI hardware and you want named helpers and typed event listeners instead of assembling status bytes yourself. Do not adopt it if you need System Exclusive handling you must verify against your own devices, or if offline documentation in the repository is a requirement, because the README is a pointer to webmidijs.org rather than a specification. Verify first that the instruments you target enumerate correctly, since the whole library is a layer over what the browser's Web MIDI implementation reports.

## FAQ

### What is webmidi used for?

webmidi, or WEBMIDI.js, is a JavaScript library for interacting with MIDI instruments from a browser or from Node.js. It provides user-friendly functions such as playNote(), sendPitchBend() and sendControlChange(), and listeners for events such as noteon, pitchbend and programchange.

### How do I get started with webmidi?

The README points to the project's website at webmidijs.org as the place to start, with documentation at webmidijs.org/docs/ and the API reference at webmidijs.org/api/. The README itself contains no install command or getting-started code sample.

### Does webmidi work with Node.js and bundlers?

Yes. The package describes itself as working in a browser or from Node.js, requires node >=8.5, and its exports map provides separate CommonJS and ESM builds with .d.ts declaration files for each. Build scripts produce CJS, ESM and IIFE formats.

### How do I request a feature in webmidi?

The README asks you to first check whether the enhancement is already planned on webmidijs.org/docs/future-versions/next, then discuss it in the Enhancement Proposals category of the project's GitHub Discussions forum.

### What licence is webmidi released under?

It is released under the Apache-2.0 licence, declared in package.json with LICENSE.txt at the repository root, and the repository also carries a SECURITY.md. This is a licensing note and not legal advice.

## Sources

- [djipco/webmidi on GitHub](https://github.com/djipco/webmidi)
- [Issues](https://github.com/djipco/webmidi/issues)
- [License: Apache-2.0](https://github.com/djipco/webmidi/blob/master/LICENSE)
- [README](https://github.com/djipco/webmidi/blob/master/README.md)
- [Releases](https://github.com/djipco/webmidi/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/djipco-webmidi
