API wrapper
spicetify apply injects two scripts into Spotify: the wrapper, which builds the Spicetify global, and the module loader, which boots modules and adds Spicetify.Modules. This reference documents what the global holds in v3.
Which entry point to use
In a v3 module, import client from stdlib instead of reading Spicetify directly. client is stdlib’s typed adapter over the same wrapper objects, so stdlib can repair a capability in one release when Spotify changes it. spicetify-kit check warns when module code reads Spicetify.*, and a module that needs the global can record an ambient-client exception in its metadata.json. The stdlib boundary describes the contract.
import { client } from '/modules/stdlib/mod.ts';
client.player.next();client.notify('Saved');These client members map to the global:
client member | Wrapper object |
|---|---|
player | Spicetify.Player |
platform | Spicetify.Platform |
storage | Spicetify.LocalStorage |
uri | Spicetify.URI |
cosmos | Spicetify.CosmosAsync, with unknown response bodies |
graphQL | Spicetify.GraphQL |
keyboard, mousetrap | Spicetify.Keyboard, Spicetify.Mousetrap |
contextMenu | Spicetify.ContextMenu |
playbar | Spicetify.Playbar |
icons | Spicetify.SVGIcons |
notify | Spicetify.showNotification |
tippy, tippyProps | Spicetify.Tippy, Spicetify.TippyProps |
react, reactDOM | Spicetify.React, Spicetify.ReactDOM |
locale, snackbar | Spicetify.Locale, Spicetify.Snackbar |
modules | Spicetify.Modules |
daemon | Spicetify.Daemon |
corsProxy | Spicetify.CORSProxy |
config | Spicetify.Config, which v3 does not set |
spicetifyVersion | The CLI version from the loader manifest |
client.popupModal is deprecated. Import displayModal and hideModal from /modules/stdlib/mod.ts instead.
Code outside a module, such as the DevTools console or a v2 extension, uses the global directly. Inside an iframe, use window.top.Spicetify.
What the global contains
The wrapper attaches these members to Spicetify. Several are filled in after Spotify’s webpack modules load, so read them when you need them instead of caching them at startup.
- Player and playback:
Player,Queue,addToQueue,removeFromQueue,getAudioData,colorExtractor. - Spotify internals:
Platform,CosmosAsync,GraphQL,URI,Locale,Color,extractColorPreset. - UI:
ContextMenu,Menu,Topbar,Playbar,PopupModal,AppTitle,showNotification,ReactComponent,ReactHook,SVGIcons,TippyProps. - Input and storage:
Keyboard,LocalStorage. - Libraries from Spotify’s bundle: see Modules.
- v3 runtime:
Modules,Daemon,CORSProxy,Events.
Spicetify.Events.platformLoaded.on(callback) runs callback once Spotify’s webpack chunks have loaded. Spicetify.Events.webpackLoaded.on(callback) runs it once the wrapper has added the members it reads from those chunks. A callback registered after its event runs immediately.
Spicetify.test() logs which expected members are missing on the running client.
v3 removed Spicetify.Panel, Spicetify.getFontStyle and the panel components. Their pages remain for v2 code.
Spicetify.Daemon
Spicetify.Daemon talks to the local Spicetify daemon on 127.0.0.1:7967. Every method except available, daemonInfo and updateAndApplySupported sends the token that spicetify apply injected into the page, so those methods reject on a client that a v3 apply did not patch.
namespace Daemon { function available(): Promise<boolean>; function daemonInfo(): Promise<{ version: string | null; autoUpdate: boolean | null; autoUpdateActive: boolean | null } | null>; function send(uri: string, options?: { expectReply?: boolean; timeoutMs?: number }): Promise<string | null>; function apply(): Promise<null>; function blockUpdates(): Promise<null>; function unblockUpdates(): Promise<null>; function setAutoUpdate(on: boolean): Promise<string>; function uninstallStaged(id: string, version: string): Promise<null>; function acquireWindowControls(onDisconnect: (error: Error) => void, options?: { timeoutMs?: number }): Promise<{ release(): Promise<void> }>; function updateAndApplySupported(): Promise<boolean | null>; const updateAndApply: { (): Promise<{ jobId: string; disposition: 'accepted' | 'joined' }>; observe(listener: (status: { kind: string }) => void): () => void; }; const managedSpotify: { status(): Promise<unknown>; check(): Promise<unknown>; update(): Promise<unknown>; };}availableresolvestruewhen the daemon’s health endpoint answers.daemonInforeturns the daemon version and its automatic update setting, ornullwhen the daemon is unreachable. A field isnullwhen the daemon is older than that field.sendsends a CLI command URI over the daemon’s WebSocket and resolves with the reply text. It rejects when the reply starts witherror:or when no reply arrives withintimeoutMs, which defaults to 15000.apply,blockUpdatesandunblockUpdatesrestart Spotify. They resolve once the daemon receives the command, so you must warn the user before you call them.setAutoUpdateturns the CLI’s automatic updates on or off and resolves onceconfig.tomlrecords the choice.uninstallStagedremoves a module that the CLI staged on disk, then runsapply.Spicetify.Modules.removeLocalcannot remove these modules.acquireWindowControlsgives the caller the daemon’s Windows title bar hit-test filter until it callsrelease.onDisconnectruns if the connection drops first.updateAndApplySupportedresolvestruewhen both the daemon and Spotify’sPlatform.UpdateAPIsupport a one-step Spotify update, andfalseornullotherwise.updateAndApplystarts that update.updateAndApply.observecalls the listener with each job status and returns a function that stops observing.managedSpotifyreads and updates a Spotify installation thatspicetify spotify installmanages.
In a module, read these through client.daemon. Its stdlib type covers available, apply, blockUpdates, unblockUpdates, acquireWindowControls, updateAndApplySupported, updateAndApply and managedSpotify.
Spicetify.CORSProxy
Spicetify.CORSProxy routes requests that Spotify’s page cannot make directly because of CORS. By default it tries the daemon’s proxy and then https://cors-proxy.spicetify.app. A custom template replaces that chain.
namespace CORSProxy { type Mode = 'automatic' | 'custom'; interface Configuration { mode: Mode; template: string | null; automaticTemplates: string[]; } function url(target: string): string; function fetch(target: string, options?: RequestInit): Promise<Response>; function templates(): string[]; function configuration(): Configuration; function configure(options: { mode: 'automatic' } | { mode: 'custom'; template: string }): Configuration; function isValidTemplate(template: string): boolean;}A template is an absolute http or https URL that contains {url}, which the proxy replaces with the target. fetch moves to the next template only when a request fails without a response, and returns an HTTP error response to you unchanged. configure throws a TypeError for an invalid custom template.
const response = await Spicetify.CORSProxy.fetch('https://example.com/lyrics.json');