OBS can be extended with Python and Lua scripts. This set of pages explains the basics to get started and describes how to implement common features.
Scripts are managed by the user through the Scripts dialog window, displayed via the menu item Tools > Scripts:
A list of scripts currently added to OBS is displayed on the left hand side (here two scripts distributed with OBS). On the right hand side, if any, the description and editable properties of the script are shown. A script can be added by clicking on + and selecting the related Python or Lua file, removed with -. Use the 🗘 button to Reload Scripts and the Defaults button to reset the values of the editable properties to their default values.
For Python scripts, a decent distribution of Python must be installed by the user, and the Python Install Path must be set in the tab Python Settings. Please refer to the OBS scripting documentation for the supported version of Python (currently Python 3.6). Depending on the Python installation, locating the installation path can be difficult, e.g. on Windows 10 with Python installed from the Microsoft Store, the installation path is located at [UserFolder]\AppData\Local\Programs\Python\Python36
.
Scripting is a way to add functionality to OBS but it is not the only one. Having an overview of the context is important before going into the details. Here is a non-exhaustive list of methods one could use to develop new functions that interact with OBS:
Lua is by far less popular and less powerful than Python, but it is a bit simpler (on purpose, to reduce complexity and footprint in the embedding executable) and better integrated in OBS (as of v26.1):
Criteria | Python | Lua |
---|---|---|
General usage | Wide usage for everything, full-featured standard library, etc | Sparse usage mainly as embedded scripting extension (e.g. in Wireshark, VLC, RPM, etc), poor standard library (use the OBS API or FFI to fill the gaps) |
Additional modules | Supported e.g. with pip | Supported for pure Lua modules, probably possible but complex for modules with binary |
Interpreter | Not embedded | Fully embedded, based on LuaJIT |
Supported libobs modules | None | Sources using source_info |
OBS has a huge API of C functions and data structures. Scripting-specific API features are described in the OBS scripting documentation. The rest of the API is documented in the original C flavour only, there is no documentation of the functions and data structures as seen from the scripting environment so far.
These resources can be helpful (feel free to add something):
[InstallationFolder]/data/obs-plugins/frontend-tools/scripts
A bare text editor is the only thing you need to get started, but prefer the IDE of your choice for a more comfortable editing. There is no official supporting file for features such as Intellisense so far.
Two tutorials are proposed in this Wiki:
Other tutorial resources (feel free to add something):
There is no strong layer of protection or consistency checking between scripting and binary functions. The C functions of the OBS API are bound to the scripting environment through wrapper functions written in C and compiled into OBS libraries.
Typically, when a Python/Lua function is called in a script, the interpreter calls the related C wrapper function that implements these 3 steps:
Wrapper functions exist as well for "getters" and "setters", in order to access the members of OBS data structures, again with data conversion between C types and Python/Lua types.
source_info
and functions with callback arguments (see the section other differences from the C API).warning: Even if most functions are usable as intended (especially the ones specifically re-designed for scripting), a few functions with SWIG-written wrappers cannot be used directly for scripting so far, because SWIG cannot interpret properly the data types of arguments or return values given in the C definition. Typically, with values passed by reference or buffers, C pointers and pointer-pointer types are inherently ambiguous.
A script must define some global script functions called by the scripting environment at different stages of the script life-cycle and at different execution phases of OBS. The following steps are performed wherever the related global script functions are implemented.
When a script was previously added to OBS, at startup:
script_defaults(settings)
is called to initialize default values in data settingsscript_description()
is called to retrieve a description string to be displayed in the Scripts window (with Qt-style formatting :bulb:)script_load(settings)
is called for one-time initialization, possibly using values of data settings (typically to setup signal handlers)script_update(settings)
is called a first time for initializations depending on the values of data settings (this function will be called again after any change of value in the data settings, see below)Please note that:
settings
during OBS startup reflect the state saved at previous OBS closure (properties changed by the user), and are already set in settings
when script_defaults
, script_load
and script_update
are calledsettings
when script_defaults
is called at OBS startup (and are available as set by script_defaults
later in script_load
and script_update
)OBS_FRONTEND_EVENT_FINISHED_LOADING
is emitted). This is especially important in script_update
if sources or scenes are looked up.Check how OBS saves properties in the user's JSON configuration file (at [UserFolder]\AppData\Roaming\obs-studio\basic\scenes
under Windows) to better understand what is going on.
script_tick(seconds)
is called every rendered frame (seconds
is the time in seconds passed since the previous frame). Consider using a timer instead of a recurrent test in script_tick
if possible.warning: Be very careful with the code in script_tick
, OBS may rapidly become unresponsive if some error or text is logged every frame.
Two global script functions are called when OBS is closed:
script_save(settings)
is called just before saving the data settings persistentlyscript_unload()
is called just before the destruction of the script execution contextData settings are saved automatically at OBS closure, it is not necessary for the script to call any function to save data settings (and not necessary to implement script_save
nor script_unload
to trigger OBS to save data set by a script).
Once OBS startup is completed, script_properties()
is called by OBS if the script is selected in the Scripts window (selecting another script would always call the related script_properties
function).
The function has to return an obs_properties_t
object created using obs_properties_create
and filled with GUI elements though obs_properties_add_*
functions. The object will be released by OBS when necessary.
A callback function can be set to each property using obs_property_set_modified_callback
.
When the value of a property is changed, the sequence is:
script_update(settings)
is called (for initializations depending on the values of data settings)Please note that:
obs_property_set_modified_callback
has to return true to trigger the refresh of the properties widget (no new call to script_properties
)script_update
, then its callback is not triggered automatically, use obs_properties_apply_settings
to trigger all callbacks (e.g. in script_update
with a properties object saved in a global variable in script_properties
)
The management operations available on the Scripts window trigger more complex sequences (described in this section as in OBS v26.1, the behavior may change in the future).
Adding a script:
Initialization steps like in OBS startup except that values of data settings are not available:
script_defaults
script_description
script_load
script_update
Then, as the script is selected in the Scripts window, the properties are initialized and displayed:
script_properties
script_properties
againscript_update
with data settings available:warning: The complete sequence may lead to inconsistencies if not carefully handled, because the same functions are called multiple times, including property callbacks at step 7, while data settings are not available (credits to eukraticism for pointing out this behavior).
Removing a script just triggers a call to script_unload
(not script_save
).
Resetting to defaults starts with a call to script_update
followed by the same steps as for removing and then re-adding a script (data settings not available).
Reloading a script is the same as removing and then re-adding a script, except that the values of data settings are available during the complete sequence.
It is common to experience OBS crashes or unexpected behavior during the development. A few hints (feel free to add your own!):
script_tick
. It may be necessary to close the OBS window or even kill the process to recover.obs_get_current_scene
must be followed by a call to obs_source_release
otherwise OBS may crash on exit (with "Freeing OBS context data" as last log entry). The need to release objects is not always documented. As a rule of thumb, if the API documentation states Returns: A new reference ... or Returns: An incremented reference... then a call to a release function is probably necessary (credits to J. Buchanan for this helpful synthesis)..hlsl
on the effect file name may help).