Getting started
Conversion tracking methods
Postback, pixel, iframe, JavaScript, server-to-server events and SDKs compared, with endpoints, parameters and responses.
A click gets a unique click_id. A conversion is attributed by sending that id back. There are several ways to do it; pick per offer with the conversion_method setting (server_postback, image_pixel, iframe_pixel, javascript_sdk, cookie_based, gtm, shopify, s2s_event_api, coupon_code, call). The setting restricts which endpoint families are accepted for that offer; a mismatch is rejected with method_not_allowed.
Which method should I use?
| Method | Use when | Endpoint (on the tracking or ingest host) | Needs |
|---|---|---|---|
| Server postback | The advertiser has a backend. Most reliable; recommended. | GET or POST /p, /postback, /conversion | The click_id stored by the advertiser. |
| Image pixel | No backend access, only a thank-you page. | GET /px.gif | Click id from a cookie or URL parameter on the page. |
| Iframe pixel | Page cannot host an image (ad blockers, CSP). | GET /px.html | Same as image pixel. |
| JavaScript | You want the browser to read the cookie itself. | /sdk.js then dtk('conversion', {...}), or GET /js | Web SDK on the thank-you page. |
| S2S event API | Many event types from a backend with an API key. | POST /v1/events (API key) | Authorization: Bearer key. |
| Mobile SDK / S2S | Apps: installs, sessions, in-app events. | /sdk/v1/*, POST /v1/events | See mobile. |
| Shopify, BigCommerce | Store conversions through webhooks. | /integrations/shopify/webhook, /integrations/bigcommerce/webhook | Webhook secret and tenant configured on ingest. |
| Coupon code | Offline or influencer codes, no click. | any inbound endpoint with coupon= | Coupon assigned to a partner. |
| Calls | Call tracking. | created internally from a qualified call | See call tracking. |
| Bulk / manual | Reconciliation, corrections. | POST /v1/conversions/bulk (JSON or CSV), admin portal | API key or portal. |
/aff_lsr and /pb are accepted aliases of the postback path.
Postback
https://track.yourbrand.com/p?click_id={click_id}&goal=sale&txn_id={order_id}&amount={total}¤cy=USD&security_token=TOKEN
The advertiser fills the braces on its side. Parameters are case-insensitive and accept many spellings; the registry is in the parameters reference:
| Canonical | Accepted names | Meaning |
|---|---|---|
click_id | clickid, cid, transaction_id, tid, aff_click_id, _ef_transaction_id, dtk_click | The id we put in the destination URL. |
goal | goal_id, goal_value, event, event_name, adv_event_id, g, event_id | Goal key (or id). Omit for the base goal. |
txn_id | order_id, trans_id, ref_id, txid, transaction, adv_txn | The advertiser's unique id for this conversion; the de-duplication key. |
amount | sale_amount, sale, revenue, rev, value, sum | Sale amount for percentage payouts and revenue. |
payout | payout | Explicit payout, honoured only for advertisers with token, IP or HMAC security. |
currency | cur | ISO currency of amount; converted with a locked FX rate. |
status | status | approved, pending or rejected, for trusted advertisers; also used to update an existing conversion. |
security_token | token, key, secret | Advertiser token. |
ts | timestamp, date, click_time | Backdate a conversion (bounded to roughly 400 days back and 5 minutes forward; it must still fit the attribution window). |
adv1..adv10, sub1.. | Advertiser-defined values kept on the conversion, usable as payout calc_param sources. | |
coupon, user_id, email, phone, ip, ua, device_id, test | Matching and test signals. |
Security modes
Set per advertiser (postback_security_mode):
| Mode | Check | Failure reason |
|---|---|---|
none | Nothing. | |
token | security_token equals the advertiser's token. | invalid_token |
ip | Source IP (postbacks and S2S) is inside the advertiser's whitelist. | ip_not_whitelisted |
hmac | Hex HMAC-SHA256 of the raw query string (or request body) keyed with the advertiser's security_token, sent in the X-DT-Signature header or a signature parameter. | invalid_signature |
Response
Ingest never answers a conversion hit with a 4xx or 5xx for business reasons, because advertiser systems retry on errors. It answers 200:
{"status":"created","conversion_id":"01J...","reason":"","conversion_status":"approved"}
status | Meaning |
|---|---|
created | New conversion recorded (its conversion_status may be pending or flagged). |
duplicate | Same txn_id (or click and goal) already recorded; nothing changed. |
updated | An existing conversion changed status because a trusted advertiser sent a different status for the same txn_id. |
rejected | Failed validation; a rejected conversion is still stored with its reason. |
unmatched | No click could be found. Stored and visible so it can be assigned. |
Pixels additionally return a 1x1 GIF (or an empty HTML page for iframes).
Validation order
First failure wins; the reason appears in the logs and the response.
- Offer:
offer_paused,offer_inactive,offer_expired. - Partner:
partner_inactive,blocked_partner. method_not_allowed(conversion method vs endpoint family).- Advertiser security:
invalid_token,ip_not_whitelisted,invalid_signature. - Click checks:
invalid_click(the click was flagged invalid), then the timing window:expired_session,ctit_too_short,ctit_too_long, andkpi_window_exceededfor goals with a KPI window. - Hooks: caps and fraud can reject or downgrade the status at their stage.
Details of matching are in attribution, duplicates in deduplication.
Pixel and iframe
<img src="https://track.yourbrand.com/px.gif?click_id=CLICK&goal=lead&txn_id=ORDER42" width="1" height="1" alt="">
<iframe src="https://track.yourbrand.com/px.html?click_id=CLICK&goal=lead&txn_id=ORDER42" width="0" height="0" style="display:none"></iframe>
A token placed in a pixel URL is visible to every visitor, so pixels are best used on offers whose advertiser security mode is none, or with only a click id while a server postback confirms the amount.
JavaScript SDK
Load the SDK from your tracking domain (/sdk.js, under 6 kB gzipped, served with an ETag), initialise it with your tracking domain, and report from the thank-you page. The SDK reads the click id from the landing URL, keeps it in a first-party cookie and local storage, and posts conversions to POST /p.
<script src="https://track.yourbrand.com/sdk.js" async
data-domain="https://track.yourbrand.com" data-consent="granted"></script>
<script>
window.dtk = window.dtk || function () { (dtk.q = dtk.q || []).push(arguments); };
dtk('conversion', { goal: 'sale', txn_id: 'ORDER42', amount: '49.90', currency: 'USD' });
</script>
| Command | Purpose |
|---|---|
dtk('init', {domain, tenant, consent, ttl, cookie, cookieEndpoint, debug}) | Configure (the data-* attributes on the script tag do the same). |
dtk('consent', 'granted' | 'denied' | {ad_storage}) | Nothing is stored before consent; conversions are queued (up to 50) and flushed when consent is granted. |
dtk('conversion', {...}) or dtk('track', {...}) | Send a conversion. A repeated txn_id in the same browser is dropped client-side. |
dtk('identify', {user_id, email_hash}) | Attach user identifiers. |
dtk('pixel', {...}) | Build a pixel URL. |
dtk('click_id'), dtk('params') | Read the captured ids. |
With cookieEndpoint: true the SDK also asks POST /sdk/v1/cookie to set an HttpOnly cookie from your tracking CNAME, which survives Safari's limits on script-written cookies. Allowed origins for these browser calls are configured on ingest with DT_INGEST_SDK_ORIGINS. A Google Tag Manager template ships in packages/web-sdk/gtm.
Server-to-server events
For richer events from your backend use an ingest API key of the tenant. The body is one event object or {"events":[...]}; a single event returns its outcome, a batch returns {"results":[...]}.
curl -X POST https://ingest.yourbrand.com/v1/events \
-H "Authorization: Bearer $DT_API_KEY" -H "Content-Type: application/json" \
-d '{"click_id":"CLICK","goal":"deposit","txn_id":"T-9","amount":"100.00","currency":"EUR"}'
Bodies that carry an app token, app id or device block, or an X-Dt-App-Token / X-Dt-Signature header, are routed to the mobile pipeline instead; see install attribution. To correct statuses later use POST /v1/conversions/{id}/status (approve, reject, pending) with the same key. POST /v1/conversions/bulk accepts JSON or CSV for bulk reconciliation.
Shopify and BigCommerce
Ingest verifies Shopify webhooks with HMAC (X-Shopify-Hmac-Sha256, secret DT_INGEST_SHOPIFY_SECRET, tenant DT_INGEST_SHOPIFY_TENANT). BigCommerce needs the shared secret in X-DTK-Webhook-Secret and reads the click id from a cart metafield (dtk_click). Both are idempotent on the order id. The WooCommerce plugin in integrations/woocommerce posts to /p and honours the WordPress consent API (options dtrackier_domain, dtrackier_tenant, dtrackier_goal, dtrackier_token, dtrackier_ttl_days).
Postbacks from Metrixed to others
Conversions can also fire postbacks out to partners and ad platforms; that direction is documented in postbacks and webhooks.