Revenue attribution
Stripe
Attribute Stripe Checkout and Payment Link payments to the visitor and channel that earned them.
Snippets use YOUR_SITE_ID as a placeholder. Sign in and they're filled in with your real site id.
VisitTrack reads Stripe's checkout.session.completed event, so it works for anything that goes through Stripe Checkout: Checkout Sessions you create from your server, and Payment Links.
1. Connect Stripe
- In Stripe, create a restricted key with read-only access (Developers → API keys → Create restricted key). VisitTrack never needs write access.
- Open Settings → Revenue → Stripe in VisitTrack and copy the webhook URL:
https://visitrack.app/api/stripe-webhook/YOUR_SITE_ID. - In Stripe: Developers → Webhooks → Add endpoint. Paste the URL and select
checkout.session.completedandcharge.refunded. - Paste the restricted key and the endpoint's signing secret (
whsec_…) into VisitTrack and press Connect.
2. Pass the visitor id
Checkout Sessions
Send the visitor id from the browser to the endpoint that creates the session, and set it as client_reference_id.
// The tracker stores one anonymous id per browser. Read it on the page
// that starts checkout and send it along with the checkout request.
const visitorId = window.visitrack?.visitorId?.() ?? localStorage.getItem("_ana_vid");
const res = await fetch("/api/checkout", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ priceId, visitorId }),
});
window.location.href = (await res.json()).url;Payment Links
Payment Links accept client_reference_id as a URL parameter. Append it to every link on the page:
<script>
document.addEventListener("DOMContentLoaded", () => {
const visitorId = localStorage.getItem("_ana_vid");
if (!visitorId) return;
document.querySelectorAll('a[href^="https://buy.stripe.com/"]').forEach((a) => {
const url = new URL(a.href);
url.searchParams.set("client_reference_id", visitorId);
a.href = url.toString();
});
});
</script>PaymentIntents and Invoices aren't attributed
Only payments that go through Checkout (checkout.session.completed) are recorded. A PaymentIntent you confirm yourself, or an invoice paid outside Checkout, has no client_reference_id. Route those through Checkout, or send them with the server-side events API.
Events
| Event | What VisitTrack does |
|---|---|
checkout.session.completed | Records the payment (amount_total, currency, customer email) against the visitor in client_reference_id. |
charge.refunded | Subtracts the refunded amount from the original payment, including partial refunds. |
| anything else | Acknowledged with 200 and ignored. |
Test it
- Open your site in a normal browser tab so the tracker records a visit (localhost is ignored unless the script tag has
data-allow-local). - Complete a checkout in test mode.
- Open Revenue in the dashboard. The payment shows up within a few seconds, with the referrer, campaign and landing page that brought that visitor in.
Nothing showed up?
See Missing or unattributed payments. The webhook response body always says why a payment was skipped.
Something missing? Tell us.
AI agent or LLM? Read this page as markdown.