Skip to main content
The widget is built to collect as little as it can, and to mask what it does collect twice: in the visitor’s browser and again on your desk. This page lists exactly what it stores and sends, and how to make it wait for cookie consent. If your site asks for consent before storing anything (a cookie banner), add data-consent="required" to the snippet:
Then call 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.
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.
The Get started checklist detects your install through the live connection, so with consent mode it ticks only after a visitor consents. Press I’ve added it if you want to tick it yourself.

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.
The desk adds the country, city and a rough location (rounded to 0.1°) from Cloudflare’s request data, and the user agent. When the visitor sends a message, a debug snapshot goes with it: the page, browser, viewport, language, time zone, and up to 40 recent events. See Debug context for the full list. Set 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, sessionStorage or 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, name and role, 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_term and utm_content keep 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.
Internal notes, tags and topics never reach visitors or the AI’s answers.

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.