askbowtie

askbowtie does not set cookies on your visitors' browsers. Not first-party, not third-party, not "analytics" cookies. This is by design, not by accident.

This page explains how it works, why it matters, and how to keep your integration cookie-free when you add server-side conversion tracking.


How sessions work without cookies

The tracker stores a random session ID in the browser's localStorage under the key bowtie_session. This is fundamentally different from a cookie:

Cookie localStorage
Sent to server automatically Yes, on every HTTP request No — never sent unless you explicitly read and pass it
Readable by other domains Third-party cookies can be No — same-origin only
Requires consent banner (EU) Usually yes, for analytics No — not classified as a tracking cookie
Survives incognito No No
Can be blocked by browsers Increasingly, yes Rarely

The session ID is random, anonymous, and not linked to any personal identity. It expires after 30 days or 30 minutes of inactivity, whichever comes first.


What this means for compliance

Because the tracker sets no cookies and collects no personal data:

If your site already has a cookie banner for other tools (Google Analytics, ad pixels), askbowtie doesn't need to be listed in it.


Server-side conversions without cookies

When you need to track conversions server-side (payment webhooks, form processing, CRM events), you need to get the session ID from the browser to your backend. You do not need a cookie for this.

The right way: pass it explicitly

Read the session ID from localStorage and include it in whatever triggers your server-side code:

Forms and checkouts — hidden field:

<input type="hidden" name="bowtie_session" id="bowtie_session">
<script>
document.getElementById('bowtie_session').value =
  localStorage.getItem('bowtie_session') || '';
</script>

AJAX / SPAs — include in the request body:

const sessionId = localStorage.getItem('bowtie_session');

fetch('/api/checkout', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ ...formData, bowtie_session: sessionId })
});

Stripe / payment processors — pass it as metadata when creating the checkout session, then read it back in the webhook. The example is Stripe's Node SDK, but every processor has an equivalent metadata field:

// When creating the checkout session (server-side)
const checkout = await stripe.checkout.sessions.create({
  metadata: { bowtie_session: req.body.bowtie_session || '' },
  // ... line items, success_url, etc.
});

// In the webhook handler
const sessionId = event.data.object.metadata.bowtie_session || null;

Client-side only — if you can detect the conversion in JavaScript, no server-side code needed:

bowtie.converted('purchase', { value: 99.00 });

What not to do

Do not mirror bowtie_session from localStorage to a cookie. This pattern has appeared in some integrations:

// Don't do this — it defeats the cookieless design
setInterval(() => {
  const s = localStorage.getItem('bowtie_session');
  if (s) document.cookie = `bowtie_session=${s};path=/;max-age=86400;SameSite=Lax`;
}, 1000);

This creates a cookie that:

Every use case this cookie solves has a better alternative above.


Decision guide

Your situation Solution Cookie?
Track conversions in JavaScript (thank-you page, SPA) bowtie.converted() No
Form submission triggers a conversion server-side Hidden <input> field No
AJAX call triggers a conversion server-side Include in request body No
Payment webhook (Stripe, PayPal) Pass as checkout metadata No
Server-side error or guardrail tracking Read from request (form/AJAX) No
Backend-only event with no browser context Send without session ID — event still tracked, just not linked to a session No

Verifying your integration is cookie-free

Open your browser's DevTools, go to Application > Cookies, and check your domain. You should see:

Under Application > Local Storage, you should see:

These localStorage entries are never sent to any server automatically.


Related