Tracking guide
Click flow
Exactly what the edge redirect does with a click, in order, and the redirect modes it can answer with.
The edge redirect (services/edge-redirect) serves every tracking link. It is built for the hot path: it reads a cached configuration snapshot (no database call per click), and a click is decided in about a millisecond of handler time (p99 under 1.5 ms in the repository benchmark, with an alert budget of 8 ms). This page is the order of decisions; each step can short-circuit with a recorded reason.
The steps
- Resolve the link. The
Hostheader selects the tenant and its legacy style. The path and query are parsed with the link codec into an offer reference, a partner reference and canonical parameters (aliases).test=1marks the click as a test. - Look up entities in the snapshot: offer, partner, landing pages, SmartLink. Unknown references answer
404. Impression links (/i/...) record the impression and return a 1x1 GIF without routing. - Enrich. Visitor IP (from the socket, or
X-Forwarded-For/X-Real-IPwhen the edge trusts its proxy withDT_EDGE_TRUST_PROXY=1), geography from your CDN's geo headers (X-Geo-Country,CF-IPCountry,CloudFront-Viewer-Country,X-Geo-Region,X-Geo-City,X-Geo-ISP), device, OS, browser and bot detection from the user agent, language fromAccept-Language, andSec-GPC. Partners flagged to allow overrides can passip_overrideandua_overridefor server-to-server clicks. - Status and access. The click is marked invalid, with a reason, when the offer is not
active(offer_inactive) or outside its start and end dates (offer_expired), the partner is not active (partner_inactive) or is blocked on this offer (blocked_partner), or the link format is not allowed for the offer (traffic_filter). - Rules. Tenant-wide traffic controls run first, then the offer's rule sets in priority order. Actions are
allow,deny,fail_traffic(send elsewhere) androute_to. A rule set can name its own fail-traffic target and reason category. Bots are markedbot. See caps, rules and day-parting. - Extension hooks. Lists and targeting, day-parting, and fraud scoring run here and may deny, mark or reroute the click.
- Caps. Click-metric caps are counted in Redis; a hard cap reached makes the click invalid with reason
caps. - Deduplication. The offer's
session_definition(cookie,ip,ip_user_agent,gaid,idfa,click_id_only) builds a session key; the first click per key in the window is unique (unique_click_session_hours, default 24), later ones are duplicates and, if the offer'sduplicate_click_actionisblockorfail_traffic, invalid with reasonduplicate. See deduplication. - Route. A valid click picks a landing page: the one named by
url_id(id or title), otherwise the offer's default landing page, otherwise the first active one (pages marked private are visible only to the partners listed on them). A landing page with a split list spreads traffic over its URLs by weight. With no landing page the offer's destination is used. Macros in the destination are expanded (macros). An allowedurl=deep link replaces the destination. An invalid click goes to its fail-traffic target, then the offer's fallback URL, fallback offer, the advertiser's fallback, the tenant's fallback, or a blank204. - Respond and record. The response is written per redirect mode, with
Cache-Control: no-store, and anX-Click-Idheader. The click event, including the decision and reason, is published to NATS (dt.click.created.v1, streamDT_CLICKS) and lands in ClickHouse. Invalid clicks are stored too.
What a click records
Every click carries: click_id (a ULID), offer, partner, advertiser, landing page, creative, SmartLink, tracking domain and app, link style, redirect mode and final destination, all canonical parameters (sub1 to sub15, source, device ids, platform click ids, utm_*), geography, device, flags (is_unique, is_duplicate, is_bot, is_proxy, is_test), fraud score and reasons, matched rule ids, cap state, and handler latency. The schema is click.
Media cost on the click
A partner can pass what it paid for the click: cost=1.25 (alias media_cost=) and optionally cost_currency=EUR
(default the offer currency). It counts only when the partner page has Media cost ▸ Accept cost= on clicks on
(partners.tracking.enable_media_cost): the click stores the cost as sent (cost_status: accepted) and reports
convert it to your currency at the click day's rate, which gives media cost and profit. From a partner without the
permission the value is ignored (not_permitted); an unreadable value is invalid. Neither affects the redirect.
Redirect modes
Set per offer, overridable per landing page. Implemented by the edge:
| Mode | Response |
|---|---|
http302 (default) | 302 with Location. |
http302_hide_referrer | 302 plus Referrer-Policy: no-referrer. |
seo_friendly_301 | 301, never cached (no-store). |
http200_js | 200 page that redirects with JavaScript, with a meta-refresh fallback. |
http200_js_hide_referrer | Same, with no-referrer policy and meta tag. |
meta_refresh_single | 200 page with a <meta http-equiv="refresh">. |
meta_refresh_double | Two meta-refresh hops through /_hop. |
direct_link, interstitial, app_store_smart | Currently answer 302 like http302; the click is still recorded. |
Async JSON instead of a redirect
Add async=json (or format=json) to any tracking link and the edge answers 200 with JSON instead of redirecting:
{"click_id": "01JC9Z3Q4M8V2N6R7T1W5X0Y3Z", "redirect_url": "https://advertiser.example/?click_id=01JC9Z3Q4M8V2N6R7T1W5X0Y3Z"}
Use it from a landing page script, an app or a server that records the click and sends the visitor on itself. The click is decided and recorded exactly as the redirect would be: rules, caps and deduplication apply, an invalid click is stored with its reason and the answer carries invalid_reason plus the fallback destination as redirect_url. An unknown link answers 404 with {"error":{"code":"not_found"}}. The answer allows any origin (Access-Control-Allow-Origin: *, no credentials) and exposes the X-Click-Id header.
Redirects are stateless by default: no cookie is set. A cookie is set only when the offer's session_definition is cookie (name dt_<offer>, Secure, HttpOnly, SameSite=Lax, lifetime session_duration_hours).
Reliability
Click events are buffered and published asynchronously; if the bus is unavailable the edge keeps serving redirects and counts dropped events. Config changes reach the edge through Postgres LISTEN, the NATS dt.config.changed.v1 event and a 30-second poll, so a change is live within seconds. Each edge region exposes /healthz, /readyz and /metrics.