[APP][Pro] Spotify Connect

While I appreciate the details you’ve provided, the larger part of your message is explained in the first post(s). Especially the limitation to what device(s) you have access to and how to activate them. Also later posts in this thread explain that further.

The only think I could try to replicate and debug is why you can’t find al playlists. But my guess is the current one filters based of the person who made this (Discover Weekly is created by Spotify, not your own account).

I’ll get back to this as soon as I find some time again.

Ah- there’s so many posts I hadn’t read far enough. For those readers who are also a tad lazy who want background on the red exclamation device connection problem, read back to posts from December 2025.

I don’t think the device awakening problem is necessarily it- because all my devices still appear in my Connect list. For reference here, my web browser is my work computer (I’m currently in the office). My computer hasn’t played anything since last night- so definitely an expired token- but still lists. My phone didn’t list at all until I opened the app, at which point it listed and I can swap playback to it. None of these devices are on the same network.

Now over the weekend when I was fiddling with this, availability for playback was dropping within seconds of swapping playback elsewhere- far sooner than a token would expire. The Connect support page does say same wifi for the first connection, but farther down mentions once we’re logged in using credentials we should see the device even if not on the same wifi (the behavior I’m seeing). I’m not convinced tokens are the answer.

There are no second accounts involved, nor other people connecting.

Now the extra funky part- I tried using the official app to transfer playback from my browser to my phone (no playback in 12+ hrs) and it worked flawlessly. So if all else fails, maybe chat with a Athem employee to see how their app is doing it? I know they love to support community developers.

An additional note: I took a moment to have Claude (my work has the super advanced model) read the entire Web API Reference, this forum, AND the whole github, and it found a solution. Maybe. Try giving this a shot:

After reading through the app source code (GitHub), here’s what I found:

How devices work now: The Spotify device ID is stored permanently at pairing time. Every 15 seconds, _sync() calls GET /me/player/devices, looks for that stored ID, and checks is_active. If the device isn’t in the response OR is_active is false, Homey marks it unavailable (red exclamation mark). The device ID is never refreshed after pairing.

The app never calls Transfer Playback. It passes the stored device_id as a query parameter to PUT /me/player/play (Start/Resume Playback), which behaves inconsistently — often returning 404 if the device isn’t already the active player. The actual Transfer Playback endpoint is PUT /me/player, which is designed to wake up and activate a known device. The app never uses it.

Three problems:

  1. No Transfer Playback — The app can’t activate an inactive device. PUT /me/player with {"device_ids": ["<id>"], "play": true} is the correct way to push playback to a device that Spotify’s servers know about but isn’t currently active. This is likely how the official Homey Spotify app can swap to devices that this app can’t see.

  2. Availability check is too strict — Gating on is_active means the device shows unavailable anytime it’s not the current playback target, even if Spotify’s servers still know about it. The check could be loosened to just verify the device exists in the response, or removed entirely and let Transfer Playback fail gracefully with a user-facing error.

  3. Frozen device IDs — Spotify can reassign device IDs when hardware reconnects. Since the stored ID never updates, the Homey device can become permanently broken with no fix other than deleting and re-pairing. A periodic ID refresh (matching on device name/type) would prevent this.

Suggested fix: Call PUT /me/player to transfer playback before issuing play commands, loosen the availability check, and add device ID refresh logic.

Now while I have Claude open… I asked about the play/pause cards toggling instead of being absolute commands:

  • The play/pause handler toggles a locally cached boolean (this.devicePlaying = !this.devicePlaying) instead of calling the API endpoints directly. Since the cache only syncs every 15 seconds, if Spotify’s state changes outside Homey in that window, the toggle fires the wrong command.

  • Fix: “Play” should always call /me/player/play, “Pause” should always call /me/player/pause. Skip the boolean entirely.

And as for the not finding all playlists problem:

