Partner Tracking Parameters

How partners send data through their tracking URLs, and how Relo uses those parameters for attribution, reporting, and commission.

TL;DR. We set partner_id and campaign_id server-side from the t.relo.mx/c/CODE short link (not from URL params — more secure). Partners can freely append utm_* or custom x_* params for their own sub-IDs, creatives, ad groups, etc. Everything captured gets queryable in the partner + admin Conversions tab.

1. Three layers of parameters

LayerWhere it comes fromExample
AUTO Set by the click wrapper server-side when a user visits t.relo.mx/c/CODE. Partner does not configure these. partner_id, campaign_id, click_id
CAMPAIGN Configured by Relo admin when creating the campaign or the short link (stored in CF KV). Landing URL, optional UTM overrides, campaign slug
PARTNER Partners append these to the short URL when running ads. We don't prescribe a schema — partners can track whatever they want. utm_source, utm_campaign, sub1, asset_id, creative_id
CUSTOM Per-event advertiser metadata sent via relo('lead', {...}) from the site itself (not the URL). product, stage, lead_value, custom x_* fields

2. The tracking URL anatomy

A partner gets one short URL from Relo:

https://t.relo.mx/c/ab12CD

They can add whatever they want after it. Every param survives the redirect:

// Partner's actual ad URL:
https://t.relo.mx/c/ab12CD?utm_source=facebook
                          &utm_campaign=summer_auto
                          &utm_content=video_a
                          &sub1=adset_123
                          &creative_id=vid_042
                          &asset_id=SAM-MX-A1B2C3

When a user clicks, the click wrapper:

  1. Looks up ab12CD in KV → gets {url, partner_id=30, client_id=5, campaign_id=8}.
  2. Generates a click_id (ULID), stores all context in Redis (30-day TTL).
  3. Sets cookie _relo_cid=<click_id> on .relo.mx.
  4. 302 redirects to the landing URL, preserving every query param the partner added plus appending &relo_click_id=<click_id>.

Result URL after redirect:

https://quote.miami/?utm_source=facebook
                     &utm_campaign=summer_auto
                     &utm_content=video_a
                     &sub1=adset_123
                     &creative_id=vid_042
                     &asset_id=SAM-MX-A1B2C3
                     &relo_click_id=01KPVT...

3. Params the pixel auto-captures

The pixel inspects the landing URL once and stores tracking params in a first-touch cookie (30 days) + last-touch cookie (session). These ride with every event going forward.

ParamPurposeWhere it lands
utm_source, utm_medium, utm_campaign, utm_content, utm_term, utm_idStandard UTM taggingevent_properties on purchase/lead_submit/form_submit
gclid, gbraid, wbraidGoogle Ads click IDSame
fbclidMeta click ID (for CAPI dedup)Same, plus used for Meta CAPI match
ttclid, twclid, msclkid, yclidTikTok / Twitter / Bing / Yandex click IDsSame
af_sub1af_sub5AppsFlyer sub-publishers (works for pixel sites too)first_touch cookie, surfaced on conversions
af_ad, af_adset, af_channelAppsFlyer creative / ad group / channel — also used for asset trackingSame
pid, cAppsFlyer partner ID + campaign shortcutSame
mc_cid, mc_eidMailchimp campaign + email IDSame
irclickid, cj_aidImpact / CJ affiliate IDsSame
partner, sub_id, click_id, relo_click_idGeneric partner IDsSame
About asset tracking. We reuse af_ad as the canonical asset-ID field. The Link Generator at /c/SLUG/link-generator auto-appends af_ad=SAM-XX-XXXXXX when a partner generates a link for a specific creative. Queries like "which banner drove the most conversions?" become GROUP BY event_properties['af_ad'] in ClickHouse.

4. Params the pixel does NOT auto-capture

Anything not in the allowlist above is ignored by getUrlParams(). If partners want to track custom sub-publishers or IDs that aren't in the list, they have two options:

Option A — use an allowlisted param

Map whatever they want into an allowlisted slot. For a "studio ID" for example, use af_sub4=studio_abc. Then admin + partner both see it in event_properties['af_sub4'].

Option B — add it to the allowlist

If you need a brand-new canonical param (e.g. studio_id), add it to TRACKING_PARAMS in backbone/workers/pixel/src/pixel.ts and redeploy the pixel worker. This is a code change, not a config change — keep the allowlist small.

5. Partner-specific custom params via lead payload

When the lead finally converts, the advertiser site can pass advertiser-controlled metadata that doesn't rely on URL params:

