Campaign links — registry

Every store link we control carries a per-placement tag, so that

  • App Store Connect reports impressions, product page views, downloads and sales per campaign token (ct), and
  • Play Console reports store-listing visitors and acquisitions per UTM campaign (“Tracked channels (UTM)”).

Generate links with scripts/campaign_link.py; never hand-type them. scripts/test_campaign_link.py fails if a row below drifts from what the generator produces.

python3 scripts/campaign_link.py site nlbe pricing
python3 scripts/campaign_link.py site nlbe pricing --row --location "where it lives"
python3 -m unittest scripts/test_campaign_link.py -v

Scheme

  • ct = utm_campaign = <channel>-<market>-<placement>, lowercase a-z 0-9 -.
  • At most 30 characters. Apple’s limit, quoted from Campaign links (read 3 Oct 2026): “You can use up to 30 alphanumeric characters and spaces”. The Phase 1 brief said 40; Apple’s current page says 30, and the generator enforces 30. The longest prefix, teacher-enca-, leaves 17 characters for the placement.
  • channel ∈ site, email, meta, gads, teacher, press. market ∈ nlbe, enca.
  • utm_source / utm_medium per channel: site website/referral, email brevo/email, meta meta/paid_social, gads google/cpc, teacher teacher/referral, press press/referral.

iOS: https://apps.apple.com/<be|ca>/app/verbomatique-secondaire/id1611881585?pt=123526428&ct=<ct>&mt=8. Apple redirects every visitor to their own storefront whatever the path says; /be/ and /ca/ are kept for continuity with the live links.

Play: https://play.google.com/store/apps/details?id=be.teamwabisabi.verbomatique_secondaire[&hl=nl&gl=BE]&referrer=<URL-encoded utm triple>. The UTM triple must sit inside referrer=, URL-encoded, at most 512 characters. A bare &utm_source= on a Play URL is not the documented format (see the two .com pages below). hl=nl&gl=BE is kept on nl-BE because the live .be links carry it.

Provider token (pt): 123526428. Read 3 Oct 2026 in App Store Connect > Analytics > Campaigns > Generate a Campaign Link. It identifies the developer account and is the same for every campaign. It is the generator default (APPLE_PROVIDER_TOKEN).

Path note. App Store Connect’s generator emits a region-less path: https://apps.apple.com/app/apple-store/id1611881585?pt=123526428&ct=site-nlbe-header&mt=8. The registry deliberately keeps /be/app/verbomatique-secondaire/ and /ca/app/verbomatique-secondaire/, for continuity with the live links. The query string (pt, ct, mt), not the path, carries the attribution, and Apple redirects every visitor to their own storefront whatever the path says. test_matches_app_store_connects_generated_link_except_the_path asserts that the query matches Apple’s.

Registry

