Guides
Install Customer messenger
Messenger runs inside your product for signed-in users, whose identity your server signs, and can also run on public pages for anonymous website visitors. In your workspace, Settings → Customer messenger → Installation shows this guide with your public key already filled in.
Before you start
Signed-in users, and optionally visitors
In your product, your server signs who each user is. On public pages such as a marketing site, turn on anonymous visitors under Experience and skip the server step.
Trusted website origins
Add every origin that will load Messenger, such as
https://app.acme.comandhttp://localhost:3000.Two server settings
RIDGETOP_WIDGET_SECRETis the signing secret.RIDGETOP_MESSENGER_ORIGINis the origin of the page that loads Messenger. Keep both out of browser code.
Step 1: Create a signed identity endpoint
Your server tells Messenger who the signed-in user is, signed so the browser cannot change it. Serve it from your product's own domain, behind your normal login.
- Sign the exact string you send. Serialize the JSON once, sign it, and return that string unchanged. Re-encoding it on the way out breaks the signature.
- Use the secret as text. HMAC-SHA256 keyed with RIDGETOP_WIDGET_SECRET exactly as shown, hex-encoded. Do not hex-decode the secret first.
- Sign the page's origin, not the endpoint's. Set RIDGETOP_MESSENGER_ORIGIN to the origin where Messenger loads, such as https://app.acme.com. It must match a trusted origin exactly.
- Fresh, in seconds, never cached. iat is Unix time in seconds and expires after 5 minutes. Respond with Cache-Control: no-store, so no proxy or CDN ever serves one user's identity to another.
- 401 when signed out. Messenger is for signed-in users. Return 401 rather than a redirect, so the browser code can skip Messenger cleanly.
- company is optional. Send it only for users who belong to an organization, and include both a stable id and a name.
Step 2: Load Messenger in your frontend
Load widget.js from Ridgetop with a script tag, start Messenger once the user is signed in, and shut it down when they sign out so the next person on the device never sees their conversations.
Using another framework? Follow the same pattern: load the script once, call Ridgetop.boot after sign-in with identity as a function, and call Ridgetop.shutdown() on sign-out. Single-page navigation is tracked automatically.
One site with both signed-out and signed-in pages? With anonymous visitors on, have your identity function return null when the endpoint answers 401. Messenger continues as a visitor, and their conversations move to their account when they sign in.
Step 3: Add properties, events, and consentOptional
Enrich conversations with user and company properties, record product events, and respect analytics consent.
Step 4: Check the connection
Open a page with Messenger installed while signed in. The browser console explains any problem with a Ridgetop: message.
- Console: "the signed origin … does not match this page's origin"
- Set RIDGETOP_MESSENGER_ORIGIN to the exact origin of the page, including scheme and port, with no trailing slash.
- Console: "this page's origin is not in Trusted website origins"
- Add the origin under Identity & security → Trusted website origins, and save.
- Console: "the signature does not match"
- Check that the server uses the current signing secret, and returns the same payload string it signed.
- Console: "the signed identity is more than 5 minutes old"
- Create the identity on every request, with iat in seconds, and make sure the endpoint is not cached.
- Console: "load widget.js with a <script> tag"
- widget.js was bundled or inlined. Load it from your Ridgetop URL with a script tag instead.
- Console: "anonymous visitors are turned off"
- A page booted Messenger without an identity. Turn on anonymous visitors under Experience, or pass identity on that page.
- No launcher appears
- The launcher shows only once a session starts. Check the console for a Ridgetop: message explaining why it did not.
- Ridgetop is not defined
- boot ran before widget.js finished loading. Call it from the script's onload, or onReady in Next.js.