relo('lead', {
  product:    'Auto Insurance Quote',
  form_id:    'quote-v2',
  stage:      'raw',
  lead_value: 50,
  currency:   'USD',
  // Anything under extra.* surfaces as x_* on the Relo side
  extra: {
    zip:             '33131',
    preferred_agent: 'maria',
    quote_id:        'Q-2026-0422-771',
    studio_id:       'miami-001'
  }
});

Relo stores these as:

6. Attribution: how parameters drive partner resolution

There are two attribution paths, and pixel clients use the first:

6.1 Click-wrapper attribution (pixel clients)

  1. Partner sends user through t.relo.mx/c/CODE.
  2. Click wrapper caches {partner_id, campaign_id} in Redis keyed by click_id.
  3. Pixel reads _relo_cid cookie (or relo_click_id URL param as fallback) on every event.
  4. Go backbone does Redis.GetClick(click_id) → populates partner_id + campaign_id columns.
Why via the short URL and not via ?partner_id=30 in the URL? Because URL params can be forged. A competitor could send traffic with ?partner_id=SOMEONE_ELSE and steal attribution. The click wrapper seals partner+campaign server-side so the partner can only tag events they actually own.

6.2 Attribution-rules (MMP clients like Samsung)

For mobile app installs where there's no click wrapper, partners get a CID pattern like mx_pd_affiliate_relo_none_always-on_sub1_banner_none_conversion. AppsFlyer passes the whole campaign string in the S2S postback. Relo matches against partner_clients.attribution_values using regex/contains/startswith/endswith to resolve the partner.

This lives in attribution.md and isn't what pixel clients use.

7. Where partners see their data

LocationWhat they see
Partner portal → Conversions tabPer-conversion list with all event_properties surfaced. Filterable by date, stage, search.
Partner portal → DashboardAggregated counts, top products, funnel, traffic sources (UTM breakdown), landing pages, geo.
Partner portal → LinksShort URL stats: clicks per code, conversions per code.
Partner portal → AssetsList of assets with af_ad tracking IDs. Performance per creative.

8. Where admins see / configure params

LocationWhat they configure
Config → Data Pipeline → Web PixelAllowed domains, consent defaults, replay sampling, HMAC secret for postbacks.
Partners → + Onboard partnerCreate partner + campaign + short link in one form. Sets KV {pid, cid, aid}.
Partners → Manage → Lead ratesPer-event / per-stage / per-product commission rates (fixed or %). With optional monthly_cap.
Campaigns → SettingsCampaign metadata, product patterns, landing URL template, UTM defaults.
Admin → ConversionsAll conversions across the client. Filter by event_types, partner, date. CSV export.
Admin → Audit → Live eventsReal-time event stream with raw event_properties visible for debugging.

9. Examples — three partner workflows

9.1 Facebook ads partner

https://t.relo.mx/c/fbAgency
    ?utm_source=facebook
    &utm_campaign=jul2026_auto
    &utm_medium=cpc
    &fbclid=IwAR...          (Meta auto-adds this)
    &sub1=adset_cheap_auto
    &sub2=ad_video_v3

9.2 Creative / asset tracking

https://t.relo.mx/c/creativeA
    ?utm_source=google
    &utm_campaign=miami_quote_q2
    &gclid=EAIaIQ...         (Google auto-adds)
    &af_ad=SAM-MX-A1B2C3     (Relo asset tracking ID)

9.3 Affiliate network partner

https://t.relo.mx/c/cjAffiliate
    ?utm_source=cj
    &utm_campaign=autumn_push
    &cj_aid=123456           (CJ auto-adds)
    &irclickid=xyz           (Impact auto-adds)
    &sub1=publisher_foo

10. Query examples

Admin can slice conversions by any captured param. Examples:

-- Conversions by sub1
SELECT event_properties['sub1'] AS sub1, count() AS leads
FROM events
WHERE client_id = 5
  AND event_name = 'lead_submit'
  AND event_time >= today() - INTERVAL 30 DAY
GROUP BY sub1
ORDER BY leads DESC;

-- Conversions by creative (af_ad = asset tracking ID)
SELECT event_properties['af_ad'] AS asset,
       count() AS conversions,
       sum(toFloat64OrZero(event_properties['lead_value'])) AS value
FROM events
WHERE client_id = 5
  AND event_name = 'lead_submit'
  AND event_properties['af_ad'] != ''
GROUP BY asset
ORDER BY conversions DESC;

-- Traffic source breakdown
SELECT event_properties['utm_source'] AS source,
       countIf(event_name = 'page_view')   AS sessions,
       countIf(event_name = 'lead_submit') AS conversions
FROM events
WHERE client_id = 5
  AND event_time >= today() - INTERVAL 7 DAY
GROUP BY source;

11. Best practices for partners

12. Best practices for Relo admins

13. See also