ct / utm_campaign Location utm_source / utm_medium / utm_campaign Final iOS URL Final Play URL Status
site-nlbe-header secondaire.verbomatique.be front page, Colibri header “DOWNLOAD GRATIS” (posts 13 + JSON 14) website / referral / site-nlbe-header https://apps.apple.com/be/app/verbomatique-secondaire/id1611881585?pt=123526428&ct=site-nlbe-header&mt=8 https://play.google.com/store/apps/details?id=be.teamwabisabi.verbomatique_secondaire&hl=nl&gl=BE&referrer=utm_source%3Dwebsite%26utm_medium%3Dreferral%26utm_campaign%3Dsite-nlbe-header live
site-nlbe-intro .be front page, “Geen boek nodig” block (post 40 c12/c16, JSON 41) website / referral / site-nlbe-intro https://apps.apple.com/be/app/verbomatique-secondaire/id1611881585?pt=123526428&ct=site-nlbe-intro&mt=8 https://play.google.com/store/apps/details?id=be.teamwabisabi.verbomatique_secondaire&hl=nl&gl=BE&referrer=utm_source%3Dwebsite%26utm_medium%3Dreferral%26utm_campaign%3Dsite-nlbe-intro live
site-nlbe-results .be front page, “Na elke oefensessie” block (post 40 c26/c30, JSON 41) website / referral / site-nlbe-results https://apps.apple.com/be/app/verbomatique-secondaire/id1611881585?pt=123526428&ct=site-nlbe-results&mt=8 https://play.google.com/store/apps/details?id=be.teamwabisabi.verbomatique_secondaire&hl=nl&gl=BE&referrer=utm_source%3Dwebsite%26utm_medium%3Dreferral%26utm_campaign%3Dsite-nlbe-results live
site-nlbe-pricing .be front page, pricing “€1,99” block (post 40 c40/c44, JSON 41) website / referral / site-nlbe-pricing https://apps.apple.com/be/app/verbomatique-secondaire/id1611881585?pt=123526428&ct=site-nlbe-pricing&mt=8 https://play.google.com/store/apps/details?id=be.teamwabisabi.verbomatique_secondaire&hl=nl&gl=BE&referrer=utm_source%3Dwebsite%26utm_medium%3Dreferral%26utm_campaign%3Dsite-nlbe-pricing live
site-nlbe-herexamen-top .be /index.php/herexamen-landing-page/, first CTA (post 587 c12/c14, JSON 596) website / referral / site-nlbe-herexamen-top https://apps.apple.com/be/app/verbomatique-secondaire/id1611881585?pt=123526428&ct=site-nlbe-herexamen-top&mt=8 https://play.google.com/store/apps/details?id=be.teamwabisabi.verbomatique_secondaire&hl=nl&gl=BE&referrer=utm_source%3Dwebsite%26utm_medium%3Dreferral%26utm_campaign%3Dsite-nlbe-herexamen-top live
site-nlbe-herexamen-bottom .be herexamen landing page, closing CTA (post 587 c46/c48, JSON 596) website / referral / site-nlbe-herexamen-bottom https://apps.apple.com/be/app/verbomatique-secondaire/id1611881585?pt=123526428&ct=site-nlbe-herexamen-bottom&mt=8 https://play.google.com/store/apps/details?id=be.teamwabisabi.verbomatique_secondaire&hl=nl&gl=BE&referrer=utm_source%3Dwebsite%26utm_medium%3Dreferral%26utm_campaign%3Dsite-nlbe-herexamen-bottom live
site-enca-hero verbomatique.com home template iotix//home, hero badges (images 120/122) website / referral / site-enca-hero https://apps.apple.com/ca/app/verbomatique-secondaire/id1611881585?pt=123526428&ct=site-enca-hero&mt=8 https://play.google.com/store/apps/details?id=be.teamwabisabi.verbomatique_secondaire&referrer=utm_source%3Dwebsite%26utm_medium%3Dreferral%26utm_campaign%3Dsite-enca-hero live
site-enca-pricing verbomatique.com home template, COST block badges (images 123/125) website / referral / site-enca-pricing https://apps.apple.com/ca/app/verbomatique-secondaire/id1611881585?pt=123526428&ct=site-enca-pricing&mt=8 https://play.google.com/store/apps/details?id=be.teamwabisabi.verbomatique_secondaire&referrer=utm_source%3Dwebsite%26utm_medium%3Dreferral%26utm_campaign%3Dsite-enca-pricing live
site-enca-homework verbomatique.com /french-homework/ (page 173) website / referral / site-enca-homework https://apps.apple.com/ca/app/verbomatique-secondaire/id1611881585?pt=123526428&ct=site-enca-homework&mt=8 https://play.google.com/store/apps/details?id=be.teamwabisabi.verbomatique_secondaire&referrer=utm_source%3Dwebsite%26utm_medium%3Dreferral%26utm_campaign%3Dsite-enca-homework live
site-enca-thanks verbomatique.com /thanks/ (page 178) website / referral / site-enca-thanks https://apps.apple.com/ca/app/verbomatique-secondaire/id1611881585?pt=123526428&ct=site-enca-thanks&mt=8 https://play.google.com/store/apps/details?id=be.teamwabisabi.verbomatique_secondaire&referrer=utm_source%3Dwebsite%26utm_medium%3Dreferral%26utm_campaign%3Dsite-enca-thanks live
email-nlbe-welcome-parent Brevo template 13 “Automation #2step#5” (source template 8) brevo / email / email-nlbe-welcome-parent https://apps.apple.com/be/app/verbomatique-secondaire/id1611881585?pt=123526428&ct=email-nlbe-welcome-parent&mt=8 https://play.google.com/store/apps/details?id=be.teamwabisabi.verbomatique_secondaire&hl=nl&gl=BE&referrer=utm_source%3Dbrevo%26utm_medium%3Demail%26utm_campaign%3Demail-nlbe-welcome-parent live
email-nlbe-welcome-teacher Brevo template 12 “Automation #2step#3” (source template 9) brevo / email / email-nlbe-welcome-teacher https://apps.apple.com/be/app/verbomatique-secondaire/id1611881585?pt=123526428&ct=email-nlbe-welcome-teacher&mt=8 https://play.google.com/store/apps/details?id=be.teamwabisabi.verbomatique_secondaire&hl=nl&gl=BE&referrer=utm_source%3Dbrevo%26utm_medium%3Demail%26utm_campaign%3Demail-nlbe-welcome-teacher live
email-enca-welcome-parent Brevo template 11 “Automation #1step#4” (source template 6) brevo / email / email-enca-welcome-parent https://apps.apple.com/ca/app/verbomatique-secondaire/id1611881585?pt=123526428&ct=email-enca-welcome-parent&mt=8 https://play.google.com/store/apps/details?id=be.teamwabisabi.verbomatique_secondaire&referrer=utm_source%3Dbrevo%26utm_medium%3Demail%26utm_campaign%3Demail-enca-welcome-parent live
email-enca-welcome-teacher Brevo template 10 “Automation #1step#3” (source template 7) brevo / email / email-enca-welcome-teacher https://apps.apple.com/ca/app/verbomatique-secondaire/id1611881585?pt=123526428&ct=email-enca-welcome-teacher&mt=8 https://play.google.com/store/apps/details?id=be.teamwabisabi.verbomatique_secondaire&referrer=utm_source%3Dbrevo%26utm_medium%3Demail%26utm_campaign%3Demail-enca-welcome-teacher live
email-nlbe-adfree-welcome Brevo template 36 “Welcome · nl-BE_step_#12” (source template 33, inactive) brevo / email / email-nlbe-adfree-welcome https://apps.apple.com/be/app/verbomatique-secondaire/id1611881585?pt=123526428&ct=email-nlbe-adfree-welcome&mt=8 https://play.google.com/store/apps/details?id=be.teamwabisabi.verbomatique_secondaire&hl=nl&gl=BE&referrer=utm_source%3Dbrevo%26utm_medium%3Demail%26utm_campaign%3Demail-nlbe-adfree-welcome live
email-enca-adfree-welcome Brevo template 37 “Welcome · en-CA_step_#9” (source template 35, inactive) brevo / email / email-enca-adfree-welcome https://apps.apple.com/ca/app/verbomatique-secondaire/id1611881585?pt=123526428&ct=email-enca-adfree-welcome&mt=8 https://play.google.com/store/apps/details?id=be.teamwabisabi.verbomatique_secondaire&referrer=utm_source%3Dbrevo%26utm_medium%3Demail%26utm_campaign%3Demail-enca-adfree-welcome live

