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:
- No cookie consent banner required for the askbowtie script
- GDPR-friendly — anonymous error and performance monitoring doesn't require consent under most interpretations
- ePrivacy Directive — localStorage for anonymous analytics generally falls outside cookie consent requirements
- Removing the tracker leaves no trace — no residual cookies, no orphaned 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:
- Gets sent to your server on every HTTP request (bandwidth waste)
- May require a cookie consent banner
- Polls every second (unnecessary CPU work)
- Undermines the "no cookies" claim you can make about your site
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:
- Your app's own session cookie, if it sets one — that's your framework, not askbowtie
- No
bowtie_sessioncookie - No
bowtie_debugcookie (unless you manually enabled debug mode)
Under Application > Local Storage, you should see:
bowtie_session— the anonymous session IDbowtie_uid— present only if you callbowtie.identify()to connect a visitor's sessions (see the JavaScript API). Sites that never call it won't have this key.
These localStorage entries are never sent to any server automatically.
Related
- Installing the Tracker — Setup instructions
- Server-Side Conversions — Full server-side tracking guide
- Privacy Policy — What data is collected and how it's handled
- Security & Data Privacy — Technical security details