Docs

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.

html
<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

AttributeWhat it does
data-site-keyRequired. Your site key.
data-apiWhere the guide API lives, for example one running in your own infrastructure. Defaults to the origin the script was loaded from.
data-accentColour of the buttons and highlight ring, as a hex colour, for example #d12f25.
data-characterlite for the 2D guide only (never loads the 3D character), or 3d. Overrides the 3D / Lite setting in the dashboard.
data-preload3d 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.

html
<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.

js
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-private on 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):

csp
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