getMyPlaylists() calls GET /me/playlists?limit=50 once with no offset and no pagination loop. If you have more than 50 playlists, the rest are silently dropped. Spotify-generated playlists like Discover Weekly and Daily Mix likely exist in the library but fall outside that first page of 50.

I do hope this is helpful! I’m a mechanical engineer, not software, so it’s difficult to verify if anything is a genuine fix. If it’s garbage, let me know.

Thank you for the support, love the app!

So I did a little more digging this morning and think I’ve found a couple things.

Device awakening is a problem, just not my problem. The ‘get /me/player/devices’ API call will pull all devices or playback options with an active token. My web browser, my desktop app, or a dedicated streamer (like a wiim) will constantly ping Spotify and maintain an active token- this is why they always show up on my Connect list. A denon AVR, a speaker, or something else will go to sleep to save power and thus lose their token after X time. Awakening them is something you’ve been looking at. But, the call yields a list of valid devices to play on. This is good, and what happens in driver.js when connecting a new device. That’s why it finds everything.

Solution proposal #1: The red exclamation mark (device unavailable)

The driver.js _sync() loop running every 15 seconds for each Homey device is operating like this:

IF device exists in API call AND device is active (playing something)
   Sync all playback data to the app for display and control
ELSE
   Set device unavailable (red exclamation!)

If playing on my phone my desktop app isn’t unavailable, it just isn’t playing anything. But the loop marks unavailable. I’d propose adding an ELSE IF in the middle there for this case:

IF device exists in API call AND device is active (playing something)
   Sync all playback data to the app for display and control
ELSEIF device exists in API call, but isn't active (playing anything)
   Do nothing. Is available, just not playing.
ELSE not in API call.
   Set device unavailable (red exclamation!). Expired token probably.

This would add some delineation between devices not playing something but available and truly unavailable and in need of a token refresh. This also fixes the discrepancy of what I see in the app vs what my Homey thinks is available.

Solution #2: Playback Transfer

So right now the only way to transfer playback between devices is to use the ‘play’ card under the new device. The official app has a card for “Play on this device” and Spotify has a dedicated API call. Under lib > SpotifyConnectOAuth2Client.js we add:

async transferPlayback(deviceId) {
    return this.put({
        path: '/me/player',
        json: {
            'device_ids': [deviceId],
            'play': true
        }
    });
}

Some notes:

The red exclamation mark seems to be more of a visual thing if anything. With proper playback transfer it technically won’t matter, because playback transfer is going to throw playback to a device ID regardless of status (unless Homey gets in the way). This delineation may even help going forward with the token refresh, since you’d only need to run a token refresh on things that actually need it. I don’t see anything that checks device availability elsewhere in the code, and I don’t know what Homey does to ‘unavailable’ devices.

As for playback transfer, I don’t know what else would be required for turning it into a new card if that’s the route to go. This could also be a function called anytime you press or send a ‘play’ command. If that’s the case, a card may be unnecessary. The ‘Play’ card from a specific device would auto transfer control more elegantly to that device.

Cheers!

The information concerning keeping the devices active, in particular the playback command, feels like the things I already tested months ago. But I gave it another shot last night. There’s a new testversion available for you to test, I’m lacking time to test myself.

Changes compared to the current live version:

  • Smart self-healing keep-alive method that monitors the device IDs in Spotify. Whenever a devices disappears the app now tries to find the new device ID by comparing the type and name, if an exact match is found it self heals by setting this new ID to the matching Homey device.
  • When using cars to start playback on a device it now first sets it as the currently playing device before starting the actual playback. To prevent that speaker from playing something that was already queued we just transfer to that device while pausing it at once. A seperate call then transfers the active song to the new device. It can be noticable (± 300 ms extra) but probably sounds better compared to having a previous song stutter for a bit before your selected song plays.
  • Playlists get loaded in-memory (5 min TTL cache) and the script now follows all pages. Obviously the easiets way to find your playlist is by searching on (parts of) the name instead of scrolling a list so long.
  • For speaker_playing, speaker_shuffle, speaker_repeat, volume_mute, volume_set, the value Homey hands the listener is the user’s intent (“set to true”), not a reading of current state. So we never need to know what Spotify currently thinks — we just send the intent. No staleness possible because no read is involved.
  • For relative bumpers (volume_up/volume_down) the staleness problem genuinely doesn’t go away. Whether I read getCapabilityValue(‘volume_set’) or my own deviceVolume, both are populated by the same 15s sync loop — they’re identically stale.

