Consent mode
If your site asks for consent before storing anything (a cookie banner), adddata-consent="required" to the snippet:
JunDesk.consent(true) when the visitor accepts, and JunDesk.consent(false) if they withdraw:
consent() takes a boolean. You can call it as often as the visitor changes their mind.
The loader doesn’t remember consent between page loads. Call
JunDesk.consent(true) on every page where your consent tool says the visitor has already agreed.Before and after consent
JunDesk.consent(false) closes the live connection (the visitor drops off your Visitors list), deletes jun:session and jun:e from your page’s storage, and deletes what the chat frame stored in localStorage.
Without data-consent="required", the widget acts as if consent was given from the start.
What the widget stores
Even without consent mode, the widget stores very little, and nothing on the chat side until a visitor writes.
A session ends after 30 minutes without a page view or a visible tab, or after 24 hours; the next page load starts a new one. Older versions of the loader used
jun:s and jun:t in sessionStorage; they’re no longer used.
No cookies. Opening the chat without writing stores nothing in the chat frame. JunDesk.logout() replaces the session and forgets the visitor token (Identify users).
What the widget sends
While the visitor browses (the live connection behind the Visitors list):- the page address, with query values removed (campaign tags kept, see below), and the page title, masked;
- the referrer, cleaned the same way;
- when the session started, how many pages it has viewed, its campaign tags, the browser’s language and time zone.
data-capture="off" and the snapshot has no events at all.
When something breaks and nudges are on, the loader sends the one masked event and the page to the desk to word a “Want a hand?” line. Nothing is stored for it.
What is never captured
- Request or response bodies, for any request.
- Cookies,
localStorage,sessionStorageor anything else your page stores. - What visitors type into your forms.
- The text of your page. Rage clicks and dead clicks keep only the element’s tag,
id,aria-label,nameandrole, and a button’s or link’s visible label when it’s 40 characters or shorter. “Stuck” events keep only the page path. - Query string values. URLs keep their path and the names of query parameters (
/search?q=…), never the values. The one exception is campaign tags:utm_source,utm_medium,utm_campaign,utm_termandutm_contentkeep their values, masked and cut to 80 characters. - Clicks inside the widget itself, or scripted clicks.
Masking, twice
Everything that leaves the browser is masked by the loader first. The desk then masks it again with the same rules, drops unknown fields, and caps every length, so a modified loader can’t slip anything through.
Error messages are cut to 500 characters, stacks to their first five lines, and app error messages from
reportError() to 300. App events from track() keep a name of up to 60 characters and up to 10 properties; string values are masked and cut to 100 characters, and anything that isn’t a string, number or boolean is dropped. Don’t send personal data in them.
Who sees what
- Your agents see the debug context in the conversation’s Browser panel, and the contact’s details.
- The AI gets the events as plain lines in its prompt. The optional error codes from
reportError()are for your team only: the AI answering visitors never sees them, so it can’t repeat one. - Other visitors never see anything about anyone else.
- Issue drafts (Issues) are built from the masked context and masked again before they’re sent to GitHub or Linear.
Turning capture off
data-capture="off" stops the loader from listening for errors, failed requests, rage clicks, dead clicks and stuck pages, makes reportError() and track() do nothing, and turns off the “something broke” nudges with them. Page openers, the live visitor list and the chat still work.
Debug context
What’s captured and how agents and the AI use it.
Security
How the desk handles secrets and tokens.