DocsGuide people through your app
Docs

Guide people through your app

Build a product tour anchored to markers in your own source: mark the elements, turn the tour on, preview the draft against your running app, and switch it off in 30 seconds.

How a tour works

A tour draws a card next to a real control in your product and waits for the person to use it. Nothing is simulated and nothing is intercepted — the listener never calls preventDefault, so your own handler runs exactly as it would with no tour on the page.

Three things have to line up, and they are the three steps below:

  1. 1

    Markers in your source

    An attribute on the element each step points at. This is the part that edits your code — it is the one real difference in effort between a tour and a demo.
  2. 2

    A published tour

    The step order, the card copy and what completes each step live in the published plan, not in your source.
  3. 3

    The tag on the page

    The same script tag a demo uses, plus data-mode="tour".

The split matters: your source says where and the plan says what. Reword a step, reorder the tour or change what completes it and no code changes — you republish. Move the button and you move the marker with it.

Mark the elements

Put the marker on the element the step points at.

jsx
<button data-rd="onboarding/new-project" data-rd-do="click">
  New project
</button>

The value is <tour>/<step>, each half a lowercase slug. data-rd and data-rendemo are the same attribute — both work everywhere and a page may mix them, so a repo can adopt the short spelling gradually. The full attribute list is in Reference.

Markers must ship to production

They are what the tour anchors to at runtime, on every visitor’s page. Do not strip them in a production build and do not put them behind a dev-only flag. They are inert attributes — no runtime cost, no behaviour of their own.

One element per marker. If the marker resolves to several elements at once — a row inside a .map(), or the same marker on two mutually exclusive branches — the step needs a match (first, last, or an index), or the tour treats the ambiguity as a missing target and waits.

Turn it on

Same tag as a demo, plus the mode. Put it in the layout or route that owns the tour’s first step, and keep it mounted across the pages the steps span — unmounting tears the tour down.

html
<script src="https://www.rendemo.com/embed.js"
        data-demo="acme/onboarding" data-mode="tour" async></script>

Three optional attributes, and absent means exactly the behaviour above:

  • data-user="u_123" — keys progress and the analytics by that id instead of by browser, so two people sharing a machine no longer share one position. Any opaque string; Rendemo never resolves it to anybody.
  • data-routes="/app,/app/projects" — which pages the tour may run on at all, re-evaluated on every navigation.
  • data-when="always" — replays a tour the viewer already finished, which is what a “Take the tour” button needs. The default is once, ever.

Mounting is starting

There is no start button and no open attribute — the tour begins when the element mounts. That is also the targeting primitive: a host that wants only trial admins to see it renders the tag only for them. See what tours do not do.

Preview before publishing

Publishing used to be the only way to see a tour, which meant making it live to find out whether it was right. rendemo_get_tour_preview({ projectId, baseUrl }) returns a link that runs the current draft against your own running app.

Nothing is published, no analytics are recorded, progress stays out of a real visitor’s storage, and every card carries a persistent “Preview — draft, not live” badge. A tour that has never been published previews fine, which is the case it matters most for.

The markers have to be in the build you point it at

A preview sends the draft plan to a browser. It cannot send the draft markup, which lives in your application. Against a dev server that is immediate — save the file and reload. Against staging or production, the commit that adds the markers has to be deployed there first, or every step correctly reports a target it cannot find.

The link is a bearer token and expires 30 minutes after it is issued — anyone holding it sees the draft, with no sign-in.

Turning one off

Two switches, neither of which deletes anything — turning either back on serves the identical tour.

  • Per tour. Take offline in the library’s ⋯ menu (or rendemo_take_demo_offline) stops the payload being served, and the tour on your product renders nothing.
  • Per workspace. Settings → Product tours refuses every tour at once — what you reach for when a release has moved the UI out from under all of them together.

Propagation is bounded at 30 seconds: the payload is served public, max-age=0, s-maxage=30, deliberately kept out of private caches so the shared-cache window is the worst case.

It stops the tour being served. It does not reach a tab where the tour is already running — that visitor finishes it.

What tours do not do

Read this before rolling one out to real users. Current absences, stated plainly rather than softened.

  • No targeting rule engine. No “new users only”, no per-plan or per-role condition, no percentage rollout. data-routes filters pages; conditionally rendering the tag is how you filter people, and that is the honest primitive rather than a gap.
  • No cross-device progress. data-user scopes progress per person within a browser — it is localStorage, not a server-side profile. Clearing storage or switching device restarts the tour.
  • No privacy posture beyond Do-Not-Track. The analytics honour DNT and nothing else; there is no consent API on that path.
  • No rule-evaluated branching. Branches are viewer-chosen buttons the author declared. A step whose target never appears gives up visibly rather than taking a path.
  • No lead capture, no localization, no replay artifact. A tour has no footage, so no HTML, poster, export or locale build — and rendemo:lead never fires for one.

A tour is also only as good as its markers, and a deleted element breaks it silently. That is what Keep tours from breaking is for.