Tutorial: How to control OBS via OpenLP custom stage view



  • edited June 2022

    OK I figured it out, blank wasn't firing the update method because it didn't check whether it was changing like the other methods. I've fixed it. See attached obs.zip. Works with OpenLP v2.

        //inserted for being able to control OBS by display style

        if(OpenLP.currentlyShowing != "blank" && data.results.blank) {

         OpenLP.currentlyShowing = "blank";



        else if(OpenLP.currentlyShowing != "theme" && data.results.theme) {

         OpenLP.currentlyShowing = "theme";



        else if(OpenLP.currentlyShowing != "display" && data.results.display) {

         OpenLP.currentlyShowing = "display";



        else if(OpenLP.currentlyShowing != "slides" && 

            !data.results.blank && 

            !data.results.theme && 

            !data.results.display) {

         OpenLP.currentlyShowing = "slides";



  • edited June 2022

    Hi I'm so close! I'd appreciate help from those who know more about programming than me.

    I would like to be able to query which Scene is active in OBS.

    For example, I'm trying to see whether the OBS scene "Pre-roll" is active.

    I've tried the following code in the stage.js file, but it doesn't seem to work.

       if(OpenLP.obsHandler.send('GetCurrentScene.name') == 'Pre-roll') {

        // do something here


    Many thanks if you can help!

  • OK I think I have the syntax but is there a shorter way than this:

        OpenLP.obsHandler.send('GetCurrentScene').then(data => {

         if (data['name'] == 'Mirror') {

         OpenLP.obsHandler.send('SetCurrentScene', {'scene-name': 'Camera'}); 


  • Please how do I get this to work on 2.9.4?

    Thank you.

  • I was looking at the same thing. Unfortunately, 2.9.4 uses the API V2, which does not use the poll.py class, and is not able to recognize the program states of blank, theme, display and slides. The comment on poll.py states "This class is DEPRECATED, if you need the state of the program, use the registry to access variables." I have not yet figured out where the program state is in the registry.

    The original stage.js script included on this thread has everything set up to use the V1 api, so even some of the other classes are changed a bit. I had liked how the OP didn't display anything for images and presentations, which does help a lot for not needed to change scenes in our case. I would manually change scenes when an image was up, since I didn't want OBS to display the file name. I was able to take what the OP did with his CSS and in JS added the. I use the notes

    I am working to see if I can find the display state and have it just adjust that in the CSS as well, rather than bother with the OBS scenes. For our purposes, I am fine just displaying text or not.

    I also set up the notes to just put my bible references in there to be displayed in the lower corner of OBS.

    This is the set of scripts I am using for now. I will be making a few more tweaks to the JS, but hopefully this will get you some basic functionality on OBS for now. The nice thing about this version is that it doesn't require any OBS plugins. everything is just managed through the custom stage as to what is displayed.

  • Just a heads up.

    This "plugin" does not work with OBS 28.0 > (websocket already pre-instaled) and OpenLP 2.9.x

    Would be great if someone could work on an embedded tool (with workable custom dock) that can help with implementing a forced split within a slide to allow for easy manipulation within OBS. At the moment if I have to display a long bible verse the preview in OBS spills over the browser boundary

  • Thanks for your script - that was really helpful for me.

    For what it's worth, I've been able to pick up the program state from the 'blank' value returned by the API (I only want to know if the screen is blacked out or not so I haven't bothered with listening for theme or desktop):

    ws = new WebSocket("ws://");
    ws.onmessage = (event) => {
       const reader = new FileReader();
       reader.onload = () => {
          data = JSON.parse(reader.result.toString()).results;
          if (data.item.plugin) {
            OpenLP.currentPlugin = data.item.plugin;
          if (OpenLP.currentItem != data.item || OpenLP.currentService != data.service) {
            OpenLP.currentItem = data.item;
            OpenLP.currentService = data.service;
          } else if (OpenLP.currentSlide != data.slide) {
            OpenLP.currentSlide = parseInt(data.slide, 10);
          if (data.blank) {
            OpenLP.currentlyShowing = "blank";
          } else {
            OpenLP.currentlyShowing = "display";
  • I made a portable versions of OBS + OpenLP if you don't want to go through the pain of it all. It's using an older version of OBS and OpenLP. Here's a web page describing it:


Sign In or Register to comment.