Install the embed script
Add the one-line script to your site, verify it, and how it behaves in single-page apps.
Add a web site
- Open the Sites page
In the dashboard, go to Your Tours (the Sites page) and click + Add site.
- Choose Web and fill in the details
Site name is just for you. Domain is your site’s address without the protocol —
example.comorapp.example.com. We use it to run the installation check and to open the Visual Editor on the right site. - Copy the embed code from the site tile
The snippet
<script src="https://app.lovelysomething.com/embed.js" data-site-key="sk_xxxxxxxxxx" async></script>Paste it on every page where a tour might run — usually in your site-wide layout or template, so it’s everywhere. Before </body> or inside <head> both work; async means it never blocks your page from rendering.
The data-site-key tells the script which site’s tours to load. Use the exact snippet from your site tile — each site has its own key.
Framework examples
Anything that can output a script tag works. A few common setups:
import Script from 'next/script'
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
{children}
<Script
src="https://app.lovelysomething.com/embed.js"
data-site-key="sk_xxxxxxxxxx"
strategy="afterInteractive"
/>
</body>
</html>
)
}<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
<script src="https://app.lovelysomething.com/embed.js" data-site-key="sk_xxxxxxxxxx" async></script>
</body>- WordPress — add it with a header/footer scripts plugin, or in your theme’s
footer.php. - Shopify — Online Store → Themes → Edit code →
theme.liquid, just before</body>. - Webflow — Site settings → Custom code → Footer code.
- Google Tag Manager — a Custom HTML tag firing on All Pages. (The installation check can’t see tags injected this way, but tours still work.)
Test the installation
Once your site is deployed, click Test installation on the site tile. We load your domain and look for the snippet:
| Result | What it means |
|---|---|
| ✓ Installed | The snippet is on the page with the right site key. |
| Different site key | The snippet is there, but it was copied from another site. Re-copy it from this site’s tile. |
| Couldn’t find the snippet | The page loaded but the script tag isn’t in the HTML. If you add it via Tag Manager or another script after load, this is expected — check in the browser instead. |
| Couldn’t load the site | Your domain isn’t publicly reachable (still local, behind a login, or a typo in the domain). |
Single-page apps
No extra setup is needed for React, Next.js, Vue, Svelte, Angular or any other client-side router. The script watches for navigation (pushState, replaceState, back/forward and DOM changes) and, whenever the URL path changes, tears down the current tour and loads the tours for the new path.
It also copes with elements that render late: when a tour is set to start on its own, the script waits up to 8 seconds for the step targets to appear before starting. See Launch behaviour.
Performance and privacy
- The script is small, loads asynchronously and only fetches tours for the current path.
- If a page has no active tour, nothing is rendered.
- No cookies are set and visitors aren’t fingerprinted. Per-visitor state (dismissed, times shown) lives in the visitor’s
localStorage. See the embed reference.
Content Security Policy
If your site sends a CSP header, allow the script and its API calls from our domain. The script injects its own <style> element for the tour UI, so inline styles need to be allowed too:
script-src 'self' https://app.lovelysomething.com;
connect-src 'self' https://app.lovelysomething.com;
style-src 'self' 'unsafe-inline';
img-src 'self' https: data:;img-src https: is only needed if you use a splash carousel with uploaded images.
/#/settings) all share one path, so use * or / as the page path and element conditions to pick the right tour per view.