External integration - Jellyfin / Emby

Hi everyone :waving_hand:

As announced in the topic of Home Assistant integrations to port, here is Jellyfin & Emby: a single integration for both servers (Jellyfin is a fork of Emby, the API is common), which automatically detects which server it is communicating with. @AlexTrovato, this is your request from August :wink:

[screenshot of the dashboard]

What it does

One device per player (TV app, phone, browser):

  • :play_button: play, pause, stop, previous, next, rewind and fast forward, volume, mute
  • :musical_note: the playback state, compatible with the Music widget on the dashboard
  • :label: the current title and remaining time
  • :sparkles: « during the intro Â» and « during the credits Â»: under Jellyfin 10.10+ with a segments plugin (Chapter Segments Provider, Intro Skipper
), under Emby with its intro detection

One server device: current plays, transcodes, a summary of « who is watching what Â» and a counter per library.

:bullseye: Scenes

Four triggers, Playback started / paused / resumed / stopped, filterable by player and media type (movie, episode, music, live TV
):

:clapper_board: A movie starts on the living room TV → dim the lights
:pause_button: Pause → turn them back on

And two scene actions:

  • :bell: Display a message on a player: « Someone is at the door Â» over the movie
  • :popcorn: Play a media on a player: search for a title in the library (movie, series, album, artist, playlist) and play it, randomly if needed

:framed_picture: Widgets

  • Now playing: who is watching what, where, with the posters
  • Player: the current playback in remote control (background image, title, remaining time, buttons). Blank setting = it follows what is playing; or choose a specific player
  • Recently added: the posters of the latest movies, series or albums, the new episodes grouped by series

Installation