Phase 2 status (3 Oct 2026)

  • Site rows (10): live. Verified by behaviour: a cache-busted curl of the .be front page, the .be herexamen page, and the .com home, /french-homework/ and /thanks/. The store hrefs served (20) equal this table exactly. The visible text and every non-store href/src on those pages are identical before and after the edit.
  • Email rows (6): live since 4 Oct 2026. The Brevo API cannot update the automation-step templates: PUT /v3/smtp/templates/{10,11,12,13,36,37} returns 404 {"code":"document_not_found","message":"Template id does not exist"}, although GET on the same IDs returns 200. The steps were therefore edited in Brevo’s web editor, not through the API. A GET read-back of all six on 4 Oct 2026 showed every store href equal to its row in this table, with no old welcome_* / adfree_welcome_* Play tags or untagged App Store links left. The source templates 6, 7, 8 and 9 had already been updated through the API on 3 Oct (204) and re-read.
  • Apple redirect. A storefront link answers 301 to …/id1611881585?ct=<ct>&pt=123526428 (same storefront, mt=8 dropped), then 200. ct and pt survive the redirect. With a plain client, App Store Connect’s region-less /app/apple-store/ form returns 404, and it redirects only for an iPhone user agent. That is one more reason to keep the storefront paths.
Where URL Why not
Brevo campaigns 14–17 (“Welcome backfill”, status sent) the welcome_* links Already sent. A sent campaign cannot be re-tagged.
Brevo templates 6–9 (source templates for automation steps 10–13) now email-… links (updated 3 Oct 2026) Re-tagged in Phase 2 along with their step rows; see “Phase 2 status”. Not separate placements.
Brevo templates 33 and 35 (inactive) as 36 and 37 Inactive. Re-tag with 36/37 for the same reason.
.be post 542 (Colibri preset, draft) apps.apple.com/us/…, bare Play URL Draft preset, not rendered.
Teacher promo codes (_promo-codes-2026-09/, 505 iOS + 5 Play) apps.apple.com/redeem?ctx=offercodes&id=1611881585&code=…, play.google.com/redeem?code=… Redemption URLs, not store-listing links. Campaign parameters are not documented for them. Already distributed.
App update wall (lib/widgets/update_wall.dart, branch feat/min-version-gate only) apps.apple.com/app/id…, play.google.com/store/apps/details?id=… In-app link, not a marketing placement, and no app channel exists in the scheme.
Judo Centrum Leuven print ad (QR code) https://secondaire.verbomatique.be (decoded from ~/Downloads/verbomatique_secondaire_ad_preview.png) Points at the site, not a store. A site UTM on a reprint is a separate decision.

