Submissions, cookies, tracking and privacy

Contents

Updated 5 October 2026. October fixes are local, not deployed. Earlier code extracts retain their September snapshot context; current confirmation/source checks and test evidence are in the fix record. This explains the code and its limits. It does not verify live tag-container settings, provider retention policies, downstream CRM configuration, or legal compliance.

1. Four separate permissions

Choice What it controls What it does not authorize
Functional cookies Makes the AI widget available after explicit saved acceptance; also controls scripts assigned to that category. Sending an enquiry or subscribing to marketing.
Analytics cookies Google Consent Mode analytics_storage and category-tagged deferred analytics scripts. AI contact submission or marketing subscription.
Marketing cookies Advertising storage, ad user data/personalization signals, and category-tagged marketing scripts. An email newsletter subscription merely because the visitor accepted cookies.
Conversational send consent Permission to submit the particular enquiry or requested agenda after its summary/confirmation. Blanket permission to submit future enquiries or subscribe to campaigns.

The agenda-email payload has a separate opt_in field for hearing more about the event. It defaults to false. The tool instructs the model to set it only when explicitly requested; this is not a dedicated, independently verified subscription ledger. The generic lead payload has a consent field and explicitly sets opt_in: false; this flow does not collect a separate marketing opt-in. CRM automation must preserve these distinctions.

Call wording: “Accepting cookies makes the assistant available. Sending something to the team requires a separate conversational confirmation. Marketing subscription is a separate choice again.”

Preferences are stored in browser localStorage, under cc-consent, as versioned functional/analytics/marketing booleans and a decision timestamp. Despite the feature’s cookie terminology, this preference record itself is not a browser cookie. Essential functionality is always allowed.

The website supports regional opt-in/opt-out script strategies. Opt-out regions can have effective non-essential script defaults before a saved choice. The AI gate deliberately requires saved functional acceptance even there.

This UI gate is not a server authentication or consent-proof mechanism. The AI APIs do not independently verify the localStorage cookie preference. Unmounting the widget does not erase its sessionStorage, delete remote traces, recall an accepted webhook, or guarantee that server work already started stops.

Source: consent-state.ts:7

export type StoredConsent = {
    v: 2
    functional: boolean
    analytics: boolean
    marketing: boolean
    decidedAt: number
}

The application first pushes denied defaults for analytics/ad storage and ad data/personalization. Saved/effective consent then updates those signals:

Source: gtm.ts:41

gtag('consent', 'update', {
        analytics_storage: c.analytics ? 'granted' : 'denied',
        ad_storage: c.marketing ? 'granted' : 'denied',
        ad_user_data: c.marketing ? 'granted' : 'denied',
        ad_personalization: c.marketing ? 'granted' : 'denied',
    })

Depending on the configured cutover, the loader uses Stape or the Google GTM loader. Category-tagged text/plain script placeholders are converted into executable scripts only when their category is allowed.

“Analytics denied” does not mean “no network requests.” The implementation supports Consent Mode/cookieless behavior and can load the configured tag container with denied signals. Actual tags and downstream behavior depend on the deployed container/vendor configuration, which this document has not audited.

Likewise, the deferred-script helper activates allowed scripts; it does not unload scripts that have already executed or purge every vendor’s cookies on withdrawal. Consent updates are sent, but vendor cleanup and tag compliance need separate verification.

4. What happens before an enquiry leaves the application

  1. The visitor requests help; the flow gathers only missing information.
  2. The assistant presents the intended request and recipient/contact details, with a consent question.
  3. A bounded affirmative reply is recognized only after the current handoff question. Negative/conditional replies and unrelated changes are not send authorization. Cancellation or withdrawal stops the pending contact flow.
  4. Tool execution checks consent, event, allowed intent, required name/email and email format. Agenda sends additionally validate selected sessions against the catalogue.
  5. Immediately before dispatch, the server re-reads published Sanity permissions.
  6. Only then does it POST to the configured Zapier endpoint.

Production visibility defaults off. The independent Allow email / contact submissions master switch also defaults off and overrides both submission tools. Individual tools can be disabled as well. With submissions disabled, contact qualification should not start or resume; informational help and in-chat agendas can remain available.

The separate Allow submissions on staging only setting applies only to Vercel Preview on pre-prod; it cannot grant production access. Other environments use the main submission setting. To disable sends on pre-prod, disable its staging permission too. This documents the configuration contract, not a live audit of the current switches.

Saved send consent helps preserve a decision across email corrections, but it is not permission to send a new request without a new summary/confirmation. The browser-provided history/profile/consent are not authenticated identity or a tamper-proof audit record. Some safeguards are code checks, others depend on conversation recognition and prompt adherence; avoid claiming an infallible consent state machine.

Source: aiCapabilityPolicy.ts:107

const config = await readSettings()
    if (!isVisible(config) || !aiToolEnabled(config, name))
        return {
            ok: false,
            error:
                'Contact submissions are currently unavailable. Nothing has been sent.',
        }
    return submit()

5. What data is submitted, and where

Both tools send to ZAPIER_LEAD_WEBHOOK_URL. The application adds source: unleash-ai-chat and a collection timestamp.

Payload Included fields
Lead Type, trigger, consent boolean, chat ID, page path (location), enquiry summary, Salesforce intent, name, email, role, company, interests, stage and opt_in: false.
Agenda email Type, chat ID, page path, name, email, event, separate opt-in and consent booleans, intent, role/company/interests and server-formatted Markdown agenda (capped at 20,000 characters) and agenda_html.

Here location means the website path, not GPS coordinates. These payloads do not include the full transcript, although personal information may appear in the enquiry summary. Contact data must remain usable in the handoff; telemetry masking does not mask the submitted email address.

Zapier is the application’s handoff boundary. Code comments describe downstream Salesforce lead creation and Postmark agenda delivery, but those systems’ current automation and configuration were not inspected for this guide.

A successful HTTP response means accepted by Zapier, not independently verified CRM persistence or inbox delivery. Missing configuration, timeout (15 seconds), and non-2xx responses are failures. A captured 503 is never a successful submission. Failed handoffs end qualification and use Support; they do not automatically resubmit. There is no application-level exactly-once delivery guarantee; downstream deduplication must be verified separately.

Source: leads.ts:198

type: 'agenda-email',
        chat_id: submission.chatId,
        location: submission.location || undefined,
        name: submission.name,
        email: submission.email,
        event: submission.event || undefined,
        opt_in: submission.optIn ?? false,
        consent: submission.consent ?? false,

6. Where conversation data is processed and retained

Layer Data/use Boundary to understand
Browser sessionStorage Chat ID, transcript, extracted profile and conversational consent. Session-scoped browser memory; cookie withdrawal does not explicitly clear it.
AI Gateway/model calls Messages/context needed for answering and profile extraction; recent context for routing. Data is processed externally even when email submission is disabled.
Pinecone/OpenAI embeddings Retrieval queries and indexed source content. Embedding/search requests are separate from contact submission.
Process-local workflow map Chat ID, workflow, event and update time. No contact details; one-hour expiry, not durable shared state.
Langfuse tracing Model/tool activity, prompts/results as captured by instrumentation, session correlation and review scores. Server-side observability, not governed by the browser analytics-cookie flag.
Background review Conversation evidence and response sent to a review model to identify possible problems. Runs unless AI_CONVERSATION_REVIEW=off; up to 24,000 response characters captured.
Zapier/downstream systems Approved enquiry/agenda payload. Separate retention, access, deletion and delivery operations.

Jev’s call explicitly requests Gateway zeroDataRetention: true. That one provider option must not be described as a system-wide guarantee for every model, traces, CRM, or other service.

Langfuse export masking replaces many non-UNLEASH email addresses and phone patterns. Names, companies, free text and unmatched formats can remain. Masking is partial redaction, not anonymization, and does not stop the underlying model from processing the original request.

Source: aiTelemetry.ts:30

if (typeof value === 'string') {
        return value
            .replace(EMAIL_PATTERN, (email) =>
                email.toLowerCase().endsWith('@unleash.ai') ? email : '[email redacted]',
            )
            .replace(PHONE_PATTERN, '[phone redacted]')
    }

7. Privacy requests and contact addresses

The assistant is instructed not to reveal/list/export the visitor’s stored personal information. Recognized requests receive a fixed referral to support@unleash.ai for privacy-policy or data-processing questions. It can still accept corrections and include details in the agreed pre-send summary. A visitor volunteering contact details is not asking for stored-profile export; referring to “that email address” does not trigger unrelated contact redirection.

This is a referral mechanism, not a data export/deletion endpoint or identity-verification process. The assistant cannot promise that saying “delete my data” erased browser, trace, CRM and provider records.

For clearly sponsorship/exhibitor-related help the contact address is customersuccess@unleash.ai. All privacy/data-processing questions and other/ambiguous support requests use support@unleash.ai.

8. What is established versus what needs operational confirmation

The code establishes cookie-based widget gating, separate send confirmation, tool/production switches, execution-time permission checks, payload shapes, consent-mode signals, and partial trace masking.

It does not establish deployed GTM/Stape tag compliance, provider retention/residency, access-control policies, CRM marketing suppression, subscription evidence requirements, real inbox delivery, or end-to-end deletion handling. Those are concrete questions for the relevant system owners; this guide makes no legal-compliance certification.

The October checks verified confirmation after reused details, corrected recipients, cancellation, accepted/rejected local handoffs and honest 503 failure messaging. They did not verify real SMTP bounce or CRM/email behavior. Report and operational boundaries.

Three useful call questions:

Code references