Install Wayhint
One script tag, on any site. Pepper reads the page the browser renders, so it works the same whatever built it.
Before you start
- A site key. It identifies your site and is safe to publish. You will get one when the dashboard opens; it shows the key on its install page.
- Your domain on the allowlist. Each key only answers requests from the origins you list, such as
https://app.example.com.
The script tag
Paste it before </body> on every page where Pepper should help. async keeps it off your page’s critical path.
<script src="https://YOUR-GUIDE-HOST/widget/guide.js" data-site-key="YOUR_SITE_KEY" async></script>Today the widget is served by the guide API at /widget/guide.js, next to its 3D character chunk, model and decoder. A CDN address comes with hosted plans; the tag stays the same apart from the host.
What it weighs
guide.js is about 17 KB gzipped: the page reading, the guide and a 2D Pepper badge that shows right away. The 3D Pepper (three.js and the model, about 165 KB gzipped for the script) loads from the same folder only when a visitor first interacts with the guide, then takes over mid-step. In lite mode it never loads at all. Visitors without WebGL, or with reduced motion turned on, get the 2D guide either way.
Optional attributes
| Attribute | What it does |
|---|---|
data-site-key | Required. Your site key. |
data-api | Where the guide API lives, for example one running in your own infrastructure. Defaults to the origin the script was loaded from. |
data-accent | Colour of the buttons and highlight ring, as a hex colour, for example #d12f25. |
data-character | lite for the 2D guide only (never loads the 3D character), or 3d. Overrides the 3D / Lite setting in the dashboard. |
data-preload | 3d loads the 3D character when the page is idle, instead of on the first interaction. |
No data attributes? Use WayhintConfig
Tag managers and some optimisers can’t set data attributes. The widget then reads window.WayhintConfig, set before the script loads, or query parameters on the script URL. A data attribute wins over WayhintConfig, which wins over the query string. The Google Tag Manager template uses both.
<script>
window.WayhintConfig = { siteKey: 'YOUR_SITE_KEY', accent: '#d12f25', character: 'lite' };
</script>
<script src="https://YOUR-GUIDE-HOST/widget/guide.js" async></script>
<!-- or, with no inline script: guide.js?site-key=YOUR_SITE_KEY -->Start a guide from your own buttons
Once ready, the widget sets window.Wayhint and fires wayhint:ready on window. If it can’t start (unknown key, domain not allowed), it fires wayhint:error with a reason. React and Next.js apps can use the @wayhint/loader package, which wraps this in a promise and a component.
function start(guide) {
guide.ask('download my tax statement'); // start a guided goal
guide.open(); // open the Ask Pepper panel
guide.stop(); // stop the current goal
guide.destroy(); // remove the widget (it can be loaded again)
}
if (window.Wayhint?.ready) start(window.Wayhint);
else addEventListener('wayhint:ready', (e) => start(e.detail.api), { once: true });
addEventListener('wayhint:error', (e) => console.warn('Pepper did not start:', e.detail.reason));Keep areas private
data-guide-privateon any element: the guide sees “(private)” instead of its text.data-guide-ignore: the element and everything inside it are invisible to the guide.
Input values are never read, and emails and long numbers in labels are masked in the browser in any case. More on security.
Content Security Policy
If your site sends a CSP header, add the guide host to these directives (merge with what you already have):
script-src https://YOUR-GUIDE-HOST 'wasm-unsafe-eval';
connect-src https://YOUR-GUIDE-HOST;
worker-src blob:;
style-src 'unsafe-inline';wasm-unsafe-eval and blob: workers are for the 3D model’s Draco decoder. The inline style is the widget’s own stylesheet inside its shadow root. The 3D chunk (character-….js) and model folder come from the same host as guide.js, so one host covers them; with a nonce-based policy, put the nonce on the guide.js tag and the widget passes it on. In lite mode, script-src for the host, the inline style and connect-src for the API are all it needs.
What the guide can’t see
- Content inside cross-origin iframes (an embedded payment form, for example).
- Apps drawn entirely on a canvas.
- Closed shadow roots, unless the tag has
data-shadow="capture"and loads before your app. Open shadow roots and web components are fine.
Pick your platform
Plain HTML
If you can edit the HTML of your pages, this is the whole install.
WordPress installer soon
Pepper works on any WordPress theme because it reads the page the browser renders, not your theme files.
Webflow
Webflow lets you add site-wide code in the project settings. That is all Pepper needs.
Shopify installer soon
Pepper can walk shoppers to size guides, shipping info and the right product filters.
React (Next.js, Vite)
Pepper notices client-side route changes (pushState, popstate), so a guided goal keeps going as your SPA navigates.
Angular
The Angular router uses the History API, which Pepper watches, so guided goals carry on across routes.
Google Tag Manager
If your marketing team manages scripts in GTM, Pepper can go in without a code deploy.