Risk check: do appended parameters break store-click tracking?

Read from the live code on 3 Oct 2026.

  • .be Meta pixel, PlayStoreClick. The WPCode legacy footer option ihaf_insert_footer uses a delegated click listener with closest('a[href]'), then h.indexOf('apps.apple.com') > -1 / h.indexOf('play.google.com') > -1 on the full href. Not affected: a substring test on the host survives any query string.
  • .com Meta pixel, AppStoreClick / PlayStoreClick. An inline footer script uses the same closest('a[href]') and indexOf pattern. Not affected. (It fires AppStoreClick for Apple, where .be fires PlayStoreClick with store: 'app_store'. That inconsistency predates this work.)
  • .be GA4 store_click (stream 3453917046). A create-event rule, click AND link_url matches .*(play\.google\.com|apps\.apple\.com).*. It is GA4 admin config, not code, so it is read from the knowledge file rather than from the live property. Not affected: .* on both sides absorbs any query. GA4 truncates parameter values at 100 characters, and the host sits in the first 30.
  • Google Ads. No store-click conversion is defined in any code read. Per the knowledge file, the Ads conversions are GA4 imports (form_submit) and the bid strategy is Maximise clicks, so link parameters cannot change them.
  • Classification. Generated Play URLs never contain apps.apple.com and generated iOS URLs never contain play.google.com, so the “apple first” branches cannot misfile a click. This is asserted in StoreClickMatcherCompatibilityTest.