React product tours: libraries, working code, and build vs. buy.
You can build a React onboarding tour four ways with open source, or skip the build entirely. Here's all of it honestly: working code for each library, the licensing trap in one of them, what every library leaves you to build yourself, and when buying actually wins.
Libraries and licenses checked August 21, 2026.
The React ecosystem has four serious open-source options for product tours, and they're all genuinely usable — this is not one of those roundups where the open source is a strawman. If your job is a single guided tour, maintained by engineers, shipped once, any of these will do it well.
The honest framing is that the library is about a fifth of the system. Steps and popovers are what libraries give you; targeting, seen-state, analytics, and the ability for non-engineers to edit copy are what production onboarding actually runs on. The roundup covers the first fifth; the second half of this page covers the rest.
The libraries, honestly — with the code.
React Joyride — the React-native default
- License:
- MIT
- Best for:
- React teams that want tours as a declarative component
Joyride is the most React-idiomatic of the four: tours are a component, steps are props, and state flows through callbacks like everything else in your tree. Spotlighting, beacons, and step styling are built in, and it handles React's re-renders sensibly.
The trade is that its tour state lives in your app's state management — which is fine for one tour and increasingly your problem for five. Persistence ("has this user seen it?") is entirely yours to build.
import Joyride from "react-joyride";
const steps = [
{
target: ".new-project-btn",
content: "Everything starts here — create your first project.",
},
{
target: ".invite-field",
content: "Onboarding sticks better with a teammate aboard.",
},
];
export function OnboardingTour() {
return <Joyride steps={steps} continuous showSkipButton showProgress />;
}Shepherd.js — the framework-agnostic heavyweight
- License:
- MIT (core library)
- Best for:
- Teams that want fine-grained control and don't mind imperative code
Shepherd is the most capable pure-DOM tour library: modal overlays, rich step options, promise-based hooks around every transition. The react-shepherd wrapper exists, but many teams use the core imperatively — it predates the framework wars and outlived most of them.
The power costs verbosity: every step is a configuration object with explicit buttons and attachment rules, and the styling starts from its own CSS you'll be overriding. Budget real time for making it look native to your product.
import Shepherd from "shepherd.js";
import "shepherd.js/dist/css/shepherd.css";
const tour = new Shepherd.Tour({
useModalOverlay: true,
defaultStepOptions: { scrollTo: true, cancelIcon: { enabled: true } },
});
tour.addStep({
id: "create-project",
text: "Everything starts here — create your first project.",
attachTo: { element: ".new-project-btn", on: "bottom" },
buttons: [{ text: "Next", action: tour.next }],
});
tour.start();Driver.js — the lightweight one
- License:
- MIT
- Best for:
- Simple highlight-and-explain tours with minimal footprint
Driver.js is the smallest and most pleasant of the four for basic work: highlight an element, show a popover, move on. The v1 rewrite made it dependency-free and a few kilobytes, and the API fits in your head after one reading.
It is deliberately less featureful — fewer step behaviors, less lifecycle control — which is either its weakness or exactly why you'd pick it. For a two-step "here's the new thing" highlight, reaching for anything heavier is ceremony.
import { driver } from "driver.js";
import "driver.js/dist/driver.css";
const tour = driver({
showProgress: true,
steps: [
{
element: ".new-project-btn",
popover: { title: "Start here", description: "Create your first project." },
},
{
element: ".invite-field",
popover: { title: "Bring the team", description: "Invite a teammate early." },
},
],
});
tour.drive();Intro.js — the famous one, with a licensing trap
- License:
- AGPL-3.0, or a paid commercial license
- Best for:
- Open-source projects, or teams that buy the commercial license
Intro.js is the name everyone knows and the demo everyone has seen — mature, polished, with hints and tooltips beyond basic tours. Then the fine print: it is AGPL-3.0 licensed, and for a commercial SaaS product the AGPL's obligations are ones almost no company will accept, which makes the paid commercial license the real price of using it.
Nothing wrong with paying for software — but teams routinely npm-install Intro.js without reading the license and discover the issue in a legal review months later. If you use it commercially, buy the license; if that changes the math, the MIT options above exist.
import introJs from "intro.js";
import "intro.js/introjs.css";
introJs()
.setOptions({
steps: [
{ element: document.querySelector(".new-project-btn"), intro: "Everything starts here." },
{ element: document.querySelector(".invite-field"), intro: "Invite a teammate early." },
],
})
.start();What every library leaves you to build.
The tour is the visible fifth of an onboarding system. These four builds are the rest — and they are where hand-rolled setups quietly stall.
Who edits the copy?
With every library above, changing a step's wording is a pull request and a deploy. The growth PM who owns activation files a ticket and waits — which is the exact dependency onboarding tooling exists to remove.
Targeting is a second project
Show the tour to new users only, skip it for invited teammates, re-show it to users who never finished — every library leaves audiences, traits, and rules entirely to you. This is routinely more code than the tour itself.
Seen-state is a third one
"Has this user seen this tour?" needs storage, per user, ideally across devices. localStorage gets you a demo; production needs it in your backend, with an API, forever.
Analytics is a fourth
Which step do users abandon? Did the tour move activation? Libraries emit events at best — the funnel, the dashboards, and the A/B harness to answer the only questions that matter are all separate builds.
The whole trade, in one table.
| Dimension | Build on a library | Buy (Wakeline) |
|---|---|---|
| Upfront cost | Free (library) + engineering days to integrate | Free tier, then $49/mo for 25,000 MAU |
| Who edits a step's copy | An engineer, via a pull request and a deploy | Anyone on the team, in a visual builder, live in seconds |
| Targeting & segmentation | You build it — user traits, rules, audiences | Included: audiences, trait rules, saved segments |
| Analytics | You build it — step events, funnels, dashboards | Included: per-step funnels, trends, click actions |
| Seen-state & persistence | You build it — per user, across devices | Included, cross-device for identified users |
| Surfaces beyond tours | Checklists, surveys, banners: all separate builds | Included in the same builder |
| A/B testing | You build it, including the statistics | Included, with significance testing |
| Ongoing maintenance | Yours — selector breakage, library upgrades, edge cases | Vendor's — anchors degrade gracefully, tooling maintained |
Wakeline with React: deliberately boring.
Wakeline sits on the buy side of that table, and the React story is deliberately boring: there is no React SDK, no wrapper components, no build-step integration. The snippet runs at the DOM level, which is the level React renders to — so it works with every React version, router, and meta-framework without knowing or caring which one you use.
- Anchors survive re-renders. Steps attach by selector to the rendered DOM; React re-rendering an element doesn't detach them, and steps wait for lazily-rendered elements (or skip gracefully) instead of pointing at nothing.
- SSR and Next.js are non-events. The SDK is client-side and loads async — server components, hydration, and streaming don't interact with it.
- Tours are built visually on your live app, no-code — the PM edits copy at 4pm and it's live at 4:01, with no ticket in sight.
- The rest of the system is included: targeting and segments, cross-device seen-state, per-step funnels, A/B testing, plus checklists, surveys, and banners from the same builder.
<script>
(function (w, d, s) {
w.Wakeline = w.Wakeline || function () { (w.Wakeline.q = w.Wakeline.q || []).push(arguments); };
var js = d.createElement("script"); js.async = 1; js.src = s;
var f = d.getElementsByTagName("script")[0]; f.parentNode.insertBefore(js, f);
})(window, document, "https://wakeline.io/wakeline.js");
Wakeline("init", { key: "YOUR_PUBLISHABLE_KEY" });
// After login — unlocks targeting, segments, and cross-device state:
Wakeline("identify", user.id, { name: user.name, plan: user.plan });
</script>When building on a library is still right.
One static tour, engineer-owned
A single walkthrough in a developer tool, written once and rarely touched, is a fine fit for Joyride or Driver.js — the system gaps above never bite because there's no program, just a tour.
Your users are developers
If your product ships to engineers who'd notice and respect a hand-rolled tour, the polish calculus shifts — and your team can genuinely maintain it.
Zero budget, genuinely
Pre-revenue and counting dollars? MIT libraries are free forever. (Though a free tier covering 1,000 MAU exists precisely for this stage — compare the engineering hours honestly.)
Total control is a requirement
If the tour must do something no vendor's renderer does — bespoke animation, deep product coupling — you were always going to build. Build on Shepherd; it will fight you least.
What is the best product tour library for React?
React Joyride for the most React-idiomatic developer experience, Driver.js for minimal-footprint highlighting, Shepherd.js for maximum control. All three are MIT. Intro.js is equally capable but AGPL-licensed — commercial use realistically requires buying its paid license.
Is Intro.js free for commercial use?
Effectively no. Intro.js is AGPL-3.0, whose obligations are unacceptable to almost every commercial product, so its paid commercial license is the practical price of shipping it in a SaaS app. Teams regularly discover this in legal review after integrating — check licenses before you npm install.
Does Wakeline have a React SDK?
Deliberately not — there is nothing framework-specific to install. The snippet works at the DOM level React renders to, so every React version, Next.js, Remix, and plain Vite apps all integrate identically: paste the snippet, call identify() after login, build tours visually.
How do tours handle React re-renders and route changes?
Wakeline anchors steps by selector to the live DOM and waits for elements to appear (or skips gracefully), so re-renders, client-side route changes, and lazy-loaded views behave. The same property is what makes tours survive your app's ordinary churn without an engineer re-wiring them.
Library or platform — how do I actually decide?
Count the tours and the editors. One tour, edited by engineers: use a library. A program — multiple flows, targeting, measurement, non-engineers iterating: the build-vs-buy table above is the honest accounting, and the four system gaps (editing, targeting, persistence, analytics) are where hand-rolled setups quietly die.
Ship a React tour today — without the build.
The snippet takes five minutes; the free plan covers 1,000 monthly active users. Compare it against the library route on your own app.