Rebrandly — clicks source & the campaign_utm_ct issue
TL;DR. The campaign of a click is extracted from the link's destination URL byrebrandly_campaign_utm_ct, which only understands old-style query params (ct=/utm_campaign=). When creators moved to AppsFlyer OneLink and baremoises.app/<slashtag>deep links in 2024, the campaign moved into the path/slashtag — the parser returnsNULL, and those clicks fall out of every campaign-keyed report.
Source pipeline
| Layer | Object | File / owner |
|---|---|---|
| Ingestion (Airflow) | moises_raw.rebrandly_raw | DAG rebrandly-to-bq · dags/to_deprecate/rebrandly_to_bq.py (S3 click-stream → GCS → BQ) |
| Prep (dbt 🧱) | rebrandly_prep | dags/domains/marketing/models/rebrandly/rebrandly_prep.sql |
| Prep (dbt 🧱) | rebrandly_campaign_utm_ct | …/rebrandly_campaign_utm_ct.sql — parses query-param campaigns; NULL for OneLink is expected (recovered downstream by the slug→sheet join) |
| Prep (dbt 🧱) | rebrandly_device_platform | …/rebrandly_device_platform.sql |
| Prep (Dataform ⚙️) | rebrandly_campaigns_creators | derived/marketing/rebrandly/rebrandly_campaigns_creators.sqlx — not yet migrated (next port) |
| Master (dbt 🧱) | rebrandly | …/rebrandly.sql — dbt is the sole writer of derived_marketing_master.rebrandly (cutover complete 2026-06-12) |
Lineage (red = model with the issue)
Airflow · S3 click-stream"] subgraph RB["dbt 🧱: rebrandly/ (migrated, sole writer)"] prep["rebrandly_prep"] utm["rebrandly_campaign_utm_ct
parses campaign from destination_raw; NULL for OneLink (expected)"] dev["rebrandly_device_platform"] master["rebrandly (master)"] end creators["rebrandly_campaigns_creators
⚙️ Dataform — not yet migrated"] sheet["connected_sheets.mkt_creators_campaigns
Connected Sheet"] funnel["campaigns_funnel_clicks → campaigns_funnel
⚙️ Dataform — slug→sheet fallback recovers OneLink"] raw --> prep prep --> utm prep --> dev prep --> master utm --> master dev --> master sheet --> creators master --> funnel sheet --> funnel classDef dbt fill:#ddf4e4,stroke:#2da44e,color:#000 classDef partial fill:#fff2cc,stroke:#c90,color:#000 class prep,utm,dev,master dbt class creators,funnel partial
How campaign_utm_ct is parsed
rebrandly_campaign_utm_ct.sqlx reads only destination_raw (the URL the link redirects to) and matches a fixed
CASE of 4 query-param shapes. There is no ELSE, so anything else → NULL:
…ct=<campaign>……utm_campaign=<campaign>…- Android old format (
utm_source%3D…, pre-2023-02-06) - Android new format (
utm_campaign%3d…, regex)
Link patterns over time (milestones)
Era 1 — 2021 → 2023: campaign in a query param ✅ (~0.6% NULL)
| Pattern | Example destination_raw | Parsed |
|---|---|---|
ct= | moises.ai/made-for/bassists/?ct=mar23_doni_yt&utm_source=youtube… | mar23_doni_yt |
utm_campaign= | moises.ai/beat-friday-2023?utm_campaign=nov23_martymusic_ig… | nov23_martymusic_ig |
Android referrer= | play.google.com/…?referrer=utm_source%3Djun_eloy_YTIG%26… | jun_eloy_YTIG |
Era 2 — 2024: AppsFlyer OneLink → campaign leaves the URL ❌ (89% NULL)
| Example destination_raw | Parsed |
|---|---|
| moises.onelink.me/AuSS/eddiewarboy | NULL |
| moisesai.onelink.me/lbUs/bf24kleyttonfarney | NULL |
| moisesai.onelink.me/lbUs/bf24kaelinellis | NULL |
The campaign moved into the OneLink path / slashtag. No ct=/utm_campaign= → parser returns NULL. This is the 2024 clicks crater.
Era 3 — 2025: messy split
| Example destination_raw | Parsed |
|---|---|
| moises.ai/features/ai-studio-creators/?utm_campaign=aug25_ericassarsson_yt… | aug25_ericassarsson_yt |
| moises.onelink.me/AuSS/pw6rzgpp (opaque token, not the campaign name) | NULL |
Many links returned to utm_campaign= (parse OK → 2025 clicks recover), but some OneLinks now use opaque random tokens that even a slashtag fallback can't resolve.
Parse success by link-creation year
| Link year | Distinct links | Parsed OK | NULL | % NULL | Dominant new pattern |
|---|---|---|---|---|---|
| 2021 | 35,869 | 35,642 | 227 | 0.6% | utm_campaign / ct |
| 2023 | 29,130 | 28,937 | 193 | 0.7% | utm_campaign / ct |
| 2024 | 21,203 | 2,253 | 18,950 | 89.4% | onelink.me (14,033) |
| 2025 | 20,024 | 19,202 | 822 | 4.1% | back to utm_campaign (19,196) |
Root cause & why it was never caught
rebrandly_campaign_utm_ct is a hard-coded CASE with no ELSE. When Marketing changed link tooling
(query-param links → AppsFlyer OneLink → back to web links), nobody updated the SQL. A NULL doesn't error — it silently drops
the row, so the funnel quietly under-counted for a full year. People changed the links; we never changed the query.
Fix direction (for the dbt migration)
- Add an AppsFlyer-OneLink branch: derive the campaign from the OneLink path /
route_slashtag(and exclude opaque tokens). - Add an
ELSEfallback (slashtag → creators sheet) so unmatched destinations don't silently become NULL. - Segregate generic CTAs (
download-app,bf25-lp…) so they don't pollute creator-campaign clicks.
See the recovery numbers in 2026-06-08 clicks (rebrandly) attribution issues.
Reproduce with qmb
session pi-2026-06-08-rebrandly-link-patterns
- Parse-rate by link-creation year:
qmb jobs sql qmb_2026-06-08_15-55-29_3c2ce7 - Example links per era — 2021:
qmb jobs sql qmb_2026-06-08_15-56-09_7f5f4d - Example links per era — 2023:
qmb jobs sql qmb_2026-06-08_15-56-20_e49a51 - Example links per era — 2024:
qmb jobs sql qmb_2026-06-08_15-56-28_bb607d - Example links per era — 2025:
qmb jobs sql qmb_2026-06-08_15-56-38_2aae34