Docs

Matching sessions to ads

Every session with paid attribution is assigned to the most specific ad entity 3x can prove. The ads.match job evaluates new sessions every 15 minutes and re-evaluates the last 90 days whenever entities, URL tags or rules change. The result (session_ad_match) stores the platform, account, campaign, ad set, ad and the method that matched.

Methods (first match wins)

#MethodEvidencePrecision
1click_idgclid/gbraid/wbraid found in Google's click viewexact ad and keyword
2utm_idUTM values that are platform ids of imported campaigns/ad sets/ads (templates)exact
3utm_mapthe literal UTM combination configured on an ad (Meta URL parameters, TikTok landing URLs, LinkedIn URLs, Google suffixes and templates)exact, or the deepest common parent when several ads share it
4namenormalized utm_campaign equals a campaign name (umlauts transliterated, punctuation → -)campaign; only when unique per platform and account
5manualyour mapping rules, highest priority firstas configured
6platformonly the platform is known (click id or a source alias like fb, ig, li)platform

Platform-level matches still count for platform cost per session; they just cannot be broken down further.

Unmatched UTMs

Dashboard → Ads → Unmatched UTMs (GET /v1/projects/{project}/ads/unmatched, MCP ads_unmatched) lists UTM combinations of paid sessions that matched only at platform level or not at all, with session counts. Typical causes:

  • ads without URL parameters (add the template),
  • hand-written campaign names that differ from the platform name (spring-sale vs. "Spring Sale 2026 – DE"),
  • links from organic posts of the same platform,
  • old campaigns that were deleted before the first sync (entities are only imported while they exist).

Mapping rules

A rule maps a UTM pattern to an entity:

{
  "platform": "meta_ads",
  "accountId": "act_1234567890",
  "match": { "utm_source": "fb", "utm_campaign": "spring-sale" },
  "campaignId": "120210000000000001",
  "adsetId": null,
  "adId": null,
  "priority": 10,
  "note": "Spring campaign used hand-written UTMs"
}
  • match takes any of utm_source, utm_medium, utm_campaign, utm_content, utm_term, utm_id; all given keys must be equal (case-insensitive).
  • Higher priority wins when several rules fit.
  • Create rules from the unmatched view with one click, via POST /v1/projects/{project}/ads/mapping-rules (scope ads:write) or MCP ads_mapping_rules_create. Existing sessions are re-matched on the next ads.match run.

Day alignment

Costs are stored per ad-account day, sessions per project day. With different time zones, a daily chart can shift spend by a few hours relative to sessions. Ranges of several days are practically unaffected. LinkedIn is always UTC.