# Kino plugins > How to write, test and publish a video-source plugin for Kino, an Android video app for phones and TVs. A plugin is a public GitHub repository (or, from Kino 0.9.50, any public https URL of its manifest) with a JSON manifest (kino-plugin.json) and one JavaScript ES module (plugin.js) that Kino runs in a QuickJS sandbox; it exports async functions (search, home, browse, episodes, resolve, and liveCategories/liveChannels/guide/liveSearch for live TV) that return plain JSON Kino validates strictly. apiVersion 1 to 7; apiVersion 6 = Kino 0.9.50, apiVersion 7 (tracking and segments) = Kino 0.9.51; Kino 0.9.53 adds kino.meta and kino.tmdb with no new apiVersion (feature-detect them). A Node kit (sdk/) runs and validates plugins locally. Everything a person reads in Kino is Spanish (Bogotá, tuteo). The guide exists in Spanish (default, site root) and English (/en/); the English pages are the ones below. For one-shot context, read llms-full.txt: every English page, AGENTS.md, contract.json and kino.d.ts in one file. ## Start here - [AGENTS.md](https://kinotvapp.github.io/kino-plugins/AGENTS.md): instructions for AI assistants building a Kino plugin (workflow, hard rules with exact limits, checklist, common mistakes) - [llms-full.txt](https://kinotvapp.github.io/kino-plugins/llms-full.txt): the complete guide as one text file - [Home](https://kinotvapp.github.io/kino-plugins/en/): what a plugin is, how people install it (owner/repo, a kino-plugin.json URL on GitHub/raw/jsDelivr, or any public https manifest URL: no sealed secrets, unsigned, not in community search), the 5-minute path - [A first plugin](https://kinotvapp.github.io/kino-plugins/en/first-plugin/): a two-file plugin and where the sdk/ kit comes from - [Get listed in Kino](https://kinotvapp.github.io/kino-plugins/en/listed/): the five steps to show in the app's "De la comunidad" list (public, not a fork, valid manifest with a Spanish name/description, topic kino-plugin, stars/top 30), timing and how to check ## Guide - [Signed plugins](https://kinotvapp.github.io/kino-plugins/en/signed/): optional apiVersion 5 author signature (Kino 0.9.45+): what it is, why it matters (trust on first use, "Firmado por su autor"), `node sdk/seal.mjs --keygen` / `--sign`, what the signature covers (sign again after every change), keeping the private key out of the repository, what happens if it is lost, error messages - [What's new](https://kinotvapp.github.io/kino-plugins/en/changelog/): what changed for plugin authors by Kino version (0.9.53: kino.meta asks Kino about a title, kino.tmdb is TMDB with no key in the plugin: Kino's own key first behind its cache and limits, the person's key as the fallback, no_tmdb_key only with no key at all; 0.9.45; 0.9.46-0.9.49: a leading "./" in entry/icon is only tolerated from 0.9.46 -- always write "plugin.js"; 0.9.50 = apiVersion 6: typed/larger sealed secrets, migrate, request-signed streams, settings form, debug, telemetry, section/categories/theme, scopedSearch, kino.error userMessage, adult entries, channels in Home rows, kino.crypto key pairs, the hidden browser (browser: true for kino.browser.capture, browser: "pages" adds kino.browser.page), Stream.label and labelled lazy copies, meta, Stream.alternatives, the subtitles export, Stream.skip, the manifest's categories field, telemetry-only log lines, genre on rows/live categories/playlists, playlist streamHeaders, catchable synchronous kino.* failures, the one-time plugin update pass after a Kino upgrade; also manifest-URL installs, liveSearch, live paging past 10 pages) - [The manifest](https://kinotvapp.github.io/kino-plugins/en/manifest/): every field of kino-plugin.json (entry/icon never start with "./"; hosts have no maximum from Kino 0.9.45; the signature field; categories, browser, debug, telemetry, section, theme; capabilities migrate, scopedSearch, meta and subtitles; reserved ids), settings (incl. list and the apiVersion 6 section/status/action types), streamHosts "any", sealed secrets (seal.mjs; typed cipher keys and 8 KB values at apiVersion 6), the person's own servers, insecureHttp, declarative downloads - [The contract](https://kinotvapp.github.io/kino-plugins/en/contract/): exported functions, arguments, returned shapes, validation rules, Stream rules (alternatives, label, skip, signing), labelled lazy copies ({ label, ref } resolved through resolve(ref) only when picked or reached by the fallback), subtitles for any title, meta (describing other titles), scoped search inside "Ver más" (scopedSearch, within), asking about a forgotten host, the broad video permission, typed errors and kino.error's userMessage with its safety rules, 18+ content (adult) behind the person's PIN - [The kino API](https://kinotvapp.github.io/kino-plugins/en/kino-api/): kino.fetch (request budget, host questions during resolve/episodes), cookies, kino.secret, crypto (incl. apiVersion 6 key pairs: generateKeyPair, sign, verify, importKey, deriveSharedSecret, with a Node/WebCrypto mapping), kino.browser (pointer to Hidden browser), kino.meta (Kino 0.9.53: Kino's TMDB/AniList/meta-plugin answer about a title, no key in the plugin, 30/min, null when unknown), kino.tmdb (Kino 0.9.53: read-only TMDB v3 with the PERSON's own key, never Kino's -- Ajustes key, else a consented Stremio addon's key, else no_tmdb_key with Kino's userMessage; allowlisted paths, 40 per 10 s, 10-min cache, no hosts entry needed), sleep, error (userMessage), config, html.select, storage, log (logcat tags, telemetry, kino.log.report), rank - [Live channels](https://kinotvapp.github.io/kino-plugins/en/live-channels/): live items (in Home rows from apiVersion 6), the channels capability, M3U/XMLTV playlists, guide, liveSearch (searching a big catalog; 18+ marks on hits) and load-more paging, adult categories/channels, liveStreamHosts, three recipes - [Customize your plugin](https://kinotvapp.github.io/kino-plugins/en/customize/): one table of everything a plugin can change in how Kino shows it (name, icon, color, marketplace chips, settings tab, status lines and buttons, theme colors, own section with tabs and hero, Categorías tiles, Home rows with genre and channels, 18+ marks, Servidor menu labels and lazy copies, skip buttons, audio/subtitle labels, userMessage, subtitles, meta, channels), with short examples and what cannot be changed - [The settings form](https://kinotvapp.github.io/kino-plugins/en/settings-form/): every field type (text, password, url, toggle, select, list, and apiVersion 6 section/status/action) with what kino.config returns, every attribute (key, label, hint, required, default, options, fields, max, confirm) and its limits, defaults when omitted, no conditional fields, password vs sealed secrets; settingsStatus, action with clearSettings, validateSettings, a complete example, each plugin's own Ajustes tab, what syncs to the person's other devices - [Signing every request](https://kinotvapp.github.io/kino-plugins/en/signed-streams/): apiVersion 6 request-signed HLS streams: signing "request", signContext, the sign export and its restricted signing lane (1.5 s, no network/storage), resolve(ref, { retry }) on 409/401/403, alternateHosts failover, casting through the phone - [Hidden browser](https://kinotvapp.github.io/kino-plugins/en/browser/): apiVersion 6 "browser": true or "pages" (red consent line, resolve 75 s): kino.browser.capture (only in a resolve the person started; returns the page's held video requests with headers and cookies to pass on) and kino.browser.page ("pages" only; a page's HTML once the site's automatic check passes by itself; not from categories; every top-level redirect/navigation must stay on the plugin's hosts or the read ends blocked; 20 reads/min; timeoutMs cut to the call's remaining time minus 1.5 s); prefer kino.fetch; safety model (loopback proxy, per-capture credential, pinned vetted IPs, never the home network, one page at a time, wiped cookies); Kino never solves a captcha (blocked); timeouts, errors (blocked, timeout, busy, browser_unavailable, not_allowed, rate_limited), a complete example with labelled lazy copies - [Moving saved titles](https://kinotvapp.github.io/kino-plugins/en/migrate/): apiVersion 6 migrate capability: claim saved library titles, chapters and live favorites Kino can no longer open - [Section, categories and colors](https://kinotvapp.github.io/kino-plugins/en/section-theme/): apiVersion 6 section (own TV sidebar entry / phone chip with tabs, hero, rows), categories (tiles in Categorías), theme (five colors with readability guardrails) - [Logs and telemetry](https://kinotvapp.github.io/kino-plugins/en/diagnostics/): the "Modo debug" switch every plugin has from Kino 0.9.50 ("debug": true only makes it on by default; on-screen errors, Registro page), telemetry true/"verbose" (opt-in error reports with consent; only declared plugins send log lines; a per-device switch comes later), kino.log.report, logcat tags KinoPlugin/ and KinoPlay, playback metrics - [Limits and engine quirks](https://kinotvapp.github.io/kino-plugins/en/engine-limits/): every limit, sandbox lifecycle, missing globals in QuickJS, splitting code across files with esbuild, the unhandled-rejection trap - [Test it locally](https://kinotvapp.github.io/kino-plugins/en/test-locally/): sdk/run.mjs, sdk/validate.mjs, record/replay fixtures, live-channel commands, apiVersion 6 commands (section, categories, theme, settingsStatus, action, validateSettings, migrate, sign, --retry, --within), kino.meta/kino.tmdb in the kit (KINO_META_FIXTURE, KINO_TMDB_KEY, KINO_TMDB_FIXTURE), what Node does not reproduce - [Publishing](https://kinotvapp.github.io/kino-plugins/en/publish/): versions and approvals (startup update check, pending-update badge and error hint), sharing by manifest URL, and every requirement to appear in the community list (topic kino-plugin) - [What people see](https://kinotvapp.github.io/kino-plugins/en/what-people-see/): consent sheet, host dialogs, player messages, statuses, uninstalling, sending to the TV (Chromecast/DLNA), plugins synced across devices, what Kino 0.9.50 does for every plugin (play on the paired TV, new chapters, Para ti) - [Cookbook](https://kinotvapp.github.io/kino-plugins/en/cookbook/): HTML site with login, JSON API with token, the person's own server, a TMDB catalog with kino.tmdb (no key in the plugin, fallback setting on older Kino, no_tmdb_key handled), Widevine, plain http - [Stremio addons](https://kinotvapp.github.io/kino-plugins/en/stremio/): how people install a Stremio addon by its manifest URL (Kino generates a plugin; the address stays in two settings, the configuration part sealed), how catalog/meta/stream/subtitles/addon_catalog and the search/skip extras map to Home rows, En vivo, search and paging (a required genre extra is left out), stream ranking, alternatives ("Opción N" in the Servidor menu), proxyHeaders.request, notWebReady ranked last, what is refused (torrents/P2P/infoHash always, even with debrid; no local streaming server), configurable and configurationRequired addons, 18+ addons behind the 18+ code, collections, catalog redirect discovery, phone-TV sync, limits, the messages people see, and when to write a Kino plugin instead - [Nuvio scrapers](https://kinotvapp.github.io/kino-plugins/en/nuvio/): how Kino installs Nuvio scrapers by converting them (version 1..0, typed search through TMDB, sealed TMDB key), and the limits and globals only converted scrapers get (not for hand-written plugins) - [Claims and plugin takedowns](https://kinotvapp.github.io/kino-plugins/en/claims/): Kino is a player; community plugins are an automatic index (listed, not recommended or promoted; each author is responsible for their plugin); how to file a claim or report a rule-breaking plugin ("Reclamo / retiro de plugin" issue template), community-blocklist.json and its reasons (claim, malware, broken, rules, author_request), what happens to installed copies, how authors appeal ## Reference - [contract.json](https://kinotvapp.github.io/kino-plugins/reference/contract.json): every number and rule the app enforces (machine-readable) - [kino.d.ts](https://kinotvapp.github.io/kino-plugins/reference/kino.d.ts): TypeScript declarations of the kino API and every shape - [Example plugins](https://kinotvapp.github.io/kino-plugins/en/examples/): the two published examples (and [Maratón](https://github.com/xuper-plugin/maraton), a community plugin that uses the hidden browser and labelled lazy copies; Kino only lists community plugins) - [kinotvapp/kino-plugin-own-server](https://github.com/kinotvapp/kino-plugin-own-server): the complete API reference and template ("Tu servidor" 1.5.0, apiVersion 7) -- every setting type and the settings form, auth, kino.storage, downloads, copies, request signing, live items and channels in every shape, a section, migrate, meta, subtitles, tracking and segments. Raw files: [plugin.js](https://raw.githubusercontent.com/kinotvapp/kino-plugin-own-server/main/plugin.js), [kino-plugin.json](https://raw.githubusercontent.com/kinotvapp/kino-plugin-own-server/main/kino-plugin.json) - [kinotvapp/kino-plugin-archive](https://github.com/kinotvapp/kino-plugin-archive): the simplest template to start from, with the sdk/ kit -- start here for a plain plugin with no settings or login ## Optional - [Build a plugin with AI](https://kinotvapp.github.io/kino-plugins/en/ai/): what a non-programmer needs first, a ready-to-paste prompt, a filled-in example, and what to do when something fails - [Markdown sources](https://github.com/kinotvapp/kino-plugins/tree/main/docs): the pages as Markdown (English: *.en.md, Spanish: *.md)