STAGING - data last refreshed unknown

Revenue Attribution

Attribute revenue to traffic sources with first-touch and last-touch models.

Revenue Attribution

EngageTrack connects your revenue data to traffic sources, giving you a clear picture of which channels drive actual business results.

How It Works

  1. Visitor Identity — The SDK generates a persistent visitor ID (localStorage) and a session ID (sessionStorage) to track visitor sessions. Access them via window.engagetrack.getVisitorId() and window.engagetrack.getSessionId().
  2. Source Tracking — Every session records the traffic source (UTM parameters, referrer, direct)
  3. Revenue Events — When a purchase occurs, EngageTrack receives a webhook from your payment provider and links the payment to the originating session
  4. Attribution — Revenue is attributed to the original traffic source using a four-level priority chain (see Attribution Models below)

Payment Provider Webhooks

EngageTrack receives payment events directly from your provider via webhooks. Connect your provider in Site Settings → Revenue:

ProviderConnection Method
StripeAPI Key
Lemon SqueezyAPI Key + auto-webhook
PaddleAPI Key + auto-webhook
PolarAPI Key + auto-webhook

EngageTrack automatically registers the webhook on your provider during connection. No manual webhook setup is required.

Manual Revenue Tracking

For custom payment flows, use the JavaScript API:

engagetrack.trackPurchase("ORD-789", 149.99, "USD");
// signature: trackPurchase(orderId, revenue, currency)

Client-side trackPurchase runs in the browser — it can fail if the user closes the tab before the success page loads, if an ad-blocker removes the SDK, or if someone calls it manually from the console. For verified revenue use the server-side flow below.

Server-Side Revenue Tracking

When your payment processor is not natively supported (for example Netopia, PayU, or any custom checkout), you can record revenue from your backend after verifying the payment notification signature yourself. This is the recommended approach for producers that deliver a webhook / IPN to your server on a confirmed payment.

The same POST /api/v1/event endpoint that powers the tracking script accepts server-side calls. No API key is required — the site is identified by its public ID.

  1. On your checkout page, capture the visitor and session IDs and the current URL (including any utm_* query parameters) before the redirect to the payment processor:

    // On the checkout / pay-now page, BEFORE redirecting to the processor:
    const payload = {
    	visitor_id: window.engagetrack.getVisitorId(),
    	session_id: window.engagetrack.getSessionId(),
    	checkout_url: location.href, // preserves utm_source, utm_campaign, etc.
    };
    await fetch("/api/checkout", {
    	method: "POST",
    	headers: { "Content-Type": "application/json" },
    	body: JSON.stringify({ ...payload, cart }),
    });
  2. Persist visitor_id, session_id, and checkout_url against the order record in your database.

  3. After the processor confirms payment (verify their signature / IPN as you normally would), call the EngageTrack ingest endpoint from your backend:

    curl -X POST https://api.engagetrack.net/api/v1/event \
    	-H "Content-Type: application/json" \
    	-d '{
    		"site_id": "YOUR_SITE_PUBLIC_ID",
    		"event_type": "purchase",
    		"url": "https://yourdomain.com/checkout?utm_source=facebook&utm_campaign=spring",
    		"visitor_uid": "<value you stored in step 2>",
    		"session_id": "<value you stored in step 2>",
    		"revenue": 249.99,
    		"currency": "RON",
    		"order_id": "ORD-12345"
    	}'

    A 202 Accepted response means the event was accepted into the ingest queue.

Field Reference

FieldRequiredNotes
site_idYesThe site's public ID (find it in Site Settings → Tracking).
event_typeYesMust be "purchase" for revenue events.
urlYesMust match your registered site domain. Include the original utm_* params for source attribution.
visitor_uidStrongly recommendedThe value from window.engagetrack.getVisitorId() captured on the checkout page. Without it the event is stored but not linked to the visitor.
session_idRecommendedThe value from window.engagetrack.getSessionId().
revenueYesNumeric amount (not cents — e.g. 249.99).
currencyYesISO 4217 code, e.g. RON, EUR, USD.
order_idYesYour order identifier. Used for deduplication on your side (see below).

Differences vs. Native Integrations

The native Stripe / LemonSqueezy / Paddle / Polar integrations do some extra work that the server-side ingest endpoint does not. Be explicit about these when you build:

  • Idempotency is your responsibility. Native webhooks are deduplicated by a (site_id, order_id) unique constraint. The ingest endpoint accepts the event every time it is called. If your processor retries the IPN, guard against double-counting in your own handler (e.g. an order_id → sent_at table with a unique index).
  • Attribution comes from the url you send. Native webhooks copy the UTM, referrer, and country fields from the visitor's most recent session event. The ingest endpoint reads UTM parameters only from the url query string of the current request. Always forward the original checkout URL (with its utm_* params) to preserve the channel breakdown in the Revenue dashboard.
  • No auto-created Revenue goal. Native integrations auto-create a Stripe Revenue / Polar Revenue goal so purchases appear under Goals. For custom processors create your own Goal manually (Goal type: Custom Event, Event name: purchase) if you want goal-based reporting.
  • Currency normalization runs only when an active native Revenue integration exists for the site. Without one, the raw revenue + currency are stored and the dashboard sums them as-is. If you invoice in a single currency this does not affect your totals.

Webhook Integration

For server-side revenue tracking (subscriptions, renewals), configure a webhook integration:

  1. Go to Site Settings → Revenue
  2. Select your payment provider (Stripe, Lemon Squeezy, Paddle, or Polar)
  3. Copy the webhook URL and add it to your provider's dashboard
  4. EngageTrack will match webhook events to visitors using the engagetrack_visitor_id in Stripe metadata
// Server-side: Add visitor ID to Stripe checkout
const session = await stripe.checkout.sessions.create({
	metadata: {
		engagetrack_visitor_id: visitorId, // from engagetrack.getVisitorId()
		engagetrack_session_id: sessionId, // from engagetrack.getSessionId()
	},
	// ...other options
});

Attribution Model

EngageTrack uses last-touch attribution based on the session data available at webhook time. When a payment webhook is received, the revenue is attributed to the traffic source of the most recent session associated with the visitor.

To ensure accurate attribution, pass the engagetrack_visitor_id and engagetrack_session_id as metadata in your payment provider's checkout flow (see the Webhook Integration section above). This allows EngageTrack to link the payment directly to the originating session and its traffic source.