Skip to content

feat: capture click IDs from other ad platforms with the clickParams option - #224

Merged
sadjow merged 9 commits into
mainfrom
feat/click-params
Oct 14, 2026
Merged

sadjow merged 9 commits into
mainfrom
feat/click-params

Conversation

@sadjow

@sadjow sadjow commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

Campaign visits from Meta, Microsoft Advertising, TikTok, LinkedIn, and other ad platforms arrive with their own click IDs, such as fbclid or msclkid. The module only recognizes UTM and Google parameters, so with captureWithoutCampaign: false these visits are dropped, and otherwise they are saved as direct visits that never become first or last touch. The README suggested reading fbclid in a utm:before-persist hook, which stores it in customParams but still leaves the visit outside attribution.

The new clickParams option lists extra query parameter names to capture:

export default defineNuxtConfig({
  modules: ['nuxt-utm'],
  utm: {
    clickParams: ['fbclid', 'msclkid', 'ttclid', 'li_fat_id'],
  },
})

A visit with a nonempty value for any listed name is a campaign visit. Its values are saved in the entry's new optional clickParams field and count toward captureWithoutCampaign, first touch, last touch, and deduplication, the same way UTM and Google click parameters do.

  • src/runtime/utm.ts adds urlHasClickParams and getClickParams, built on the helpers from feat: capture GA4 campaign parameters and Google click IDs used on iOS and Display & Video 360 #223. The helpers read only the query's own properties, so a configured name such as constructor cannot match what every object inherits. isRepeatedEntry compares every stored click ID, not only the currently configured names, so changing the list between visits cannot hide a new click.
  • src/runtime/history.ts accepts stored entries whose clickParams is a string map, and getCampaignTouches treats them as campaigns.
  • src/options.ts holds the build time option checks. The existing maxAge and maxEntries checks moved there from src/module.ts unchanged. clickParams must be a list of nonempty names without surrounding spaces, and it cannot include a UTM or Google click parameter, because those are already captured in utmParams and gclidParams; the error names the field.
  • src/runtime/parameters.ts holds that name rule, and the plugin applies it to the runtime config too. A runtime override such as NUXT_PUBLIC_UTM_CLICK_PARAMS=fbclid,msclkid arrives as a string and skips the build time checks, so the plugin ignores anything that is not a valid list instead of failing every capture.
  • The README documents the option, updates the places that list what counts as a campaign, and changes the hook example from fbclid to a non-click promo value so it no longer points click IDs at customParams. It also says to list only the click IDs a site's consent policy covers, and that every query parameter stays in additionalInfo.landingPageUrl unless a hook redacts it.

There are no defaults, so existing sites capture exactly what they did before. Design choices worth a reviewer's opinion:

  • The option and the entry field are both named clickParams, mirroring utmParams and gclidParams. The option is a list of names and the field is a map of values.
  • Listing a name that is already built in, such as gclid, fails the build. That keeps clickParams limited to other platforms' click IDs, so a backend that counts click IDs across both maps cannot count gclid twice. The option is new, so this excludes no existing configuration.
  • The option is opt-in with no suggested defaults, because which platforms matter, and whether storing their IDs is acceptable under a site's consent policy, varies by site.

The unit, history, options, and browser integration tests were written first and failed for the intended reasons: the helpers were missing, history ignored clickParams, the options module did not exist, and the integration fixture saved no entry within the timeout. They pass with the change. The later tests for whitespace and built-in names, inherited names, and a string runtime override also failed first, and the test for a visit without click IDs after one with them fails if deduplication compares only the current entry's keys.

Validation: pnpm lint --max-warnings 0, pnpm format:check, pnpm test:types, pnpm dev:build, pnpm test (113 tests), pnpm test:package, and pnpm test:compatibility on Nuxt 4.6.1 and Nuxt 3.21.11 pass.

@sadjow

sadjow commented Oct 14, 2026

Copy link
Copy Markdown
Member Author

Review notes before merging:

  • The query helpers read a configured name with a plain property lookup, so clickParams: ['constructor'] matched the function every object inherits and marked every visit as a campaign. They now read only the query's own properties.
  • Listing gclid or a UTM name would have stored the same value twice and let a backend that sums click IDs across both maps count it twice. The build now fails with the field that already captures the name, and empty names or names with surrounding spaces fail too, which catches typos such as ' fbclid'. The option is new, so this rejects no existing configuration.
  • A runtime override such as NUXT_PUBLIC_UTM_CLICK_PARAMS=fbclid,msclkid reaches the plugin as a string and skips the build time checks. The plugin applies the same name rule and ignores anything that isn't a valid list, so a malformed override leaves UTM and Google tracking working instead of breaking every capture.
  • A test now covers a visit without click IDs right after one with them, and it fails if deduplication compares only the current entry's keys.
  • The README says to list only the click IDs a site's consent policy covers, and that every query parameter still stays in additionalInfo.landingPageUrl unless a utm:before-persist hook redacts it.

Base automatically changed from feat/google-campaign-parameters to main October 14, 2026 01:31
# Conflicts:
#	README.md
#	src/runtime/parameters.ts
#	src/runtime/utm.ts
#	test/utm.test.ts
@sadjow
sadjow enabled auto-merge (squash) October 14, 2026 01:32
@sadjow
sadjow merged commit cf29d31 into main Oct 14, 2026
7 checks passed
@sadjow
sadjow deleted the feat/click-params branch October 14, 2026 01:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant