Skip to main content
mpv loads Lua scripts automatically and exposes a built-in mp module that lets scripts send commands, read and write properties, react to events, and register key bindings. Internally, Lua scripts use the same client API as any other mpv controller.

Script location

Scripts are loaded from two places:
  • Automatically: any .lua file in ~/.config/mpv/scripts/
  • Explicitly: passed with the --script flag: mpv --script=/path/to/myscript.lua file.mkv
mpv derives a script’s internal name by stripping the .lua extension and replacing non-alphanumeric characters with _. For example, my-tools.lua becomes my_tools. If multiple scripts share the same derived name, a number is appended to make it unique. Files with a .disable extension are always ignored.

Directory scripts

A script can be a directory instead of a single file. mpv looks for main.lua inside that directory. This is the recommended layout for scripts that span multiple source files or need to load data files:
Use mp.get_script_directory() inside the script to locate the directory at runtime. The directory is also prepended to Lua’s package.path, so you can require modules from it directly.

Lifecycle

Each script runs in its own thread. On startup:
  1. mpv executes the script’s top-level code.
  2. The built-in event loop (mp_event_loop) starts, dispatching events to registered handlers.
The player waits until the script enters the event loop before beginning playback. When mpv quits, it sends a shutdown event, which makes the event loop return.
If your script enters an infinite loop before calling mp_event_loop, mpv will hang on exit waiting for it to terminate.
Since scripts start concurrently with player initialization, some properties may not yet be populated at top-level. Read property values inside event handlers or with mp.observe_property instead.

Quick example

A script that exits fullscreen whenever playback is paused:
Save this as ~/.config/mpv/scripts/exit-fullscreen-on-pause.lua and it will be loaded automatically.

mp module

The mp module is preloaded. You can also load it explicitly with require 'mp'.

Commands

Run an input command given as a single string. Behaves like a command in input.conf, including OSD display.Returns true on success, or nil, error on failure.
Like mp.command, but each argument is passed separately — no quoting or escaping needed. OSD is not shown by default.
Note: properties are not expanded in arguments. Use mp.get_property to read values first.
Like mp.commandv, but arguments are passed as a Lua table. Supports native types (booleans, numbers) and named arguments.For named arguments, include a name key with the command name:
Returns a result table on success, or def, error on failure.
Like mp.command_native, but runs asynchronously. fn(success, result, error) is called on completion.
Returns a handle that can be passed to mp.abort_async_command.
Abort a running async command. Takes the return value of mp.command_native_async. Whether the abort succeeds depends on the command.

Properties

Return the property value as a string (formatted like ${=name}). Returns def, error on failure (def defaults to nil).
Return the property formatted for OSD display (same as ${name} in input.conf). Always returns a string (empty string on error unless def is set).
Return the property as a Lua boolean. Returns def, error on failure.
Return the property as a Lua number (double). Returns def, error on failure.
Return the property in the most appropriate Lua type. Complex properties like chapter-list are returned as tables.
Set a property to the given string value. Returns true on success, nil, error on failure.
Set a property to the given boolean value.
Set a property to the given numeric value. mpv will use an integer if the value can be represented as one, otherwise a double float.
Set a property using its native Lua type. Useful for properties that take tables. Avoid for simple string/bool/number properties.
Delete the given property. Most properties cannot be deleted. Returns true on success, nil, error on failure.
Call fn(name, value) whenever name changes. type controls how the value is retrieved: "bool", "string", "number", "native", or nil/"none" (no value passed).You always receive an initial notification with the current value.
Change events are coalesced: if the property changes many times in rapid succession, only the last value triggers the callback.
Remove all property observers registered with the given function reference.

Key bindings

Register fn to be called when key is pressed. key uses the same names as input.conf (e.g. "ctrl+a", "F5"). name is a unique symbolic name for the binding.Users can remap the binding in their input.conf:
The flags table accepts:
Like mp.add_key_binding, but this binding overrides even user-defined bindings in input.conf. Use sparingly.
Remove a binding registered with mp.add_key_binding or mp.add_forced_key_binding by name.

Events

Call fn(event) when the named event occurs. event is a table with at least an event field (the event name string). Returns true if the event exists, false otherwise.
Remove all event handlers equal to fn. Uses Lua == comparison — be careful with closures.

Timers

Call fn once after seconds seconds. Returns a timer object. If disabled is true, the timer starts in a paused state and must be started manually with :resume().
Call fn repeatedly every seconds seconds. Returns a timer object with these methods:The object also has timeout (RW) and oneshot (RW) fields.

Script identity and messaging

Script messages

Send from input.conf or another script:

Hooks

Hooks let scripts run synchronous code at specific points in the player’s lifecycle. Use mp.add_hook to register them.
priority is an integer; 50 is the recommended neutral default. Lower values run first. Available hook types:

mp.msg module

Load with require 'mp.msg' or use via mp.msg.*.
Log levels in order of severity: fatal, error, warn, info, v, debug, trace. By default, v, debug, and trace are hidden unless the user enables verbose output. msg.log(level, ...) is the generic form; all others are shortcuts.

mp.options module

Parse options from a config file and/or --script-opts on the command line.
The config file is read from ~/.config/mpv/script-opts/myscript.conf:
Command-line options are prefixed with the identifier:
Pass an on_update callback as the third argument to read_options to react to runtime changes via the script-opts property.

mp.utils module

Functions in mp.utils may be removed or changed in future mpv versions. They are not part of the guaranteed stable API.

mp.input module

Prompt the user for text input using the mpv console.

input.get(table) options

input.select(table) — selection list

Other functions


Events reference

Register handlers with mp.register_event(name, fn).

start-file

Fired before a file starts loading. Fields: playlist_entry_id.

file-loaded

Fired after a file is loaded and playback begins.

end-file

Fired after a file is unloaded. Fields: reason (eof, stop, quit, error, redirect), playlist_entry_id.

seek

Fired when the player seeks (including internal seeks).

playback-restart

Fired at start of playback after a seek or file load.

shutdown

Fired when mpv is quitting. Normally handled automatically.

log-message

Fired for log messages enabled with mp.enable_messages(level). Fields: prefix, level, text.

property-change

Fired when an observed property changes. Fields: name, data.

video-reconfig

Fired on video output or filter reconfiguration.

audio-reconfig

Fired on audio output or filter reconfiguration.

Script-opts configuration

Each script can have a dedicated config file at:
Options use key=value syntax. # begins a comment. Booleans are yes/no.
Read them in your script with mp.options.read_options.