PluginKit is the public plugin bridge for Cider. It sits on top of the closed source frontend and exposes the host objects and helpers that plugins are allowed to rely on.
The package is intentionally thin:
window.__PLUGINSYS__is the host integration surface.window.CiderAppis the main app object.window.CiderAudioexposes the audio host.- Most helpers in this package forward directly to those objects.
This document explains the contract from a plugin author's point of view.
A plugin runs inside Cider's frontend process. The plugin does not own the application shell, routing, or playback engine. Instead, it receives access to selected host APIs through PluginKit.
That has a few consequences:
- You can only use these helpers while running inside Cider.
- Behavior depends on the host version and which host subsystems have been initialized.
- Some APIs are thin wrappers over the host, so failures usually mean the host is unavailable or not ready yet.
Use definePluginContext to bind plugin metadata to plugin-scoped helpers.
import { definePluginContext } from "@ciderapp/pluginkit";
const ctx = definePluginContext({
setup() {
// Plugin startup logic.
},
name: "Example Plugin",
identifier: "example-plugin",
description: "Example plugin for Cider",
version: "1.0.0",
author: "You",
repo: "https://github.com/you/example-plugin",
});definePluginContext returns:
customElementName(name)for generating host-safe custom element names.goToPage({ name })for navigating to a plugin page.useCPlugin()for accessing the plugin metadata object.setupConfig(defaults)for creating a reactive plugin config object.getBundledAssetURL(path)for resolving bundled assets.plugin, which is the metadata object augmented withpluginKitVersion.
setupConfig(defaults) reads and writes the plugin's config subtree under CiderApp.config.
- Default values are merged with saved values.
- The returned value is a Vue
Ref. - Mutating the ref updates the saved plugin config.
- Call
saveConfig()when you want Cider to persist the updated config.
Returns the active CiderApp instance.
Use this when you need lower-level host access that is not wrapped by PluginKit.
Returns the host router used by Cider.
In plugin contexts, this usually resolves to the plugin router if one exists, otherwise the main app router.
Reads a query parameter from the current URL.
Deprecated compatibility helper. It returns null and should not be used for new playback code.
Use AppleMusic instead.
AppleMusic is the supported playback controller for plugins.
It is backed by the host's Apple Music store and MKLite internals. The controller is synchronous at the API boundary, but some operations may return promises because the host may need to ensure the player is ready first.
import { AppleMusic } from "@ciderapp/pluginkit";
AppleMusic.playPause();
AppleMusic.next();
AppleMusic.setShuffleState(true);shuffleModeis numeric, using the MusicKit-style values0for off and1for on.repeatModeis numeric, using0for none,1for one, and2for all.nowPlayingItemreturns the current host now-playing object.
playPause(),play(),pause(),stop(),next(),previous()control transport.setShuffleState(state?)toggles or explicitly sets shuffle.setRepeatState(mode?)toggles or explicitly sets repeat. Accepted values are0,1,2,none,one, andall.playItemById({ type, id })builds an Apple Music URL from the item type and ID, ensures the player exists, and starts playback.
Returns the Cider audio host object.
Use this for audio-level integrations such as inspecting the current audio graph or responding to the audio subsystem's ready event.
The object includes:
contextandsourcefor Web Audio access.audioNodesfor the host audio graph.storefor preset and profile data.init()to initialize the audio subsystem.subscribe()anddispatchEvent()for audio events.
Subscribes to a Cider PAPI event and unwraps the event detail before calling your callback.
Available PAPI events include:
- Custom Elements reference
shell:layout_type_changedimmersive:openedimmersive:closedminiplayer:openedminiplayer:closedbrowser:page_changed
The function returns an unsubscribe callback.
Convenience wrapper for a single-fire subscription.
Manually removes a PAPI event listener.
Direct access to the host's cross-plugin and host messaging bus.
Use this when you need lower-level message dispatch or when you want to interoperate with another plugin or host feature directly.
Vue-friendly wrapper around ExternalMessages.addEventListener.
- Registers the listener immediately.
- Automatically removes it when the current component unmounts.
- Returns a manual cleanup function.
Creates a native <dialog>-based modal element.
Options:
escClosecloses the modal when Escape is pressed.classNameadds one or more CSS classes.noDefaultClassskips the defaultplugin-base-modalclass.elementappends a child element into the dialog.
Returns:
openDialog()to mount and show the dialog.closeDialog()to close and remove it.dialogElementfor direct DOM access.addClass(className)for runtime class changes.
These are the higher-level dialog helpers exposed by the host dialog system.
createDialog<T>(props)opens a custom dialog component and resolves withT.createAlert(message, title?)shows a basic alert.createAlertOptions({ message, title? })is the options-based alert variant.createConfirm(message, title?, opts?)shows a confirm prompt and resolves toboolean | null.createPrompt(message, title?, opts?)shows a prompt and resolves tostring | null.
The namespace-style dialog API exported by the host. Use this if you want the same methods under a grouped object rather than individual helpers.
Adds an entry to the main application menu and returns a removal function.
Adds an item to the media item context menu and returns a removal function.
Adds an item to the immersive player menu and returns a removal function.
Registers and removes custom immersive layouts.
Use these when a plugin wants to provide an alternate immersive surface rather than a small control or menu item.
Adds a host chrome button.
Supported locations are:
chrome-top/rightmojave/player/right
You can provide separate click and context-menu handlers, plus optional menu element markup.
The host's context menu object model exposed as a namespace.
Vue composable for binding a context menu to an element reference.
Use this when you need host-style menus that track a specific DOM element and show on right click.
Calls the host's v3 API client.
Use this for direct Apple Music or related host-backed requests when the built-in controller does not cover the operation you need.
Turbo-style wrapper around the same host request machinery.
The metadata object passed into definePluginContext.
Required fields:
setup()nameidentifierdescriptionversionauthorrepo
Optional fields:
ce_prefixSettingsElementCustomElementspluginKitVersion
The package exports the following public helpers and types:
definePluginContextPluginAPIAppleMusicuseCideruseRoutergetURLParamuseMusicKituseCiderAudiosaveConfigsubscribeEventsubscribeEventOnceunsubscribeEventExternalMessagesuseMessageListenercreateModalDialogAPIContextMenuAPIuseContextMenuaddCustomButtonaddImmersiveLayoutremoveImmersiveLayoutremoveImmersiveLayoutByIdaddMainMenuEntryaddMediaItemContextMenuEntryaddImmersiveMenuEntryv3v3TurboComponentNamesCustomButtonOptionsCustomImmersiveLayoutMenuItemCARPresetCOCPresetSpatialPreset
- Prefer the highest-level helper that covers the job. For example, use
AppleMusicbefore falling back touseCider().configorv3. - If an API returns a removal callback, keep it and call it during plugin teardown.
- If you are binding anything to Vue component lifecycle, prefer
useMessageListeneror the composables instead of manual global listeners. - To ensure stability only use the documented helpers and APIs. Avoid reaching into
window.__PLUGINSYS__or other host objects directly. PluginKit APIs are designed to be stable and backward-compatible, but the underlying host objects may change without warning.