Tracking Custom Websites & Checkouts
If you're building on a custom website or using a checkout platform that doesn't expose server webhooks (custom CMS, headless storefront, payment-link checkouts, custom funnels, etc.), you can still track purchases end-to-end by firing a single browser-side purchase event on your order confirmation page.
The event sends the order to TrueTracked and produces the same end result as a webhook integration: an entry in your orders table, server-side Meta CAPI / TikTok CAPI / GA4 Measurement Protocol fires, browser-side Meta Pixel / TikTok Pixel / GA4 / Google Ads conversion fires, identity stitching, and full attribution.
Already on Shopify or GoHighLevel? Use the dedicated webhook flows in the Integrations guide instead - those have native server-side order sources with richer data than the browser can provide.
Prerequisites
Before firing the purchase event, you need the TrueTracked base pixel installed on every page (including the order confirmation page). See the Pixel Installation guide for the base loader script. The purchase event uses the same SDK that powers your other tracking - no separate installation.
Quick example
On your order confirmation page (after a successful purchase), fire the event with the merchant's order details. This snippet works in any context where window.truetracked is loaded - directly in HTML, in a Custom HTML GTM tag, or inside your app code.
<script>
window.truetracked('track', 'purchase', {
// Required
transaction_id: 'ORDER-12345',
value: 47.00,
currency: 'USD',
// Strongly recommended (Meta CAPI EMQ score)
email: 'customer@example.com',
phone: '+15551234567',
first_name: 'Jane',
last_name: 'Doe',
shipping_country: 'US',
shipping_postal_code: '90001',
// Optional but useful
sub_total: 39.00,
tax: 4.00,
shipping: 4.00,
new_customer: true,
items: [
{
item_id: 'sku-1',
item_name: 'Widget',
price: 39.00,
quantity: 1,
item_sku: 'sku-1'
}
]
});
</script>How it works
- Browser fires
truetracked('track', 'purchase', {...}) - SDK auto-attaches the visitor's
tt_user_id,tt_session_id, fingerprints, and page context - no need to pass those manually - TrueTracked normalizes the payload, writes the order to your orders table, and runs identity stitching (so the order is linked to the visitor's journey)
- Server-side conversions (Meta CAPI, TikTok CAPI, GA4 MP) fire with the enriched order data - high match quality
- Browser-side pixels (Meta Pixel, GA4, TikTok Pixel, Google Ads) fire on the same event - using the same
transaction_idfor browser ↔ server deduplication
Required fields
These three fields are mandatory. The event will be dropped silently if transaction_id is missing or empty.
| Field | Type | Description |
|---|---|---|
transaction_id | string | Unique per order. Used as the deduplication key across browser pixel + server CAPI fires. |
value | number | Total purchase amount including tax and shipping (the number you want to attribute to your ads). |
currency | string | 3-letter ISO 4217 code (e.g. USD, EUR, GBP). |
Recommended fields
Pass as many of these as your checkout exposes. Each field directly raises Meta's Event Match Quality (EMQ) score - the difference between EMQ ~3 (low) and ~8+ (high) is whether Meta can properly attribute the purchase to the visitor's ad-click.
| Field | Type | Description |
|---|---|---|
email | string | Customer email - the strongest single identity signal for CAPI matching. |
phone | string | E.164 format preferred (+15551234567). |
first_name / last_name | string | Customer name - boosts EMQ even when email/phone are present. |
items | array | Array of { item_id, item_name, price, quantity, item_sku }. Drives product-level attribution. |
sub_total | number | Pre-tax, pre-shipping order amount. |
tax | number | Tax portion of the order total. |
shipping | number | Shipping cost charged to the customer. |
shipping_country | string | Customer country (e.g. US). |
shipping_postal_code | string | Customer ZIP / postal code - strong CAPI matching signal. |
new_customer | boolean | If you know whether this is a first-time customer, pass true / false. Otherwise omit and TrueTracked will look it up by email. |
Optional fields
| Field | Type | Description |
|---|---|---|
customer_id | string | Your internal customer ID, if you have one. |
external_id | string | Any merchant-controlled session/cart token. The visitor's tt_user_id is already the primary identity for browser-fired events; this is for cross-device stitching scenarios. |
coupon | string | Discount code applied to the order. |
discount | number | Total discount amount applied. |
shipping_country_code | string | 2-letter country code if different from shipping_country. |
shipping_province | string | State or province. |
shipping_city | string | City. |
source_name | string | Free-text channel label (e.g. website, mobile_app). |
note | string | Free-text note attached to the order. |
processed_at | string | ISO 8601 timestamp. Defaults to the moment the event is received. |
Google Tag Manager example
If your checkout already pushes order data to dataLayer, you can fire the purchase event from a Custom HTML tag triggered on the order confirmation page. Replace the data-layer variable references with your own.
<script>
window.truetracked('track', 'purchase', {
transaction_id: '{{dlv - ecommerce.transaction_id}}',
value: {{cjs - ecommerce.value (number)}},
currency: '{{dlv - ecommerce.currency}}',
email: '{{dlv - user_data.email}}',
phone: '{{dlv - user_data.phone}}',
first_name: '{{dlv - user_data.first_name}}',
last_name: '{{dlv - user_data.last_name}}',
shipping_country: '{{dlv - user_data.address.country}}',
shipping_postal_code: '{{dlv - user_data.address.postal_code}}',
sub_total: {{cjs - ecommerce.sub_total (number)}},
tax: {{cjs - ecommerce.tax (number)}},
shipping: {{cjs - ecommerce.shipping (number)}},
items: {{cjs - ecommerce.items-TT}}
});
</script>Trigger the tag on a Page View event scoped to your order confirmation URL (e.g. Page Path matches /thank-you). The TrueTracked base script must load on the same page; both can live in the same GTM container.
What fires for each platform
A single purchase event triggers all of the following automatically (assuming you have the platform configured under Integrations or TrueSignal):
| Platform | Browser | Server |
|---|---|---|
| Meta | Pixel Purchase | CAPI Purchase + NewCustomerPurchase / ReturnCustomerPurchase |
| GA4 | gtag purchase | Measurement Protocol purchase |
| TikTok | Pixel Purchase | Events API Purchase |
| Google Ads | Conversion (via GA4 purchase) | - |
Deduplication
Browser pixels and server CAPI both fire for the same purchase. To prevent each platform from counting it twice, TrueTracked uses your transaction_id as the deduplication key:
- Meta: browser
eventID+ serverevent_id=transaction_id - TikTok: browser
event_id+ serverevent_id=transaction_id - GA4: dedupes natively on
transaction_id
As long as transaction_id is unique per order, each ad platform will count exactly one Purchase per fire - even if both browser and server fires reach them successfully.
Verifying it works
- DevTools Network tab - after firing a test purchase, look for these requests:
POST t.ttrkd.com/event(the TrueTracked event ingest)POST facebook.com/trwithev=Purchase(Meta Pixel)GET t.ttrkd.com/g/collect?...&en=purchase(GA4 + Google Ads)POST analytics.tiktok.com/...withev=Purchase(TikTok Pixel)
- Meta Events Manager → Test Events - confirm a single Purchase event with
eventIDmatching yourtransaction_id. The badge should show both "Browser" and "Server" merged. - GA4 DebugView - should show one
purchaseevent with the correct value, currency, and items. - TikTok Events Manager - should show one Purchase event with matching
event_id. - TrueTracked dashboard - the order will appear in your orders list with platform
customwithin a few seconds.
Troubleshooting
- Event fired but no order in dashboard - check that
transaction_idis non-empty. Events without it are accepted but the order is dropped (you'll still see the event in your raw events log). - Order shows
value: 0- thevaluefield arrived asundefinedor empty string. Confirm your data-layer variable resolves to a number, not a string template like'{{order.total}}'that didn't render. - Same purchase appearing twice in Meta - different
transaction_idvalues across browser fire and a parallel server webhook will both count. Pick one source (browserpurchaseevent OR a webhook) - don't fire both for the same workspace. - Google Ads conversion not firing - Google Ads piggybacks on the GA4
purchaseevent. Make sure your Google Ads conversion is configured against your GA4 property in your Google Ads account, with thepurchaseevent mapped to a conversion label. - Customer always shows as "new" - if you're not passing the
new_customerfield, TrueTracked checks the orders table by email. The first order for a given email is always classified as new. To override, passnew_customer: falseexplicitly. - Page refresh fires the event again - TrueTracked deduplicates browser
purchaseevents ontransaction_id, so a second fire with the same ID is dropped. No action needed.
Related guides
- Pixel Installation - install the base script on every page (prerequisite).
- Integrations - Shopify and GoHighLevel webhook setup if you have those platforms.
- TrueSignal - connect your Meta CAPI, Google Ads, and TikTok server-side conversions.
- Cost Settings - add product costs so the dashboard can calculate gross profit and ROAS for these orders.