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
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):
|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)
|Supported e.g. with pip
|Supported for pure Lua modules, probably possible but complex for modules with binary
|Fully embedded, based on LuaJIT
|Supported libobs modules
|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):
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 settings
script_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
script_update are called
script_defaults is called at OBS startup (and are available as set by
script_defaults later in
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 persistently
script_unload() is called just before the destruction of the script execution context
Data 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_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
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
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_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
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:
Then, as the script is selected in the Scripts window, the properties are initialized and displayed:
script_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
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).