# Jellyfin Binding

This is the binding for Jellyfin (opens new window), the volunteer built media solution that puts you in control of your media. This binding allows you to interact with Jellyfin clients that supports remote control. It is compatible and tested with Jellyfin servers from version 10.10.7. Earlier versions use a different API and are not supported.

# Binding - Configuration

Parameters to fine-tune server discovery. For most users the default configuration will work.

Parameter Description Value
discoveryPort Port used to query servers on local network(s) 0 - 65535
discoveryTimeout Maximum amount of time to wait for a response [ms] 500 - 5000

# Discovery

Servers can be discovered using a local network broadcast. This discovery needs to be triggered manually and is designed for local networks. Broadcasts typically do not traverse subnets or VLANs without specific network configurations. If your Jellyfin servers are on different subnets, auto-discovery will likely not work. In this case you need to configure the server manually using its IP address or hostname.

Once a Jellyfin server bridge has been added, clients will be detected automatically.

# Thing Types

ThingTypeID Description
server (bridge) Jellyfin server instance
client Jellyfin controllable client instance

# Authentication

To allow the server thing to go online, you must provide a valid access token for the user that the binding will use to interact with the server. Please note that the user should be allowed on the Jellyfin server to remote control devices.

You can generate an access token in the Jellyfin web UI under Dashboard → API Keys.

# Server Thing Configuration

Config Type Description
hostname Text Hostname or IP address of the server (required)
port Integer Port of the server (required)
ssl Boolean Connect through https (required)
path Text Base path of the server
refreshSeconds Integer Interval to pull devices state from the server
token Text The user access token

# Advanced: Client Discovery Filters

These settings are visible under Show advanced in the openHAB UI. They only affect which Jellyfin clients appear in the openHAB Inbox; already-discovered things are not removed.

The client category is determined by the application name reported by the Jellyfin client to the server.

Config Type Default Description
discoverWebClients Boolean false Discover Jellyfin Web clients (e.g., Jellyfin Web)
discoverAndroidClients Boolean true Discover Jellyfin Android clients (e.g., Jellyfin for Android)
discoverAndroidTvClients Boolean true Discover Jellyfin Android TV clients (e.g., Jellyfin for Android TV)
discoverIosClients Boolean true Discover iOS clients (e.g., Jellyfin iOS, Swiftfin, Infuse)
discoverKodiClients Boolean true Discover Kodi clients (e.g., JellyCon, Jellyfin for Kodi)
discoverRokuClients Boolean true Discover Roku clients (e.g., Jellyfin for Roku)
discoverOtherClients Boolean true Discover third-party clients not matched by any category above

# WebSocket Real-Time Updates

The binding automatically uses WebSocket connections to receive real-time updates from the Jellyfin server. This provides instant notifications when media playback state changes, with automatic fallback to polling if WebSocket fails.

WebSocket Connection Behavior:

  • Automatic connection: WebSocket is always used when available (no configuration needed)
  • Automatic reconnection: If the WebSocket connection is lost, the binding automatically attempts to reconnect
  • Exponential backoff: Reconnection attempts use increasing delays: 1s → 2s → 4s → 8s → 16s → 32s → 60s (capped)
  • Maximum retries: After 10 failed reconnection attempts, the binding falls back to polling mode
  • Seamless fallback: When WebSocket fails permanently, the binding automatically switches to periodic polling (using refreshSeconds interval)

WebSocket connections require network connectivity and may not work correctly if:

  • Your Jellyfin server is behind a reverse proxy that doesn't support WebSocket upgrades
  • Network firewalls block WebSocket connections
  • The server is temporarily unreachable

In these cases, the automatic fallback to polling ensures the binding continues to function.

# Client Thing Configuration

Config Type Required Description
serialNumber Text Yes The Jellyfin device ID as reported by the client application.

# Advanced — Now Playing Images

These settings are visible under Show advanced in the openHAB UI. Each image type can be enabled independently. All types are disabled by default because image downloads add network load on every session update (every 30 seconds by default).

When enabled, a dynamic Image channel is created automatically with the channel ID playing-item-image-<type> (lowercase type name).

Config Type Default Description
imagePrimaryEnabled Boolean false Enable download of the primary cover art (album cover, movie poster)
imagePrimaryWidth Integer 512 Maximum width in pixels for the primary image (128/256/512/1024)
imageBackdropEnabled Boolean false Enable download of the background fanart / backdrop image
imageBackdropWidth Integer 512 Maximum width in pixels for the backdrop image (128/256/512/1024)
imageLogoEnabled Boolean false Enable download of the transparent text or graphical logo
imageLogoWidth Integer 512 Maximum width in pixels for the logo image (128/256/512/1024)
imageThumbEnabled Boolean false Enable download of the landscape thumbnail (wide-format still)
imageThumbWidth Integer 512 Maximum width in pixels for the thumb image (128/256/512/1024)
imageDiscEnabled Boolean false Enable download of the CD, DVD or Blu-ray disc artwork
imageDiscWidth Integer 512 Maximum width in pixels for the disc image (128/256/512/1024)
imageArtEnabled Boolean false Enable download of the ClearArt transparent promotional artwork
imageArtWidth Integer 512 Maximum width in pixels for the art image (128/256/512/1024)
imageBannerEnabled Boolean false Enable download of the wide horizontal banner (TheTVDB-style)
imageBannerWidth Integer 512 Maximum width in pixels for the banner image (128/256/512/1024)

# Channels

channel Type Description
send-notification String Display message in client
media-control Player Control media playback: play, pause, next, previous, fast-forward, rewind (standard openHAB Player channel)
media-stop Switch Stop playback: send ON to stop (complements media-control which doesn't have native stop command)
media-shuffle Switch Control shuffle mode (ON=random order, OFF=sequential order)
media-repeat String Control repeat mode (off=play once, one=repeat item, all=repeat queue)
media-quality Number Set maximum streaming bitrate in Kbps (140-8000)
media-audio-track Number Select audio track by zero-based index
media-subtitle Number Select subtitle stream by index (-1=disable, 0+=track selection)
playing-item-id String Id of the item currently playing (readonly)
playing-item-name String Name of the item currently playing (readonly)
playing-item-series-name String Name of the item's series currently playing, only have value when item is an episode (readonly)
playing-item-season-name String Name of the item's season currently playing, only have value when item is an episode (readonly)
playing-item-season Number Number of the item's season currently playing, only have value when item is an episode (readonly)
playing-item-episode Number Number of the episode item currently playing, only have value when item is an episode (readonly)
playing-item-genders String Comma-separated list of the item's genres currently playing (readonly)
playing-item-type String Type of the item currently playing (readonly)
playing-item-percentage Dimmer Played percentage for the item currently playing, allow seek
playing-item-second Number Current second for the item currently playing, allow seek
playing-item-total-seconds Number Total seconds for the item currently playing (readonly)
play-by-terms String Play media by terms, works for series, episodes and movies; terms search is explained bellow
play-next-by-terms String Add to playback queue as next by terms, works for series, episodes and movies; terms search is explained bellow
play-last-by-terms String Add to playback queue as last by terms, works for series, episodes and movies; terms search is explained bellow
browse-by-terms String Browse media by terms, works for series, episodes and movies; terms search is explained bellow
play-by-id String Play media by id, works for series, episodes and movies; id search is explained bellow
play-next-by-id String Add to playback queue as next by id, works for series, episodes and movies
play-last-by-id String Add to playback queue as last by id, works for series, episodes and movies
browse-by-id String Browse media by id, works for series, episodes and movies

# Image Channels (Dynamic)

Image channels are dynamic — they appear only when the corresponding image type is enabled in the client thing configuration (under Show advanced → Now Playing Images).

When enabled, a channel of type Image is created automatically with the pattern playing-item-image-<type>.

Channel ID Item Type Description
playing-item-image-primary Image Primary cover art (album cover, movie poster, or main thumbnail)
playing-item-image-backdrop Image Background fanart / backdrop (wide full-resolution scene image)
playing-item-image-logo Image Transparent text or graphical logo
playing-item-image-thumb Image Landscape thumbnail (wide-format still or episode preview)
playing-item-image-disc Image CD, DVD or Blu-ray disc artwork
playing-item-image-art Image ClearArt — transparent promotional artwork
playing-item-image-banner Image Wide horizontal banner (TheTVDB-style)

State values:

  • JPEG image data — image fetched successfully from the Jellyfin server
  • NULL — no item is currently playing, or the image type is not available for the current item
  • UNDEF — temporary network error while fetching the image; will retry on the next session update

The terms search has a default behavior that can be modified by sending some predefined prefixes.

The default behavior is to search for movies, series, or episodes whose name starts with the given text. If it finds results the binding will proceed as described above. If the result is a series, the binding will try to resume some episode. If not, it will look for the next episode to watch and finally will fall back to the first episode.

You can prefix your search with <type:movie>, <type:episode>, <type:series> to limit your search to a specific type.

You can also search for a specific series episode by season and episode number by prefixing your search with <season:1><episode:1> with the desired values. So <season:3><episode:10>Something will try to play episode 10 of season 3 of the series called Something.

# Known Limitations

This binding has been tested with an Android TV client and the web client. The only issue that was found is that the play-next-by-terms and play-last-by-terms channels currently don't work on the Android TV client.

Before opening an issue, please test that you are able to control your device correctly from the Jellyfin web UI to determine if it is a client-side issue.

# Troubleshooting

# WebSocket Connection Issues

If you experience issues with real-time updates or see repeated connection attempts in the logs:

Check the logs for WebSocket-related messages:

INFO: WebSocket connection established
WARN: WebSocket connection failed, attempt X/10, retrying in Ys
INFO: WebSocket max retries exceeded, falling back to polling

Common solutions:

  1. Reverse proxy configuration: If your Jellyfin server is behind a reverse proxy (nginx, Apache, Caddy), ensure WebSocket upgrades are properly configured:

    • nginx: Add proxy_set_header Upgrade $http_upgrade; and proxy_set_header Connection "upgrade";
    • Apache: Enable mod_proxy_wstunnel
    • Caddy: WebSocket support is enabled by default
  2. Firewall rules: Ensure WebSocket connections (typically on the same port as HTTP/HTTPS) are not blocked

  3. Server compatibility: Verify your Jellyfin server version is 10.10.7 or newer

  4. Automatic fallback: If WebSocket connections fail, the binding automatically falls back to polling using refreshSeconds interval

# Delayed Updates

If you notice delayed state updates:

  • Check refreshSeconds: Lower values mean more frequent polling (minimum recommended: 5 seconds)
  • Verify WebSocket status: Check logs to confirm WebSocket is connected (not in fallback mode)
  • Network latency: High network latency between openHAB and Jellyfin may cause delays

# Full Example

# Example Server (Bridge) - jellyfin_bridge.things

Bridge jellyfin:server:exampleServerId "Jellyfin Server" [
    hostname="192.168.1.177",
    port=8096,
    refreshSeconds=30,
    ssl="false"
    token=XXXXX # Optional, read below
    userId=XXXXX # Optional, read below
]

The token can be obtained from the Jellyfin web UI under Dashboard → API Keys.

# Example Client - jellyfin_clients.things

Thing jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID> "Jellyfin Web client"     (jellyfin:server:exampleServerId)
Thing jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID> "Jellyfin Android client" (jellyfin:server:exampleServerId)

It is recommended to create clients using discovery. To get the device ids manually, it is possible to use the Jellyfin web interface with the web inspector and look for the request that is launched when you click the cast button (<jellyfin url>/Sessions?ControllableByUserId=XXXXXXXXXXXX).

# Example Items - jellyfin.items

String strJellyfinAndroidSendNotification      { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:send-notification" }
Player plJellyfinAndroidMediaControl           { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:media-control" }
String strJellyfinAndroidPlayingItemId         { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-id" }
String strJellyfinAndroidPlayingItemName       { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-name" }
String strJellyfinAndroidPlayingItemSeriesName { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-series-name" }
String strJellyfinAndroidPlayingItemSeasonName { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-season-name" }
Number nJellyfinAndroidPlayingItemSeason       { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-season" }
Number nJellyfinAndroidPlayingItemEpisode      { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-episode" }
String strJellyfinAndroidPlayingItemGenders    { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-genders" }
String strJellyfinAndroidPlayingItemType       { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-type" }
Dimmer dJellyfinAndroidPlayingItemPercentage   { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-percentage" }
Number nJellyfinAndroidPlayingItemSecond       { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-second" }
Number nJellyfinAndroidPlayingItemTotalSeconds { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-total-seconds" }
String strJellyfinAndroidPlayByTerms           { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:play-by-terms" }
String strJellyfinAndroidPlayByNextTerms       { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:play-next-by-terms" }
String strJellyfinAndroidPlayByLastTerms       { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:play-last-by-terms" }
String strJellyfinAndroidBrowseByTerms         { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:browse-by-terms" }

# Example Image Items (requires image types to be enabled in thing config)

// Enable imagePrimaryEnabled=true in the client thing configuration to create these channels.
Image imgJellyfinPrimary  { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-image-primary" }
Image imgJellyfinBackdrop { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-image-backdrop" }
Image imgJellyfinLogo     { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-image-logo" }
Image imgJellyfinThumb    { channel="jellyfin:client:exampleServerId:<JELLYFIN_DEVICE_ID>:playing-item-image-thumb" }