Skip to content

traffic.cx documentation

Lemon Squeezy Revenue Attribution Setup

Connect Lemon Squeezy to traffic.cx and pass the visitor's IDs as checkout custom data.

Updated 14 October 2026

traffic.cx reads orders, subscription renewals and refunds.

Install the tracker first. You need an owner/admin role in traffic.cx and access to your Lemon Squeezy store's API settings. Connect test mode to a separate traffic.cx test site while verifying; test orders appear in that site's reports. traffic.cx creates a webhook in the selected store.

1. Connect

  1. In Lemon Squeezy, open Settings → API and create an API key. A test-mode key connects your test store.
  2. In traffic.cx, open Settings → Revenue, choose Connect next to Lemon Squeezy and paste the key. If the account has several stores, also enter the store's ID.

traffic.cx adds a webhook to the store (signed with a secret it generates), and imports the last 90 days.

2. Pass the visitor's IDs

Send them as checkout custom data, in the checkout URL or through the API.

html

<a href="https://yourstore.lemonsqueezy.com/checkout/buy/VARIANT_ID" data-lemon-link>Buy now</a>
<script>
  document.querySelectorAll('[data-lemon-link]').forEach((link) => {
    link.addEventListener('click', () => {
      const url = new URL(link.href);
      const pageview = window.trafficcx?.pageviewId?.();
      const vid = window.trafficcx?.visitorId?.(); // cookie mode only
      if (pageview) url.searchParams.set('checkout[custom][tcx_pvid]', pageview);
      if (vid) url.searchParams.set('checkout[custom][tcx_vid]', vid);
      link.href = url.toString();
    });
  });
</script>

Use your store's actual checkout link. This example uses normal link navigation; if you use an overlay SDK, pass the custom data through that SDK's checkout configuration before opening it. See Lemon Squeezy's custom-data guide.

js

// Or when you create the checkout on your server
// tcx is the validated object from the browser identifier handoff.
const response = await fetch('https://api.lemonsqueezy.com/v1/checkouts', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.LEMONSQUEEZY_API_KEY}`,
    Accept: 'application/vnd.api+json',
    'Content-Type': 'application/vnd.api+json',
  },
  body: JSON.stringify({
    data: {
      type: 'checkouts',
      attributes: { test_mode: true, checkout_data: { custom: tcx } },
      relationships: {
        store: { data: { type: 'stores', id: process.env.LEMON_STORE_ID } },
        variant: { data: { type: 'variants', id: process.env.LEMON_VARIANT_ID } },
      },
    },
  }),
});
if (!response.ok) throw new Error('Lemon Squeezy checkout failed');
const checkout = await response.json();
const url = checkout.data.attributes.url;

Get tcx from the identifier handoff, configure the server-only credentials and store/variant IDs, and return url from your existing endpoint. Keep authentication and cart validation. Use a live key and test_mode: false only when moving to live checkout. The checkout API reference describes those fields.

What traffic.cx records

WebhookRecorded as
order_createdThe payment (paid orders only), including a subscription's first payment
subscription_payment_successA renewal (the first payment is counted with its order)
order_refunded, subscription_payment_refundedThe refunded amount, as one refund that grows with each partial refund

Amounts leave out the tax Lemon Squeezy collects. Historical order imports do not include checkout custom data. They can remain Unattributed when no recorded visit or earlier customer payment supplies a link.

3. Verify and troubleshoot

Use the attribution test flow with a test checkout. Inspect the webhook's meta.custom_data for tcx_pvid and, in cookie mode, tcx_vid. Confirm the order appears once, then verify a subscription renewal and refund if you use those flows.

  • Wrong store: specify the store ID when the API key can access several stores.
  • No orders: check that the key, product and checkout are in the same test/live mode. An unpaid order does not create revenue.
  • Unattributed imported orders: historical order reads do not provide checkout custom data; connecting today cannot reconstruct an earlier missing visit link.
  • Custom data missing: check the final checkout URL or API request, then the delivered webhook. Do not put IDs in an unrelated metadata field.

Test keys only access test-mode store data; use the provider's test-mode instructions. The connector and examples are checked with fixtures; a fresh purchase in your account remains a setup verification step.

Need a hand with your setup?

Contact supportPlans and trial details