Install the snippet
The snippet is two script tags. The first defines a small queue so your code can call UserOnboarder before the real script has loaded; the second loads the script asynchronously, so it never blocks your page.
Get your snippet
The dashboard's Install page shows the snippet with your workspace's key and server address already filled in. It looks like this:
<script>
window.UserOnboarder = window.UserOnboarder || { q: [] };
["identify", "track", "start", "page", "reset", "setLocale", "openResourceCenter", "closeResourceCenter"].forEach(function (m) {
UserOnboarder[m] = UserOnboarder[m] || function () { UserOnboarder.q.push([m, arguments]); };
});
</script>
<script async src="https://guides.example.com/sdk.js" data-key="pk_…" data-wait-for-identify></script>
Put it in the <head> of every page, then identify signed-in users.
Script tag attributes
| Attribute | Required | Meaning |
|---|---|---|
data-key |
yes | The workspace's public key. Identifies which workspace's guides to load. It isn't secret. |
data-wait-for-identify |
no | Show nothing until identify() is called. Use it on apps where everyone is signed in, so guides never flash for an anonymous visitor first. Remove it on pages where you want to reach anonymous visitors. |
data-locale |
no | The language to show guides in, e.g. de. Without it the language comes from the user's attributes, <html lang> or the browser. See Languages and translation. |
data-api |
no | Address of the User Onboarder server, if it differs from where sdk.js is served (for example when you host sdk.js on your own CDN). |
Framework notes
Angular
Add the snippet to src/index.html. Calls from components and services go through window; declare it once so TypeScript knows about it:
// src/user-onboarder.d.ts
type LGValue = string | number | boolean | null;
interface Window {
UserOnboarder: {
identify(id: string, attributes?: Record<string, LGValue>, options?: { hash?: string }): void;
track(name: string): void;
start(guideId: string): void;
page(): void;
reset(): void;
};
}
Then, for example in your auth service after login:
window.UserOnboarder.identify(String(user.id), { plan: user.plan, role: user.role });
Angular's router changes the address with history.pushState, which the script detects on its own.
React / Next.js
In Next.js (App Router), add the tags to the root layout with next/script:
import Script from "next/script";
<Script id="lg-stub" strategy="beforeInteractive">{`
window.UserOnboarder = window.UserOnboarder || { q: [] };
["identify","track","start","page","reset","setLocale","openResourceCenter","closeResourceCenter"].forEach(function (m) {
UserOnboarder[m] = UserOnboarder[m] || function () { UserOnboarder.q.push([m, arguments]); };
});
`}</Script>
<Script src="https://guides.example.com/sdk.js" data-key="pk_…" data-wait-for-identify strategy="afterInteractive" />
Call window.UserOnboarder.identify(...) in an effect once the session is known.
Server-rendered sites
Add the snippet to your base template. Identify the user in an inline script rendered on pages where they're signed in.
Check that it works
- Open your site. In the browser's developer tools, the network tab should show
sdk.jsand a request to/api/sdk/initwith status 200. - The Install page in the dashboard shows Receiving data, and people appear under Users.
- Problems are logged to the browser console with the prefix
[UserOnboarder]. See Troubleshooting.
Content Security Policy
If your site sends a Content-Security-Policy header, allow the User Onboarder server:
| Directive | Add | Why |
|---|---|---|
script-src |
your User Onboarder address, plus a nonce or hash for the inline stub | loading sdk.js and the queue |
connect-src |
your User Onboarder address | loading guides and sending events |
style-src |
'unsafe-inline' |
the script styles its own elements |
img-src |
your User Onboarder address, plus any other image hosts you link to | images in steps and announcements (uploads are served from User Onboarder) |
frame-src |
https://www.youtube-nocookie.com https://player.vimeo.com |
video blocks |
What the script adds to your page
Everything is drawn inside one <user-onboarder> element attached to <html>, using a shadow root, so your CSS doesn't affect guides and guide CSS doesn't affect your page. It sits at z-index 2147483000. The script stores one value in localStorage (lg_anon_id, the anonymous visitor id) and, only in builder mode, one value in sessionStorage. It sets no cookies.