Skip to main content

Jellyfin Media Server

Control playback on Jellyfin clients and read what is currently playing across a self-hosted Jellyfin media server. Jellyfin is the free, open-source media system — a community fork of Emby and a drop-in alternative to Plex — so this driver is the path for sites that run their own library instead of a cloud service.

One Jellyfin server is the GEM device. Each GEM zone maps to one Jellyfin client (a player app: Apple TV, Android TV, Fire TV, the web/desktop app, a Kodi/MPV add-on, etc.) addressed by that client's stable DeviceId. Playback commands (play, pause, stop, skip, seek, volume, mute) are issued to the client's live session; a background poll of /Sessions keeps each zone's state and now_playing in sync.

Authentication is a single API key minted from the Jellyfin dashboard — no OAuth, no cloud round-trip. Everything happens on the LAN.

Prerequisites

  • Jellyfin server 10.8 or newer running on the LAN and reachable from the GEM server (default port 8096 for HTTP, 8920 for HTTPS).
  • An API key. In the Jellyfin web UI: Dashboard → Advanced → API Keys → (+), give it a name such as GEM, and copy the generated key. API keys carry server-wide privileges — treat the value like a password.
  • Every client you want to control must be signed in to the same server and support remote control. A client advertises this as SupportsRemoteControl in its session entry; most native apps do, some third-party TV apps do not.

Setup steps

  1. Go to Devices → Add Device, choose the Jellyfin Media Server driver.
  2. Enter the server IP / Host and paste the API key into the API Key field. Leave Port at 8096 (or 8920 with Protocol set to https if you terminate TLS on the server itself).
  3. Save, then run the get_sessions command on the device. This returns the clients currently connected, each with a DeviceId, DeviceName, and Client string.
  4. For each player you want to automate, create a zone and set the zone Address to that client's DeviceId.
Zones are not created automatically

get_sessions enumerates clients so you can copy their DeviceId, but it does not create zones. Add a zone per client yourself and paste the id into the zone Address field. This keeps you in control of which players become automatable targets.

Attributes

Device

AttributeTypeRequiredDescription
ipstringyesLAN IP or hostname of the Jellyfin server.
tokenstring (secure)yesJellyfin API key from Dashboard → Advanced → API Keys. Stored encrypted.
portintnoServer port. Default 8096 (HTTP); use 8920 for HTTPS.
protocolstringnohttp (LAN, default) or https (TLS terminated on the server).
status_intervalintnoHow often /Sessions is polled, in milliseconds. Default 5000, minimum 1000.
client_idstring (read-only)noAuto-generated stable id sent as DeviceId in the authorization header — this is how GEM appears in the server's Devices list. The driver sets it on first connect; you do not edit it.

Zone

Zones need no attributes beyond the Address (see below). The driver writes these read-only state attributes onto each zone as it polls:

AttributeMeaning
stateplaying, paused, idle (connected, nothing playing), or offline (client not connected).
now_playingFormatted title of the current item (series — season — episode, or artist — track).
media_typeJellyfin item type: Movie, Episode, Audio, MusicVideo, Video, …
volumeClient volume 0–100, when the client reports it.
mutedBoolean mute state, when the client reports it.

Zone address format

The zone Address is the Jellyfin client DeviceId — a stable identifier per player device (unlike the per-connection session Id, which changes each time the app reconnects). Run get_sessions on the device to list live clients and their DeviceId values.

Commands

CommandArgsNotes
playaddressResume (unpause) the client.
pauseaddressPause the client.
play_pauseaddressToggle play/pause.
stopaddressStop playback.
skip_nextaddressNext track / next item.
skip_previousaddressPrevious track / previous item.
seekaddress, offsetSeek to an absolute position in milliseconds; converted to Jellyfin 100-ns ticks on the wire.
set_volumeaddress, levelSet client volume 0–100. Only clients advertising SetVolume honour it.
mute / unmuteaddressMute / unmute the client (capability-dependent).
send_messageaddress, text, headerDisplay an on-screen message on the client (default header GEM).
get_sessionsList active client sessions and their DeviceId.
get_server_infoRead the server identity / version document.

Known limitations

  • Clients must be connected. A player only appears in /Sessions while its app is open and connected. A closed or backgrounded app drops off the list, and the driver reports state=offline for that zone until it returns.
  • Volume / mute are advisory. Jellyfin forwards SetVolume/Mute only to clients that implement them. Many smart-TV apps ignore volume control; use the display's own driver (CEC, IP, or IR) for guaranteed volume in those rooms.
  • No library browsing / "play this title" yet. This release covers transport control and now-playing reporting. Queuing specific items by id (POST /Sessions/{id}/Playing?ItemIds=…) is not wired up; it is a natural follow-up once library-search commands are added.
  • One server per device. Multi-server setups need one GEM device per Jellyfin server.

Troubleshooting

SymptomCheck
401 Unauthorized on every requestThe API key was deleted or mistyped. Re-create it in Dashboard → Advanced → API Keys and update the token attribute.
get_sessions returns an empty arrayNo client apps are currently connected. Open a Jellyfin player so it registers a session, then retry.
Command returns "client not currently connected"The DeviceId in the zone Address is not in the live session list. Confirm the player is open and re-run get_sessions to verify the id.
Commands ack but nothing happens on screenThe target client does not advertise SupportsRemoteControl (visible in the get_sessions output). Some third-party apps cannot be remote-controlled.
Connection flaps / timeoutsConfirm the server IP and port, and that protocol matches how the server is actually exposed (http vs https). A reverse proxy in front of Jellyfin may rewrite paths — point the driver at the server directly.
  • Devices
  • Zones
  • Plex Media Server — the same integration pattern for a Plex library.