Library / SDK
bencevans/node-sonos avatar
bencevans/node-sonos

node-sonos puts the Sonos local API behind a JavaScript interface

🔈 Sonos Media Player Interface/Client

723 stars140 forksJavaScriptMIT

At a glance

What is it?
bencevans/node-sonos is an MIT licensed Node.js library that discovers Sonos speakers on the network and controls playback, queues, groups, volume and alarms, with events for state changes. It is wide rather than deep, and one method is struck through because a Sonos firmware upgrade broke it, which is the clearest sign of how much of it depends on undocumented local behaviour.
Who is it for?
Adopt node-sonos if you are building your own JavaScript tooling for a household of Sonos speakers and you want direct local control with change events rather than a cloud integration, since the library exposes discovery, playback, queue and group operations in one package.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 140 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Discovery on the LAN, then HTTP and XML to each speaker

node-sonos gives you the power to control Sonos devices from your own JavaScript applications, and the mechanism has two halves. The first is discovery: the library finds your devices automatically on the network, so your code does not have to know their addresses in advance. The second is the per device interface, exposed as the Sonos class, which is constructed with a host and an optional port. Everything the library does is expressed as methods on that object, and the underlying plumbing is visible in the dependency list: axios for the HTTP requests, xml2js for parsing the XML payloads, the debug module for tracing, and the ip package for working with addresses. The API also exposes a raw request method taking an endpoint, an action, a body and a response tag, which tells you the calls are structured XML documents against named service endpoints rather than a REST API in the usual sense.

Two discovery styles, one event contract

Discovery comes in two flavours and the choice is about how your code is shaped. The first is a callback style where the discovery function is called with a listener that fires for every device found:

js
const { DeviceDiscovery } = require('sonos')

// event on all found...
DeviceDiscovery((device) => {
  console.log('found device at ' + device.host)

  // mute every device...
  device.setMuted(true)
    .then(d => console.log(`${d.host} now muted`))
})

The second form is a class with an event emitter, where you wait for a DeviceAvailable event and then work with the device:

js
DeviceDiscovery().once('DeviceAvailable', (device) => {
  console.log('found device at ' + device.host)

  // get all groups
  device.getAllGroups().then(groups => {
    groups.forEach(group => {
      console.log(group.Name);
    })
  })
})

There is also an asynchronous variant for code that prefers promises over callbacks:

js
const DeviceDiscovery = require('sonos').AsyncDeviceDiscovery
let discovery = new DeviceDiscovery()
discovery.discover().then((device, model) => {
    // Do stuff, see examples/devicediscovery.js
})

Note that the async class exposes both discover and discoverMultiple, while the callback style class exposes a destroy method, which is the way to stop the discovery process when you no longer want it. The model is returned alongside the device in the promise form, which is useful when you need to distinguish a speaker from a soundbar.

The surface is wide: playback, queue, groups, alarms and events

The API listing in the README is long, and it is worth reading as a map of what a Sonos speaker can be asked to do. Playback covers play(uri), pause, stop, next, previous, seek(seconds) and togglePlayback, plus getPlayMode and setPlayMode. The queue has getQueue, queue(uri, positionInQueue) and queueNext(uri). Grouping has joinGroup(otherDeviceName), leaveGroup() and getAllGroups(). Volume and mute have getVolume, setVolume, getMuted and setMuted, and there are extras such as getZoneInfo, getZoneAttrs, getLEDState, setLEDState, setName, flush and an alarmClockService with ListAlarms, PatchAlarm and SetAlarm. Spotify support appears as setSpotifyRegion, and a TuneIn-style radio example lives in the examples directory alongside playSpotifyMusic and playTuneinRadio. The event list is the part that makes this more than a remote control: startListening and stopListening enable notifications for CurrentTrack, NextTrack, PlayState, PlaybackStopped, AVTransport, Volume, Muted and RenderingControl, so your application can react to a track change instead of polling.

Installing and controlling a device you already know the address of

The published package is the recommended route, and the repository version is offered as the way to live on the edge:

bash
    $ npm install sonos
bash
    $ npm install git://github.com/bencevans/node-sonos.git

If you already know the address of a speaker, you can skip discovery entirely and construct the device object directly:

js
const { Sonos } = require('sonos')

const device = new Sonos('192.168.1.56');

device.play()
  .then(() => console.log('now playing'))

device.getVolume()
  .then((volume) => console.log(`current volume = ${volume}`))

Every call returns a promise, which is the consistent style across the API. For a first run, the sequence that makes sense is to start discovery, confirm that the speakers you expect are found, then start listening for events and drive playback. The examples directory holds one file per topic, with entries such as deviceDiscovery.js, events.js, queue.js, groupManagement.js, alarmService.js, addSpotify.js, playNotification.js, control-led.js, getstate.js, radio.js and searchLibrary.js, so there is a working example for most of the surface rather than a single getting started snippet.

A struck through method is the clearest warning in the README

One line in the API list deserves attention because it explains the fragility of the whole approach. getTopology is marked as not working if you upgraded to Sonos v9.1, with a pointer to getAllGroups as a replacement. That is a firmware change breaking a method that had no contract to break, and the maintainer handled it by documenting the failure and naming a substitute rather than removing the entry. The reason is not hard to see: the library drives speakers over local interfaces that Sonos does not promise to keep stable, so a speaker software update can change what a method returns. The same applies to the rest of the surface, from the alarm service to the Spotify region call. Treat each method as something that should be exercised against your actual hardware and firmware before you depend on it, rather than as a stable contract.

standard lint, mocha with nock, and generated docs

The repository shows the shape of a long lived library in its tooling. Linting is done with standard, the JavaScript style guide tool, and the pre-commit hook runs that lint step, so style problems are caught before a commit lands rather than in review. Tests run through mocha against test/sonos.test.js with a 20 second timeout, and the nock package is a development dependency, which is how the suite avoids hitting real speakers on a network. Documentation is generated from JSDoc comments with jsdox, using separate templates for the library, the services and the events directories, and the README says the goal was to add jsdoc info to all functions and generate documentation from it. The repository also carries API.md, a CHANGELOG.md, a LICENCE.md, a renovate.json for dependency updates, a .vscode directory and an .all-contributorsrc file.

MIT licensed, and the release history is not linear

The licence is MIT, recorded both in the package metadata and in the LICENCE.md file at the repository root, which is the permissive choice that lets you ship it inside a larger application. The release history is worth reading carefully because the tags are not in a straight line. v1.15.0-alpha.5 was published on 2021-10-04, v1.14.2 on 2025-12-01 and v1.14.3 on 2026-02-27, so the alpha line is years older than the stable line and the stable line is the one that has moved recently. The repository is not archived and the last push was on 2026-06-05, which is months after the newest published release, so the branch and the published package are not the same thing. If you depend on a specific behaviour, pin an exact published version rather than tracking the branch, and read the CHANGELOG.md between the version you use and the newest one.

A bridge such as MQTT or Homebridge is the other way in

The README lists the projects built on this library, and they fall into a pattern that is itself an alternative design. sonos2mqtt bridges Sonos to an MQTT server, homebridge-zp is a Homebridge plugin, sonos-cli is a command line interface, and AirSonos adds AirPlay support to every speaker on a network. Rather than reaching for the speakers directly, these projects translate Sonos control into a protocol your home automation system already speaks, which is a different approach to the same problem. The difference matters for two reasons. A bridge lets you control speakers from a system that already handles lighting, sensors and locks, so your code does not need the library at all. And a bridge keeps the Sonos specific dependency in one place, so a firmware change that breaks a method costs you one adapter to fix rather than every integration that talks to the speaker. If your project is already inside one of those ecosystems, the bridge is probably the route, and if you are writing a self contained application that needs track level events, the library itself is.

Editorial conclusion

Adopt node-sonos if you are building your own JavaScript tooling for a household of Sonos speakers and you want direct local control with change events rather than a cloud integration, since the library exposes discovery, playback, queue and group operations in one package. Do not adopt it for a commercial product without checking the licence of the Sonos interfaces it relies on, and do not expect every method to work on current firmware, since getTopology is marked as not working after Sonos 9.1. Before you build on it, check the last push date of 2026-06-05 and the newest published release v1.14.3 from 2026-02-27 against the firmware you run, and confirm the events you need are listed in the API section of the README.

Frequently asked questions

How do I install node-sonos and find my speakers?

Install the published package with npm install sonos, or the repository version with npm install git://github.com/bencevans/node-sonos.git. Discovery is handled by DeviceDiscovery, either as a callback for every device found or as a class that emits the DeviceAvailable event, with AsyncDeviceDiscovery available for promise based code.

How do I control a Sonos speaker with a known IP address?

Construct the device directly with new Sonos('192.168.1.56') and call methods such as play(), getVolume() or setMuted(). Every call returns a promise, and the class also accepts an optional port as a second argument.

Which node-sonos events can I listen to?

After calling startListening, the documented events are CurrentTrack, NextTrack, PlayState, PlaybackStopped, AVTransport, Volume, Muted and RenderingControl. The options parameter is accepted by startListening, and stopListening turns the subscription off.

Does getTopology still work in node-sonos?

The README marks it as not working if you upgraded to Sonos v9.1, and points to getAllGroups as a replacement. That entry is a good indicator of how much of the API depends on local interfaces that firmware updates can change.

Can I control Sonos groups and alarms with node-sonos?

Yes. Grouping is handled by joinGroup, leaveGroup and getAllGroups, and the alarmClockService exposes ListAlarms, PatchAlarm and SetAlarm. The examples directory contains groupManagement.js and alarmService.js as working references.

Official sources

  1. bencevans/node-sonos on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/bencevans-node-sonos.svg)](https://hysenlabs.com/projects/bencevans-node-sonos)

Was this useful?