Curious to see if we can get these long standing issues sorted by this.

Thanks for thinking along! Really appreciated.

Oh sweet! That was quick. I also realize I was running the last released version 1.4.1, not 1.5+

There’s been a bit of a (major) problem. Seems like there’s a super secret max API call count, beyond the known calls per 30 second window rate limit. I did some testing for 20 minutes, let it play, and came back 30 minutes later or so to find every device unavailable and showing “rate limited”. No calls allowed through. I seem to recall you or someone else saying there’s a limit of 1000 calls, which is why we have our own dev apps- the last post in this thread suggests it’s more like 600. Possibly the loop causing problems with 3 devices connected? I barely did any testing… Tried disabling the app, waiting for 30s API window to rollover, deleting all devices, downgrading to last full version released- all with no luck. Even reconnecting devices didn’t work, also rate limited. Might be worth looking into. Claude thinks it’s a 429 error with no back off death loop. *Update: that was at 11:00. It is now 16:30 and things seem to be working normal again? I’ll see if I can break it again tomorrow.

Test Results and Observations:

  • Red exclamation // Devices unavailable when not playing
    • Seems to be fixed. Devices with active tokens are now just gray (as if it was a turned off light). Selecting brings up song controls (no song displayed if not active device, see pic). Pressing play does in fact transfer playback to it too! Sweet! The skip button skips the song on the playback device and does not switch playback devices. Album art does not seem to populate anymore, not a major bug.
  • Playback transfer
    • The ‘Play’ cards in flows transfer playback to the card’s device seamlessly.
  • Other card functionality
    • Play and Pause cards are absolute now, no weird toggle behavior
    • Toggle play/pause works per usual
    • [Device] Is playing works great. Prior, if device not playing, card would throw error since device was ‘unavailable’. Now it flows to negative option, opening error path for if device was actually offline.
    • Play [Song] is iffy. Is playback is on device X, and card is to play song on X, it works great. If playback is on device X, and card is to play song on Y, it only switches playback and does not actually play the song. Minor bug.
  • Wasn’t sure how to test the smart self-healing. Sorry.
  • Playlist searching is still broken
    • I can see playlists that I’ve made and ones I’ve saved into my library, mostly. Daily mixes, which are saved to my library, are not present. Seems there’s some filter on your end or another.
    • Claude is telling me your playlist.tracks?.total was deprecated and should become playlist.items?.total to fix the zero tracks bug
    • I can’t believe there’s no command to pull find everything inside a user’s library. That strikes me as odd. I’ll look harder tomorrow. The official app does it somehow- it even finds the AI DJ.

Volume staleness I don’t think is that huge of a problem quite frankly. Though one solution might be to add more calls on top of the sync. If a card sends a command, or certain cards maybe, run sync immediately instead of waiting. Unless you already do that…

Anyway- happy to help! I’ve got a couple other bugs in mind, but they’re a minor thing and I need to run.

I know from my search a few months back that there are no exact numbers given towards what the actual rate limit is per app. I can image that it also depends on how busy the api actually is at the moment (the way Claude manages their usage windows too). So far I have never hit any rate limit during testing and honestly. The only info they give is that you can’t exceed the 30s window limit, but not what that limit exactly is.

Even with 3 devices it takes just 6 calls for the polling interval to refresh the states and if you decide to skip a few tracks or change some playback things you’d hardly hit 10-15 calls in that window. IIRC there was an option to request a larger limit for your app inside the developer portal too.

Self-healing can’t be tested really, it’s just a matter of watching your devices stay available. Perhaps you could try to do a power cycle on one of your speakers. As this should hand out another device ID the self-healing process should catch the new ID and save it with your existing device.

The volume staleness can be fixed by adding a sync call prior to executing the volume relative change. This would take the speakers actual volume and +/- that value. Only strange thing would be the volume slider skipping a few numbers, but in the end it does what you expect (increase/decrease the volume you are currently hearing).

Sounds like I’ve got these things to check:

  • See why album art doesn’t work, probably a local “active device” setting or something. I recall having some issues at the start while building this app to get it working properly.
  • After the “Play song on [X]” we need to make sure that it transfers and starts playing the selected song. It’s a 2-step proces in the code already (just to play safe) but maybe it needs a bit more time than the 300ms pause I’ve used now.
  • Playlist search still doesn’t show all results

Feel free to let me know what other bug you’re after. I’m off for a few days, but I’ll get back to this after the weekend.

Thanks for your help!

Well I tried and tried and couldn’t break the API again. Must have been a unicorn event.

Album art was also a unicorn event, I get home from the office and it worked fine. Even today in the office, working fine. Must’ve been something unrelated.

I’ve given up on the playlist search being able to find everything. The GET /me/playlists is limited exclusively to user owned or followed playlists, NOT including spotify owned playlists (like the daily mixes). They must be under some special category, despite being saved in my library. There’s evidence of this with the GET /browse/featured-playlists call (now deprecated) pulling the featured playlists, presumably including the daily mixes, DJ, and others.

Now I looked into that option to request a larger API call limit and found a couple things: to start, there’s 2 levels of developer app. Our level, which we are familiar with, and the extended quota level, which has some pretty stiff requirements. For one, having 250,000 users. This is almost definitely the API level that Homey has, and one benefit of that is that all of the deprecated commands we can’t use are available to them. No way around that one.

So in short, I don’t think there’s an easy way to solve the problem. Not unless you integrate GET /search into the variable on the card itself, searching for only playlists. If this is a path you’re intrigued by, I’d say this is the way to go:

IF user selecting a playlist
   show playlists in library
   IF start typing in box
      filter by their typing
      IF no results
         use /search to get more results [filter search by playlists]

I suggest this because using search should pull up the user specific featured playlists, ie daily mixes. Maybe.

So that’s it! I’m perfectly happy with the current state and it works great. Poking at other bugs would just be a little pedantic, and I can work around them no problem. I’ll let you know if there’s anything in mind that comes up.

Appreciate the responses! Enjoy the weekend!

Can somebody please tell me which Spotify connect device i need since Sonos doesnt work? :slight_smile:

Great!

I’ll see if I can do some tests with the playlist. Haven’t been using the app myself very often recently, hopefully soon enough once the renovation at home is coming to an end and I can start truly wiring up all devices, automations and a nice tablet as control center :slight_smile:

@Sand3R: what is it that you exactly mean? As long as the speaker works directly using Spotify Connect you’re good. Sonos and Google speakers work via their own network which I can’t control via the Spotify API. That’s all.

I want to control my sonos speakers with Spotify Connect via my Homey Dashboard. Is this possible by any means? Should i use a device in between which supports Spotify connect and can talk to my Sonos?

Then I don’t think the first post can be anymore clear about that. Unfortunately that’s it for now. I’m working on an update that is going to support Sonos but no ETA yet.

:warning: This app only works with a Spotify Connect device and will not work with Sonos or Google speakers! :warning:

Just popping in again…

It seems to me that Sonos integration should work without issue as-is. You can add Spotify to your Sonos account and thus control your speaker through Connect- per the Spotify website, AND the Sonos website. Given that Sonos would show up as a Connect device, this app should be able to see and control it. If the speaker maintains a valid token that is.

I don’t have Sonos so I can’t verify that, nor do I know specifics of the network problem, but I’d think this should work.

@Sand3R So in theory you can put things between, yes. The (simplified) audio chain for basically anything from small things like this to theaters to concerts is [Input/streamer/etc —> amplifier —> speaker]. Sonos puts all those things in the same box. You could buy a dedicated streaming device like a wiim and try to connect it to your Sonos, via cable or bluetooth or other. If you ditch sonos, you could even split the others- getting some passive bookshelf speakers and a small amp, like from Fosi audio. Just beware it’s extremely easy to go overboard with that approach. And I don’t know what external inputs are available on your sonos speakers, so I can’t give specific recommendations.

It’s a limitation in the Web API and is not related to it actually being a Spotify Connect device. A bit confusing, and that’s a bit on me an Spotify both I guess. I also thought this should work when starting on this app but had to learn the hard way.

So — “is a Spotify Connect device” and “is fully controllable through the Web API” are two different things, and Sonos sits in the gap between them.

What’s happening is that the Web API’s /me/player endpoints don’t accept commands from every Connect device. Not all devices are supported by the /player endpoints, and the player API limitations are documented by Spotify. When you fetch the device list, look at two fields on each device object: Spotify Community

  • is_restricted — whether controlling this device is restricted. If this is “true” then no Web API commands will be accepted by that device. (Spotify)
  • supports_volume — whether the device can be used to set the volume. (Spotify)

Sonos typically comes back with is_restricted: true (and often supports_volume: false). So it appears in the device list and you can sometimes transfer playback to it, but transport and volume commands either no-op or return errors. Some developers don’t even see Sonos in the device list at all, depending on state.

In the update update I’m working on it actually only saves the Sonos device ID. And only the search endpoints are actually hitting the Spotify Web API. As soon as you choose something playable that track ID, for example, then is sent over the Sonos network interface directly. So waking up, playback and controls run fully independent of the Spotify API. It only requires you to have setup Spotify in the Sonos app.

In some way adding Sonos bypasses the scope set by the name of this app. But looking at the amount of times this is being asked for (and my personal choice for Sonos as home audio) I think it’s worth having this in one app.

Huh, weird. Sonos is a spotify connect device, but cannot be commanded through the API. Interesting.

Now there is a bit of a quirk in the API: control commands don’t necessarily have to go to the direct device. If I’m playing on device A, but send certain commands to device B (next, pause, shuffle, etc), then device B will accept those commands and sync through Spotify back to device A. You can get pseudo control of device A like that, for non-device specific commands. This method does require a device B with a persistent active token though… But technically you could control sonos like this. You local network fix is way better of course.

But neat to learn that some devices are API restricted, I wouldn’t have ever thought that. And agree that Sonos integration would be a good thing despite the added scope.

In unrelated news, I found the specific reason your app can’t pull the spotify created playlists but the official app can. They use extended quota mode, which is unaffected. See point 8.

A Spotify Connect device only indicates it can be controlled using your Spotify app. But it doensn’t mean the Web API works on that device. Sonos and Google for example both excluded their devices from the Web API. Sonos probably because they have their own API layer (Control API).

For the playlist “bug”: it turns out my app does find Discover Weekly. There is a chance that’s because I’ve created my developer app just a few weeks (oct 2024) before the limitations where applied (nov 2024).

You’re using the Play [playlist] card and can see discover weekly? Lucky you. I was under the impression from the article that all dev level apps would have it disabled, not just ones after that date. I’ve got nothing :smiling_face_with_tear:

Makes me wonder, did I really find my own playlist yesterday or did I find a random playlist named Discover Weekly…

I found mine using the dashboard widget (filtered on playlists). Worth a try to see if it pops up there, but I doubt it. It’s not uncommon that apps have different features enabled based off of when they are created for an API (permissions are attached on the date of creating it). They limitted features last nov/dev also, but in that message they stated that apps created prior to that date wouldn’t be affected.