Protokit

Payments

Subscriptions via Lemon Squeezy, and Stripe for revenue attribution

Payments

Datyze uses two separate, unrelated payment integrations. Don't confuse them:

  • Lemon Squeezy — Datyze's own billing (how customers pay for their Pro/Business subscription).
  • Stripe — a product feature for customers (revenue attribution), not Datyze's billing.

Billing — Lemon Squeezy

Lemon Squeezy is the sole billing provider. It is a Merchant of Record, so it handles VAT/sales-tax compliance and payouts.

Configuration

LEMONSQUEEZY_API_KEY="..."
LEMONSQUEEZY_STORE_ID="..."
LEMONSQUEEZY_WEBHOOK_SECRET="..."
LEMONSQUEEZY_TEST_MODE="true"   # set to "false" in production
 
# One variant id per plan/interval
LEMONSQUEEZY_PRO_MONTHLY_VARIANT_ID="..."
LEMONSQUEEZY_PRO_YEARLY_VARIANT_ID="..."
LEMONSQUEEZY_BUSINESS_MONTHLY_VARIANT_ID="..."
LEMONSQUEEZY_BUSINESS_YEARLY_VARIANT_ID="..."

How it works

  • Plans and pricing live in packages/lemonsqueezy/src/config.ts (PRODUCTS).
  • Checkout is created via createLemonSqueezyCheckout() (@lucashochart/lemonsqueezy); the route is POST /api/lemonsqueezy/checkout.
  • The webhook (POST /api/lemonsqueezy/webhook) verifies the HMAC signature and keeps the subscription table in sync (status mapped to Stripe-compatible names).
  • getTeamPlan() (@/lib/billing) is the single source of truth for a team's effective plan. It also honours complimentary plans granted by an admin (team.compedPlan / compedUntil).

Free plans for a user

Admins grant a complimentary Pro/Business plan from Admin → Users → a user → Complimentary Plan (or Admin → Teams → a team). This bypasses Lemon Squeezy entirely. Percentage discounts are managed natively in the Lemon Squeezy dashboard.

Revenue attribution — Stripe (and others)

This is a feature for Datyze customers: they connect their own payment provider so Datyze can tie their revenue to the visitors and channels that drove it. It never touches Datyze's own money.

  • Stripe — one-click connect via Stripe Connect OAuth (/dashboard/sites/[siteId]/integrations). Needs STRIPE_SECRET_KEY, STRIPE_CONNECT_CLIENT_ID, STRIPE_CONNECT_WEBHOOK_SECRET.
  • Lemon Squeezy / Paddle — a per-site webhook + the visitor id in custom data.
  • Any provider — the authenticated POST /api/v1/payments API with the site's API key.

Attribution relies on the tracker exposing window.datyze.visitorId, which the site attaches to its checkout (e.g. Stripe client_reference_id). Revenue is stored in the revenue_event table.

In cookieless mode the tracker fetches its own daily visitor hash from /api/whoami and exposes it as window.datyze.visitorId (kept in memory, never stored on the device). Attribution works for conversions that happen the same day as the visit; cross-day attribution requires the consent-based full mode.

Privacy modes (cookieless vs full)

Every site picks a privacy mode at onboarding (and can change it under Site settings → Confidentialité). The choice is stored on the site (privacyMode) and decides the install snippet.

  • Cookieless (default, recommended) — GDPR-compliant with no consent banner. No device storage; the server derives a daily visitor hash. Audience metrics (daily visitors, pageviews, country). One line to install:

    <script defer data-site="YOUR_PUBLIC_KEY" src="https://datyze.fr/tracker.js"></script>
  • Full pack — everything cookieless, plus consent-gated enhanced tracking (multi-day journeys, returning visitors, identify() / LTV). Without consent it falls back to cookieless, so no data is ever lost. Adds the consent banner:

    <script defer data-site="YOUR_PUBLIC_KEY" src="https://datyze.fr/tracker.js"></script>
    <script defer data-site="YOUR_PUBLIC_KEY" src="https://datyze.fr/banner.js"></script>

Privacy mode (tracking richness) is independent from the public dashboard toggle (which makes your stats visible and powers the embeddable widget).

Sites that want enhanced tracking (visitor journeys, returning visitors, identify()) add the Datyze consent banner alongside the tracker. It is themed from your site settings and calls the tracker's consent API automatically:

<script defer data-site="YOUR_PUBLIC_KEY" src="https://datyze.fr/tracker.js"></script>
<script defer data-site="YOUR_PUBLIC_KEY" src="https://datyze.fr/banner.js"></script>

The banner only appears when no choice has been stored yet, and never under Do Not Track / Global Privacy Control. Optional attributes: data-lang (fr/en), data-position (bottom-left, bottom-right, bottom), data-privacy-url.

On this page