:warning: Gladys 5.1 minimum.

  1. Create an API key for Gladys: under Jellyfin, Dashboard → API Keys; under Emby, Settings → Advanced → API Keys
  2. In Gladys: Integrations → Multimedia → Jellyfin & Emby
  3. Enter the server URL (http://server-ip:8096, or your https address) and the key, then Test the connection
  4. Discovery tab: add the server and your players

A player only appears when it is connected to the server: open the app on the TV, then click on « Search for players Â».

What I would like you to test :folded_hands:

I tested it on Jellyfin 10.11 and 12.1 and on Emby 4.10, with a simulated player. I am missing real conditions:

  • your TV apps (Android TV, Fire TV, LG, Samsung
): the buttons, the volume, the on-screen message
  • Emby: everything, and especially the intro and the credits
  • a server behind a reverse proxy: if the WebSocket does not pass, the integration falls back to a query every 15 s (let me know if this is the case, the logs report it)

In case of trouble, the integration logs, visible in Gladys, help me a lot.

This is a 0.2.0: the 1.0 will come with your feedback. Code, FR/EN doc and tests: GitHub - guim31/gladys-jellyfin · GitHub

Hi and thanks :television:

Tested with my Jellyfin server behind a proxy (but the websocket works) :white_check_mark:
Devices discovered and added successfully.
The widgets display the players/playbacks in short and the latest additions :star_struck:
Actions and triggers work except the one to send a message (tested with the official iPhone client and the official Apple TV).
The Pause/Play and Stop functions work on the widget (but with a few seconds of latency on the state return). However, nothing at all with the next button.

Here are my logs :

[2026-09-27T20:31:16.413Z] [INFO] Starting the Jellyfin & Emby integration v0.2.0...
[2026-09-27T20:31:17.027Z] [INFO] [gladys-sdk] connected to Gladys (http://172.30.0.1:80)
[2026-09-27T20:31:17.119Z] [INFO] Waiting for the configuration (server URL + API key)
[2026-09-27T20:32:03.208Z] [INFO] onConfigUpdated -> new configuration received
[2026-09-27T20:32:03.401Z] [INFO] [media-monitor] Connected to Jellyfin server "99b9829bee05" (v12.1.0)
[2026-09-27T20:32:03.478Z] [INFO] [media-monitor] New player discovered: Firefox (Jellyfin Web)
[2026-09-27T20:32:03.871Z] [INFO] [media-socket] Real-time socket connected
[2026-09-27T20:32:07.675Z] [INFO] [media-monitor] Connected to Jellyfin server "99b9829bee05" (v12.1.0)
[2026-09-27T20:32:07.694Z] [INFO] [media-monitor] New player discovered: Firefox (Jellyfin Web)
[2026-09-27T20:32:39.225Z] [INFO] [media-monitor] New player discovered: Cyril's iPhone (Jellyfin iOS)
[2026-09-27T20:32:39.382Z] [INFO] [media-monitor] Scene event playback_started: Severance - S01E02 - Half Loop on Cyril's iPhone
[2026-09-27T20:32:50.765Z] [INFO] onDeviceCreated <- ext:ext-guim31-gladys-jellyfin:player:62eff0df731b02bf
[2026-09-27T20:32:52.309Z] [INFO] onDeviceCreated <- ext:ext-guim31-gladys-jellyfin:server:76b6e7325e104d378c17f1432a1a0dde
[2026-09-27T20:35:20.643Z] [INFO] onSetValue <- ext:ext-guim31-gladys-jellyfin:player:62eff0df731b02bf:pause = 1
[2026-09-27T20:35:20.731Z] [INFO] [media-monitor] Command pause sent to Cyril's iPhone
[2026-09-27T20:35:29.191Z] [INFO] onSetValue <- ext:ext-guim31-gladys-jellyfin:player:62eff0df731b02bf:pause = 1
[2026-09-27T20:35:29.243Z] [INFO] [media-monitor] Command pause sent to Cyril's iPhone
[2026-09-27T20:35:35.099Z] [INFO] onSetValue <- ext:ext-guim31-gladys-jellyfin:player:62eff0df731b02bf:stop = 1
[2026-09-27T20:35:35.176Z] [INFO] [media-monitor] Command stop sent to Cyril's iPhone
[2026-09-27T20:35:50.401Z] [INFO] onSetValue <- ext:ext-guim31-gladys-jellyfin:player:62eff0df731b02bf:pause = 1
[2026-09-27T20:35:50.479Z] [INFO] [media-monitor] Command pause sent to Cyril's iPhone
[2026-09-27T20:37:57.838Z] [INFO] [media-monitor] Message displayed on Cyril's iPhone
[2026-09-27T20:38:27.762Z] [INFO] [media-monitor] Playing "Moana (2016)" on Cyril's iPhone
[2026-09-27T20:38:31.917Z] [INFO] [media-monitor] Playing "Moana (2016)" on Cyril's iPhone
[2026-09-27T20:39:26.866Z] [INFO] [media-monitor] Scene event playback_paused: Severance - S01E02 - Half Loop on Cyril's iPhone
[2026-09-27T20:39:30.246Z] [INFO] [media-monitor] New player discovered: AppleTV (Swiftfin tvOS)
[2026-09-27T20:39:40.014Z] [INFO] [media-monitor] Playing "Moana (2016)" on Cyril's iPhone
[2026-09-27T20:40:11.116Z] [INFO] onDeviceCreated <- ext:ext-guim31-gladys-jellyfin:player:aa7023ad2115e61c
[2026-09-27T20:40:26.749Z] [INFO] [media-monitor] Playing "Severance" on AppleTV
[2026-09-27T20:40:32.684Z] [INFO] [media-monitor] Scene event playback_started: Severance - S01E01 - The Good Half on AppleTV
[2026-09-27T20:41:01.842Z] [INFO] [media-monitor] Scene event playback_paused: Severance - S01E01 - The Good Half on AppleTV
[2026-09-27T20:41:14.032Z] [INFO] [media-monitor] Scene event playback_resumed: Severance - S01E01 - The Good Half on AppleTV
[2026-09-27T20:41:29.032Z] [INFO] onSetValue <- ext:ext-guim31-gladys-jellyfin:player:aa7023ad2115e61c:pause = 1
[2026-09-27T20:41:29.120Z] [INFO] [media-monitor] Command pause sent to AppleTV
[2026-09-27T20:41:31.034Z] [INFO] onSetValue <- ext:ext-guim31-gladys-jellyfin:player:aa7023ad2115e61c:pause = 1
[2026-09-27T20:41:31.042Z] [INFO] [media-monitor] Command pause sent to AppleTV
[2026-09-27T20:41:34.246Z] [INFO] [media-monitor] Scene event playback_paused: Severance - S01E01 - The Good Half on AppleTV
[2026-09-27T20:41:35.699Z] [INFO] onSetValue <- ext:ext-guim31-gladys-jellyfin:player:aa7023ad2115e61c:play = 1
[2026-09-27T20:41:35.709Z] [INFO] [media-monitor] Command play sent to AppleTV
[2026-09-27T20:41:40.846Z] [INFO] [media-monitor] Scene event playback_resumed: Severance - S01E01 - The Good Half on AppleTV
[2026-09-27T20:41:48.766Z] [INFO] onSetValue <- ext:ext-guim31-gladys-jellyfin:player:aa7023ad2115e61c:next = 1
[2026-09-27T20:41:48.843Z] [INFO] [media-monitor] Command next sent to AppleTV
[2026-09-27T20:41:58.735Z] [INFO] onSetValue <- ext:ext-guim31-gladys-jellyfin:player:aa7023ad2115e61c:stop = 1
[2026-09-27T20:41:58.793Z] [INFO] [media-monitor] Command stop sent to AppleTV
[2026-09-27T20:41:58.923Z] [INFO] [media-monitor] Scene event playback_stopped: Severance - S01E01 - The Good Half on AppleTV
[2026-09-27T20:42:11.278Z] [INFO] [media-monitor] Scene event playback_started: Severance - S01E02 - Half Loop on AppleTV
[2026-09-27T20:42:15.261Z] [INFO] onSetValue <- ext:ext-guim31-gladys-jellyfin:player:aa7023ad2115e61c:pause = 1
[2026-09-27T20:42:15.352Z] [INFO] [media-monitor] Command pause sent to AppleTV
[2026-09-27T20:42:20.614Z] [INFO] [media-monitor] Scene event playback_paused: Severance - S01E02 - Half Loop on AppleTV

Great feedback, I’ll check it out tomorrow!

Version 0.2.1 is out, here’s what your feedback led to:

:next_track_button: The Next button: Swiftfin (like Jellyfin for Android TV) only moves to the next item if it has a playback queue, which is not the case for a single episode. Now, on an episode, Next and Previous request the neighboring episode from the server and launch it directly. It works everywhere the « Play media Â» action works, and it worked for you :wink:

:stopwatch: Latency on state: in your logs, the app reports its pause about 5 seconds after the command, and Gladys limits widget refreshes to once every 10 seconds. Two changes: the Player widget buttons now use « widget actions, Â» which Gladys reloads immediately upon press, and the expected state is displayed right away before being confirmed by the app. No more double-tapping :grinning_face_with_smiling_eyes:

:bell: The message: here, it’s not the integration, the server receives the command correctly (« Message displayed Â» in your logs). It’s the application that chooses to display it:

  • Swiftfin doesn’t handle messages yet (it’s literally a TODO in its code :sweat_smile:)
  • the official iOS app doesn’t display it during a video
  • the web client and Jellyfin for Android TV display it correctly

This is now specified in the documentation and in the action description.

Let me know if it’s better on your end!

Next Button :white_check_mark:
Latency :white_check_mark: it’s hyper responsive
Message :white_check_mark: on a Web client

Thanks :handshake:

Well that’s cool :+1: