External integration - Plex

Hi everyone! :waving_hand:

I’m sharing a new external integration that I just published: Plex, to connect your Plex server to Gladys. If, like me, you have a NAS running Plex and you’ve been dreaming of connecting your playbacks to your automations, here it is! :slightly_smiling_face:

What it does

A « server » device with monitoring sensors:

  • :bar_chart: number of active streams and sessions in transcoding
  • :satellite_antenna: streaming bandwidth (kbps)
  • :television: a « now playing » text that summarizes who is watching what
  • :card_index_dividers: a counter per library: movies, series (+ episodes), music (+ tracks) — can be disabled if you don’t want them

A device per Plex player (TV app, phone, etc.):

  • :play_button: the controls: play, pause, stop, previous, next, fast forward/rewind, volume, mute
  • :musical_note: the playback state, compatible with the Music widget on the dashboard
  • :label: the current title (Series S01E02 - Episode, Artist - Title, Movie (year)) and the remaining time
  • :sparkles: my favorites: two binary sensors « in the intro » and « in the closing credits », based on the markers detected by Plex!

This last point opens up nice scenarios:

When the credits start in the living room → turn on the lights :light_bulb:
When a playback starts after 10 p.m. → dim to 20 %
A « general pause » button at mealtime :spaghetti:

The states update in a few seconds: the integration listens to the Plex server’s real-time stream (WebSocket), with a configurable fallback polling. Players are automatically discovered — even on the fly as soon as a device starts a playback.

Installation

  1. In Gladys: Integrations → Multimedia category → Plex (while the store indexer passes, you can also install via the repository URL)
  2. Enter the URL of your server (http://nas-ip:32400) and your X-Plex-Token (how to find it)
  3. « Test connection » button, then Discovery tab → add your devices, that’s all :white_check_mark:

A small but important detail: to control a phone/tablet, remember to enable « Announce as a player » in the relevant Plex app. Without this, only the Stop button works (it cuts the session on the server side).

Under the hood

This is a v1.0.0: tested at my place (NAS + SHIELD + mobiles), but I count on you to push it to its limits :grinning_face_with_smiling_eyes: Feedback, ideas, and PRs are welcome — tell me what you’re missing (launching a specific media? additional sensors?).

Happy reading… of movies! :popcorn:

Hey!

Thanks for this integration! You were faster than me for the release, I had a test version but I wasn’t satisfied with it yet :zany_face:

I do get feedback but I can’t control the music of Plexamp on the iPad (nothing at all). Nothing explicit in the logs:

[2026-08-16T05:26:02.094Z] [INFO] onConfigUpdated -> new configuration received
[2026-08-16T05:26:02.103Z] [INFO] [plex-monitor] Connected to Plex server "gladys" (v1.43.3.10861-07dfddaeb)
[2026-08-16T05:26:02.411Z] [INFO] [plex-notifications] Connected to the Plex notification socket
[2026-08-16T05:26:04.920Z] [INFO] [plex-monitor] Connected to Plex server "gladys" (v1.43.3.10861-07dfddaeb)
[2026-08-16T05:26:18.383Z] [INFO] onDeviceCreated <- ext:ext-guim31-gladys-plex:server:2b588884a92967f7f95cb7f55784f2dd5468ac73
[2026-08-16T05:32:58.442Z] [INFO] [plex-monitor] New Plex player discovered: iPad
[2026-08-16T05:33:54.106Z] [INFO] onScanRequest -> publishing 2 devices
[2026-08-16T05:33:57.652Z] [INFO] onDeviceCreated <- ext:ext-guim31-gladys-plex:player:b8474c9e-6b33-454e-8594-14ba25f9babd
[2026-08-16T05:35:44.327Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:b8474c9e-6b33-454e-8594-14ba25f9babd:pause = 1
[2026-08-16T05:36:05.254Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:b8474c9e-6b33-454e-8594-14ba25f9babd:play = 1
[2026-08-16T05:36:06.530Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:b8474c9e-6b33-454e-8594-14ba25f9babd:previous = 1
[2026-08-16T05:36:21.819Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:b8474c9e-6b33-454e-8594-14ba25f9babd:next = 1
[2026-08-16T05:36:36.768Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:b8474c9e-6b33-454e-8594-14ba25f9babd:stop = 1
[2026-08-16T05:36:47.420Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:b8474c9e-6b33-454e-8594-14ba25f9babd:forward = 1
[2026-08-16T05:36:50.634Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:b8474c9e-6b33-454e-8594-14ba25f9babd:mute = 1
[2026-08-16T05:36:52.369Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:b8474c9e-6b33-454e-8594-14ba25f9babd:rewind = 1

I’d like you to ask your ‹ new friend â€ş to add webhook usage (I have a Plex Pass and GladysPlus) because it allows not to wait for the 10s poll.

Unfortunately, I can’t see it on the store :man_shrugging:
But I’m waiting for its integration

Oh man! We didn’t communicate well… :sweat_smile:
Maybe your version would be more polished?

I’ll check out Plexamp, I’m silly I have it on my phone but I forgot to test it because I don’t use it anymore!

I’ll give you feedback from my technician and let you know :+1:

Oops, I hadn’t indexed it! It’s done, it will appear in max 1 hour

My turn to be happy :slight_smile:

This is an integration I was waiting for :slight_smile:

I currently have an issue with the plex chrome client (haven’t tested the TV yet) :

I don’t know why I have no recent value instead of push button.

The push buttons don’t respond except for stop, the volume also doesn’t seem to work either :slight_smile:

And we don’t judge the media, it’s for my daughter :eyes: :stuck_out_tongue:

log :

[2026-08-16T10:04:00.117Z] [INFO] Starting the Plex integration...
[2026-08-16T10:04:00.307Z] [INFO] [gladys-sdk] connected to Gladys (http://172.30.0.1:8455)
[2026-08-16T10:04:00.322Z] [INFO] Waiting for the Plex configuration (URL + token)
[2026-08-16T10:10:22.832Z] [INFO] onConfigUpdated -> new configuration received
[2026-08-16T10:10:22.832Z] [INFO] Waiting for the Plex configuration (URL + token)
[2026-08-16T10:11:13.870Z] [INFO] onConfigUpdated -> new configuration received
[2026-08-16T10:11:13.907Z] [INFO] [plex-monitor] Connected to Plex server "DiskStation" (v1.43.2.10687-563d026ea)
[2026-08-16T10:11:14.437Z] [INFO] [plex-notifications] Connected to the Plex notification socket
[2026-08-16T10:11:20.384Z] [INFO] onConfigUpdated -> new configuration received
[2026-08-16T10:11:20.391Z] [INFO] [plex-monitor] Connected to Plex server "DiskStation" (v1.43.2.10687-563d026ea)
[2026-08-16T10:11:20.566Z] [INFO] [plex-notifications] Connected to the Plex notification socket
[2026-08-16T10:11:21.853Z] [INFO] [plex-monitor] Connected to Plex server "DiskStation" (v1.43.2.10687-563d026ea)
[2026-08-16T10:11:41.734Z] [INFO] onDeviceCreated <- ext:ext-guim31-gladys-plex:server:a8058595a4bb5a3537614ec74ebdf3c644e8d14e
[2026-08-16T11:39:01.060Z] [INFO] [plex-monitor] New Plex player discovered: Chrome
[2026-08-16T11:40:14.880Z] [INFO] onDeviceCreated <- ext:ext-guim31-gladys-plex:player:ed9ht57db2wn25la3vfyjnpo
[2026-08-16T11:41:30.401Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:ed9ht57db2wn25la3vfyjnpo:volume = 22
[2026-08-16T11:41:31.140Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:ed9ht57db2wn25la3vfyjnpo:volume = 11
[2026-08-16T11:41:41.139Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:ed9ht57db2wn25la3vfyjnpo:volume = 0
[2026-08-16T11:41:42.369Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:ed9ht57db2wn25la3vfyjnpo:volume = 7
[2026-08-16T11:41:43.282Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:ed9ht57db2wn25la3vfyjnpo:volume = 0
[2026-08-16T11:41:54.712Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:ed9ht57db2wn25la3vfyjnpo:mute = 1
[2026-08-16T11:41:57.426Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:ed9ht57db2wn25la3vfyjnpo:mute = 1
[2026-08-16T11:42:11.046Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:ed9ht57db2wn25la3vfyjnpo:stop = 1
[2026-08-16T11:42:11.066Z] [INFO] [plex-monitor] Session of ed9ht57db2wn25la3vfyjnpo terminated server-side (stop fallback)
[2026-08-16T11:42:33.547Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:ed9ht57db2wn25la3vfyjnpo:mute = 1

ps: Tested on Android via the app, same issue :frowning:

Thanks to both of you for the ultra-detailed feedback, and especially for the logs :folded_hands: They helped find the culprit in two minutes. v1.0.1 is available, it fixes all that.

What was wrong

To check if a player is controllable, I relied on the /clients endpoint of the server. Beginner’s mistake: it’s the old discovery mechanism (GDM), and it’s empty on most modern servers — Plex apps no longer announce themselves there. Result: Plexamp on iPad, Plex Web on Chrome and friends were rejected before any command was even attempted. Hence « no button reacts ».

And if Stop worked, it was a happy coincidence: it was the only one with a backup plan (cutting the session on the server side), which still works :sweat_smile:

What changes in 1.0.1

  • :video_game: Commands are now actually sent, and it’s the server’s response that decides. If Plex refuses, you get an explicit error in Gladys instead of a dead button — and Stop keeps its backup plan.
  • :muted_speaker: The Mute button finally works as a toggle. Gladys displays it as a push button (it always sends « 1 »), so my code only knew how to mute the sound, never to unmute it. @spenceur that explains your mute = 1 loop in the logs!
  • :repeat_button: No more double initialization. Your two logs showed « Connected to Plex server » twice: saving the config while the connection started launched a second polling loop and a second WebSocket. Fixed.
  • :clipboard: Logs now indicate the result of each command, and warn when a player does not announce the playback capability.

@GBoulvin — for webhooks: good news, no need for Plex Pass here! The integration already listens to the server’s real-time WebSocket (/:/websockets/notifications), so play/pause/stop changes are reported in less than a second. The 10s polling is just a safety net if the socket drops. If you still see latency on Plexamp, let me know with a log in LOG_LEVEL=debug, I’m interested. And curious to know if Plexamp control responds in 1.0.1 :crossed_fingers:

@spenceur — let me know if your buttons respond now. If Plex still refuses some commands, the error displayed in Gladys will tell me exactly what to dig into. And if you can specify what was displayed « instead of the push button », I’ll take a look.

No change for me :slight_smile:

[2026-08-16T14:13:24.558Z] [INFO] Starting the Plex integration...
[2026-08-16T14:13:24.870Z] [INFO] [gladys-sdk] connected to Gladys (http://172.30.0.1:8455)
[2026-08-16T14:13:24.898Z] [INFO] [plex-monitor] Connected to Plex server "DiskStation" (v1.43.2.10687-563d026ea)
[2026-08-16T14:13:25.353Z] [INFO] [plex-notifications] Connected to the Plex notification socket
[2026-08-16T16:27:40.274Z] [INFO] [plex-monitor] New Plex player discovered: S26 Ultra de 
[2026-08-16T16:27:59.153Z] [INFO] onDeviceCreated <- ext:ext-guim31-gladys-plex:player:cxus6yubstmxb3mw0sr8if7b
[2026-08-16T16:30:35.319Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:cxus6yubstmxb3mw0sr8if7b:mute = 1
[2026-08-16T16:30:35.320Z] [WARN] [plex-monitor] Player cxus6yubstmxb3mw0sr8if7b does not advertise the "playback" capability; trying anyway (enable "Advertise as player" in its Plex app if nothing happens)
[2026-08-16T16:30:42.329Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:cxus6yubstmxb3mw0sr8if7b:volume = 21
[2026-08-16T16:30:42.329Z] [WARN] [plex-monitor] Player cxus6yubstmxb3mw0sr8if7b does not advertise the "playback" capability; trying anyway (enable "Advertise as player" in its Plex app if nothing happens)
[2026-08-16T16:30:45.383Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:cxus6yubstmxb3mw0sr8if7b:volume = 76
[2026-08-16T16:30:45.383Z] [WARN] [plex-monitor] Player cxus6yubstmxb3mw0sr8if7b does not advertise the "playback" capability; trying anyway (enable "Advertise as player" in its Plex app if nothing happens)
[2026-08-16T16:30:50.571Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:cxus6yubstmxb3mw0sr8if7b:volume = 37
[2026-08-16T16:30:50.571Z] [WARN] [plex-monitor] Player cxus6yubstmxb3mw0sr8if7b does not advertise the "playback" capability; trying anyway (enable "Advertise as player" in its Plex app if nothing happens)
[2026-08-16T16:30:51.264Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:cxus6yubstmxb3mw0sr8if7b:volume = 5
[2026-08-16T16:30:51.264Z] [WARN] [plex-monitor] Player cxus6yubstmxb3mw0sr8if7b does not advertise the "playback" capability; trying anyway (enable "Advertise as player" in its Plex app if nothing happens)
[2026-08-16T16:30:57.906Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:cxus6yubstmxb3mw0sr8if7b:rewind = 1
[2026-08-16T16:30:57.907Z] [WARN] [plex-monitor] Player cxus6yubstmxb3mw0sr8if7b does not advertise the "playback" capability; trying anyway (enable "Advertise as player" in its Plex app if nothing happens)
[2026-08-16T16:31:00.900Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:cxus6yubstmxb3mw0sr8if7b:forward = 1
[2026-08-16T16:31:00.900Z] [WARN] [plex-monitor] Player cxus6yubstmxb3mw0sr8if7b does not advertise the "playback" capability; trying anyway (enable "Advertise as player" in its Plex app if nothing happens)
[2026-08-16T16:31:04.059Z] [INFO] onSetValue <- ext:ext-guim31-gladys-plex:player:cxus6yubstmxb3mw0sr8if7b:stop = 1
[2026-08-16T16:31:04.060Z] [WARN] [plex-monitor] Player cxus6yubstmxb3mw0sr8if7b does not advertise the "playback" capability; trying anyway (enable "Advertise as player" in its Plex app if nothing happens)
[2026-08-16T16:31:04.100Z] [INFO] [plex-monitor] Session of cxus6yubstmxb3mw0sr8if7b terminated server-side (stop fallback)

Plex v1.0.3 — thanks for the logs, a lot has changed :rocket:

Hi everyone :waving_hand:

Big bug-fixing session since the Plex integration release, almost entirely thanks to @GBoulvin and @spenceur who sent me golden logs :folded_hands: We went from 1.0.0 to 1.0.3. Here’s a quick recap of what changed.

The big change: player control

The symptom you both had: no button worked, except Stop.

Two stacked errors on my side:

  1. To know if a player was controllable, I relied on the /clients endpoint of the Plex server. This is the old discovery mechanism (GDM), and it’s empty on most modern servers. Result: Plexamp, Plex Web, and mobile apps were rejected before any command was even sent.
  2. Once this blockage was removed, commands finally went out… but the Plex server itself refused to relay them to these players. A log from @spenceur proved it: 41 ms between the command and the fallback to Stop, so immediate failure. I was always knocking on the only closed door :person_facepalming:

What 1.0.3 does: the integration now tries two paths before giving up — via the server (which works for TV apps, boxes, and consoles), then directly to the player at its local address, the path Plex uses when you « cast Â». The responding path is remembered, so subsequent commands go to the right place on the first try.

Other fixes

  • :muted_speaker: The Mute button now toggles properly. Gladys displays it as a push button (which always sends « 1 Â»): my code only knew how to mute, never to unmute.
  • :bar_chart: Sensors now fill up as soon as a device is added. Before, values published before clicking « Add to Gladys Â» were lost, and my deduplication never sent them again. Hence the persistent « No recent value Â».
  • :repeat_button: No more double initialization. Saving the config while the connection started launched a second polling loop and a second WebSocket (visible in your logs with the « Connected to Plex server Â» in duplicate).
  • :stethoscope: Logs are much more talkative in case of failure: they list the error of each attempted path.

A word on the method :robot:

For those interested: the integration was written with Claude Opus 5, then I had Claude Fable 5 review all the code by giving it your feedback as context. And honestly, it was worth it — it found four things the first pass had missed:

  • the direct route used the default port (32500) while /clients provides the exact port of the player, and TV apps often listen on 3005;
  • for a stream watched outside the home, we tried to reach a public address — unnecessary request and 2 seconds lost on the command budget;
  • in the worst case, the « server try → direct try → fallback Stop Â» chain could exceed the 5 seconds that Gladys allows for command acknowledgment: Stop worked but appeared as a failure;
  • the remembered route was never forgotten in case of failure.

Two AIs, two perspectives, and more robust code. All covered by 53 unit tests now :grinning_face_with_smiling_eyes:

:warning: The limit we can’t bypass

Let’s be honest: a Plex app only accepts remote control if it announces itself as a player. Without this setting, it literally listens to no command — not even the official Plex app can control it.

  • :white_check_mark: TV / box / console: enabled by default, everything works.
  • :warning: Mobile, Plexamp, Plex Web: needs to be enabled manually, usually in **Settings → Remote Control → « Announce as player Â».

The sensors (current title, playback state, remaining time, intro/credits), however, work on all players no matter what.

And now?

Gladys should offer you 1.0.3 directly. If control still doesn’t work for you, send me the line Command ... failed on every route -> ... from your logs: it will tell me exactly where it’s stuck (server refusal, unreachable player, closed port…).

Thanks again, keep breaking my integration, it makes it better :popcorn:

:backhand_index_pointing_right: GitHub - guim31/gladys-plex · GitHub

I’ll take care of it tomorrow on my TV to check :slight_smile:
Nice work

Well, I didn’t really do much, you know ^^ :wink: