API & integration¶
SendToKodi has no API of its own: it is a Kodi plugin, so anything that can make Kodi play a plugin:// URL can use
it. That includes Kodi's JSON-RPC interface, playlists, STRM files, other add-ons, Home Assistant and a shell with
curl. This page documents the URL format and shows the common clients.
The plugin URL¶
| Parameter | Required | Meaning |
|---|---|---|
url |
yes | The web page or media URL to resolve, URL-encoded (https:// becomes https%3A%2F%2F). Anything in yt-dlp's list of supported sites works, and direct links to media files play as well. Playlist and channel URLs are expanded into Kodi's playlist. |
yt-dlp-options |
no | A URL-encoded JSON object with yt-dlp options for this request only, for example credentials or extractor arguments. The legacy key ydlOpts is still accepted. See yt-dlp options per request. |
action |
no | queue appends the item to Kodi's playlist instead of playing it. See Queue instead of play. |
title |
with action=queue |
Label of the queued item, URL-encoded. Without it the URL is shown. name is accepted as an alias. |
Legacy form¶
Older integrations put the media URL directly after the ?, without url= and without encoding:
This still works and is what the browser extension sends for Play. It cannot carry other parameters, except for the
old form of yt-dlp options: a space followed by a JSON object {"ydlOpts": {...}}. New integrations should use the
url= form, which survives any characters in the target URL.
JSON-RPC¶
Kodi's JSON-RPC API is reachable over HTTP once Settings → Services → Control →
Allow remote control via HTTP is on. The endpoint is http://<kodi-ip>:8080/jsonrpc with the username and password
from the same settings page as HTTP basic auth. To play a URL, call Player.Open with the plugin URL as the file:
{
"jsonrpc": "2.0",
"method": "Player.Open",
"params": {
"item": {
"file": "plugin://plugin.video.sendtokodi/?url=https%3A%2F%2Fsoundcloud.com%2Fspinnin-deep%2Fsam-feldt-show-me-love-edxs-indian-summer-remix-available-june-1"
}
},
"id": 1
}
With curl:
curl -u kodi:kodi -H 'Content-Type: application/json' http://192.168.0.138:8080/jsonrpc -d '{
"jsonrpc": "2.0", "id": 1, "method": "Player.Open",
"params": {"item": {"file": "plugin://plugin.video.sendtokodi/?url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DTLNdBIRTNM4"}}
}'
Kodi answers {"id":1,"jsonrpc":"2.0","result":"OK"} as soon as it has accepted the item; resolving happens afterwards
inside Kodi, so a failing URL is reported on the Kodi screen and in its log, not in the JSON-RPC response.
Testing with Postman or similar tools¶
- Create a
POSTrequest tohttp://<user>:<password>@<kodi-ip>:8080/jsonrpc. - Set the body type to raw
application/json. - Paste one of the JSON-RPC examples and send.
yt-dlp options per request¶
yt-dlp-options carries a JSON object that is merged into the options yt-dlp runs with, for this request only. Any
option of yt-dlp's Python API is accepted; the names are those of YoutubeDL's options, not the command line flags.
Typical use is a site login:
{
"jsonrpc": "2.0",
"method": "Player.Open",
"params": {
"item": {
"file": "plugin://plugin.video.sendtokodi/?url=https%3A%2F%2Fvk.com%2Fvideo-124136901_456239025&yt-dlp-options=%7B%22username%22%3A%22user%40email.com%22%2C%22password%22%3A%22password%20with%20spaces%22%7D"
}
},
"id": 1
}
Decoded, the yt-dlp-options value is {"username": "user@email.com", "password": "password with spaces"}. Options
that apply to every request belong into the yt-dlp config file instead.
Request options win over the config file, and both win over the add-on's own defaults.
Queue instead of play¶
action=queue adds the item to Kodi's video playlist without interrupting the current playback. If nothing is playing,
the item waits in the playlist until you start it. title sets the label shown in the playlist:
Via JSON-RPC, send it with Player.Open just like a playback request; the add-on recognises the action and queues
instead of playing. From inside Kodi or another add-on, RunPlugin does the same:
xbmc.executebuiltin("RunPlugin(plugin://plugin.video.sendtokodi/?action=queue&url=<urlencoded_stream_url>&title=<urlencoded_title>)")
The queued entry is resolved when it is reached, so queuing is instant and a site that fails to resolve only affects its own entry.
Playlists and STRM files¶
Kodi's own playlists and library accept plugin URLs. An M3U file with website links (playlist-example.m3u in the repository):
#EXTM3U
#EXTINF:1,[Youtube] Booka Shade - Body Language
plugin://plugin.video.sendtokodi/?url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DTLNdBIRTNM4
#EXTINF:2,[Soundcloud] Sam Feldt - Show Me Love
plugin://plugin.video.sendtokodi/?url=https%3A%2F%2Fsoundcloud.com%2Fspinnin-deep%2Fsam-feldt-show-me-love-edxs-indian-summer-remix-available-june-1
A .strm file contains one plugin URL and behaves like a video file in Kodi's library. Combined with an NFO file for
the metadata, website videos can be part of a library section.
From another Kodi add-on¶
Any add-on can hand a URL to SendToKodi. To play it immediately:
import urllib.parse
import xbmc
url = urllib.parse.quote("https://www.youtube.com/watch?v=TLNdBIRTNM4", safe="")
xbmc.executebuiltin("PlayMedia(plugin://plugin.video.sendtokodi/?url={})".format(url))
ActivateWindow(10025, 'plugin://plugin.video.sendtokodi/?url=...', return) is the older form found in existing
add-ons and keeps working. To list a SendToKodi item in your own directory, create a ListItem with the plugin URL as
its path and IsPlayable set to true; Kodi resolves it through SendToKodi when the user selects it.
Home Assistant and other automation¶
Home Assistant's Kodi integration exposes the JSON-RPC API as the
kodi.call_method action, so an automation or a script can send any link to Kodi:
action: kodi.call_method
target:
entity_id: media_player.kodi_living_room
data:
method: Player.Open
item:
file: "plugin://plugin.video.sendtokodi/?url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DTLNdBIRTNM4"
Node-RED, openHAB, ioBroker and similar systems have Kodi nodes or bindings that send JSON-RPC in the same way. Any
HTTP client works as well, as the curl example above shows.
Behaviour to rely on¶
- Resolving is asynchronous. JSON-RPC returns before the URL is resolved. Watch Kodi's player state
(
Player.GetActivePlayers) or its notifications to know whether playback started. - Playlists expand lazily. A playlist URL adds all entries at once but resolves each entry when it is played.
- Errors show on screen. A failed resolve shows Could not resolve the url in Kodi and writes the yt-dlp traceback to Kodi's log. There is no error channel back to the sender.
- Encoding matters. In the
url=form, encode the target URL completely (urllib.parse.quote(url, safe="")in Python,encodeURIComponentin JavaScript). An unencoded&in the target URL would be read as a plugin parameter.