The Unofficial Guide to the Interactive Tours API

I Hope @knolleary & @dceejay don't mind me documenting this API, I know there is a view to develop some documentation on it when time allows, but I think this API deserves more exposure, so thought id share my DIY handbook on it for others.

Please do correct me on the below, if I have anything incorrect.


A node module can include interactive tours (like the one you see after a new Node RED release)
Below is how you package one with your own Node module.


The Tour File contains an exported object, that contains a steps array, where each step object contains the following properties.

Property Use Case
titleIcon Optional Font Awesome Icon Identifier
title Optional title of the current step
width Optional width of the overlay
description The content of the step (can be HTML)
prepare() Optional javascript to be executed prior to the step being executed
complete() Optional javascript to be executed after a step has finished and moved on
element, direction Animates a halo/focus around this DOM element for this step
wait Wait for this event before moving to the next step

Notes on title and description::

These must be per region code you have translation for

  • en-US
  • fr
  • ja

etc etc

Notes on wait::

When this is provided, the next button is hidden, as the sequence is only advanced to the next step once wait has been satisfied.

Example

wait: {
    type: "dom-event",
    event: "click",
    element: "#red-ui-workspace .red-ui-tab-button.red-ui-tabs-add a"
}

Using wait allows an interactive walkthrough of your node module.

Notes on element::

This should be a jQuery selector path, along with the direction of the anchor, in which the description is displayed

Example

element: "#menu-item-arrange-menu-submenu",
direction: "left",

Notes on prepare and complete::

Passing an argument of done, you can halt the remaining execution of the step until you call done

Example

prepare(done) {
    $('#zwjs-sidebar > div.red-ui-sidebar-header.zwjs-sb-menu-header > a:nth-child(1)').trigger('click')
    setTimeout(done, 250);
},

The trick with all this, is to carefully guide the user around the Node, and to ensure certain interaction has been triggered (interactively or in your prepare stages)

With all this in mind, the below

/* ZwaveTour.js */
export default {
    steps: [{
            titleIcon: "fa wifi",
            title: {
                "en-US": "Welcome to Z-Wave JS for Node-RED",
            },
            description: {
                "en-US": "<p>Let's show you around the features.</p>",
            }
        },
        {
            title: {
                "en-US": "Here are the nodes that have been installed.",
            },
            prepare() {
                $('#red-ui-palette-container').scrollTop(100000)
            },
            element: '#red-ui-palette-base-category-ZWave_JS',
            description: {
                "en-US": `
                <ul>
                    <li>The Controller Node</li>
                    <li>The Device Node</li>
                    <li>The Event Splitter</li>
                    <li>The CMD Factory</li>
                </ul>`
            }
        },
        {
            title: {
                "en-US": "The Network Management Tab",
            },
            width: 400,
            prepare() {
                $('#red-ui-tab-zwave-js-link-button i').trigger('click')
            },
            element: '#zwjs-node-list > div > div > div',
            direction: 'left',
            description: {
                "en-US": 'This is where all advanced network management tasks can be accessed.'
            }
        },
        {
            title: {
                "en-US": "Node Information",
            },
            width: 400,
            prepare() {
                $('#zwjs-node-name-2').trigger('click')
            },
            element: '#zwjs-panel-stack > div:nth-child(3)',
            direction: 'left',
            description: {
                "en-US": 'Clicking a device in the list will show its details.'
            }
        },
        {
            title: {
                "en-US": "Advanced Panels",
            },
            width: 400,
            element: '#zwjs-sidebar > div.red-ui-sidebar-header.zwjs-sb-menu-header > a:nth-child(1)',
            direction: 'left',
            description: {
                "en-US": 'Both the selected node and network panels provide access to advanced operations.'
            }
        },
        {
            title: {
                "en-US": "Once opened, you have access to various advanced operations.",
            },
            width: 400,
            prepare(done) {
                $('#zwjs-sidebar > div.red-ui-sidebar-header.zwjs-sb-menu-header > a:nth-child(1)').trigger('click')
                setTimeout(done, 250);
            },
            element: '#red-ui-editor-stack > div > div.red-ui-tray-body-wrapper > div > div.zwjs-tray-menu',
            direction: 'right',
            description: {
                "en-US": 'The available operations depend on whether the advanced window was opened from a node or from the main network pane.'
            }
        },
        {
            title: {
                "en-US": "To close the panel, simply click the Close button.",
            },
            width: 400,
            element: '#zwjs-tray-close',
            prepare() {
                $('.red-ui-tourGuide-shade').css({
                    pointerEvents: 'none'
                })
            },
            direction: 'left',
            description: {
                "en-US": "Let's do it now."
            },
            wait: {
                type: "dom-event",
                event: "click",
                element: "#zwjs-tray-close"
            },
        },
        {
            title: {
                "en-US": "Have Fun!",
            },
            width: 400,
            description: {
                "en-US": "Please report any issues on my GitHub."
            }
        },
    ]
}

Does this.

May-09-2026 15-33-36

So how to trigger the tour?

/* Storing my tour using the resources API */
RED.tourGuide.run('/resources/<Module-Name>/Tours/ZwaveTour.js')

I hope this is helpful for the fellow Advanced Node developers, who are looking to add some really cool guided walkthroughs with your Nodes :nerd:

Thanks for that, Marcus. Currently, the API isn't fully open to third-party developers. Even though I also use it as a welcome tour. I also have a typing definition and some initial documentation for this API.

Yup...

I spoke to Nick about it maybe a year ago, its available for use - just not yet documented in help material, so until such documentation exists, thought id share a usable guide until such a time

its an Awesome API and is pretty handy for advanced Nodes

Quick technical note: the core is not (currently) protected against the simultaneous launching of tours. Then there's the debate of how to launch tours without it turning into a chaotic mess.

The tours I am working, are not auto triggered, it will be from a user action wanting to view the tour from the Side Panel.

Personally, I don't think 3rd party Nodes should be allowed to force a tour - but thats just MO, for 3rd party tours, I think it should be limited to executing it willingly and consciously.

Which is one reason UIBUILDER does not use it. :smiley:

It has a simple notification if some data is available when a uibuilder version changes. It isn't perfect but it gets the job done and I don't think it conflicts (much?) with the Node-RED version tour.

You may be correct, however, some Node packages may benefit (ahem) from at least some kind of user notification when their version is updated. :smiley:

Should any node devs want something simple, I'm happy to share.

My intention for tours is to "kick start" users who have yet to understand (the fairly complex) set of Nodes and interaction it provides.

It's not really for those who already understands the offering if that makes sense.

  • Im not good at writing - so tours is ideal for me

The Tours API is perfect for this I (rather then to showcasing changes), but yes... I have used the Notification API also - but didn't see it through.

Happy to consider a PR based on that - probably to fit in here somewhere - node-red.github.io/docs/api/ui at master · node-red/node-red.github.io · GitHub