A small, dependency-free browser library for keeping the first marketing touch that brought someone to your site. It captures UTM parameters, supported advertising click IDs, the landing page, and the external referrer. It does not make network requests or send the data anywhere.
Try the live demo or read the source.
Use Attribution Tracker when you need to keep the first marketing touch in the browser and pass selected values into a form, Server Action, analytics event, or backend request. It is deliberately smaller than a full analytics platform.
| Requirement | Fit |
|---|---|
| Keep first-touch UTMs, supported click IDs, landing page, and referrer | Yes |
Store data in a first-party cookie or sessionStorage |
Yes |
| Send data to a form, analytics service, or CRM | Your application handles the handoff |
| Collect page views, events, sessions, or conversions | No |
| Connect activity across devices or cleared storage | No |
| Model multiple touches or assign conversion credit | No |
| Replace a consent manager | No |
<script src="https://cdn.jsdelivr.net/gh/jasenf/attribution-tracker.js@v0.1.1/dist/attribution-tracker.js"></script>
<script>
const tracker = new AttributionTracker({
consent: () => window.cookieConsent === true
});
const attribution = tracker.getAll();
</script>You can also download tracker.js and serve it from your own site.
npm install @feech/attribution-trackerimport AttributionTracker from '@feech/attribution-tracker';
const tracker = new AttributionTracker({ consent: true });
console.log(tracker.getAll());consent: true is appropriate only when your application has already received the required consent. In production, a callback tied to your consent manager is usually safer.
Given this first visit:
https://example.com/pricing?utm_source=newsletter&utm_medium=email&ref=partner
getAll() returns an object like this:
{
utm_source: 'newsletter',
utm_medium: 'email',
ref: 'partner',
referrer: 'https://partner.example/article',
landingPage: 'https://example.com/pricing?utm_source=newsletter&utm_medium=email&ref=partner',
timestamp: '2026-09-20T12:00:00.000Z'
}First-touch values win. Later visits do not replace values that are already stored.
The default parameters are:
- UTM:
utm_source,utm_medium,utm_campaign,utm_content,utm_term - Referral:
ref - Facebook and Meta:
fbclid,fb_source,fb_ref,mclid - Google Ads:
gclid,gclsrc,dclid,gad_source - X and Twitter:
twclid,tw_source - Reddit:
rdt_cid,rdt_source
If ref is absent, the tracker can infer a short label from a supported click ID, a known utm_source, or an external referrer. An explicit ref always wins. ref is separate from referrer, which contains the original document.referrer URL.
const tracker = new AttributionTracker({
cookieDuration: 30,
useSessionStorage: false,
additionalParams: ['affiliate_id'],
storageKey: 'attribution_data',
consent: () => window.cookieConsent === true,
requireConsent: true,
debug: false,
cookieSameSite: 'Lax',
cookieSecure: true
});| Option | Default | Description |
|---|---|---|
cookieDuration |
30 |
Number of days before the first-party cookie expires. |
useSessionStorage |
false |
Store data in sessionStorage instead of a cookie. |
additionalParams |
[] |
Extra query parameters to capture. |
storageKey |
attribution_data |
Cookie or session storage key. |
consent |
undefined |
A boolean or callback that supplies the current consent decision. |
requireConsent |
true |
When true, the tracker does nothing if it cannot find a consent decision. |
debug |
false |
Write diagnostic messages to the browser console. Values are not logged unless this is true. |
cookieSameSite |
Lax |
Cookie SameSite value: Strict, Lax, or None. |
cookieSecure |
HTTPS sites: true |
Add the cookie Secure attribute. |
Attribution Tracker is a storage utility, not a consent manager. It does not claim that a site is compliant with GDPR, ePrivacy rules, or any other law.
By default, the tracker requires consent before it captures or stores anything. It checks, in order:
- The
consentconfiguration value or callback. - Global Privacy Control and Do Not Track signals.
- A boolean
window.cookieConsentvalue. - Common
cookieconsent_statusandcookie_consentcookies.
If none of those supplies an affirmative decision, capture is skipped. Connect the consent callback to the consent manager used by your site:
const tracker = new AttributionTracker({
consent: () => Cookiebot.consent.marketing
});Landing page URLs, referrers, advertising click IDs, and custom parameters can contain identifying or sensitive values. Decide what to capture, how long to retain it, and where it may be sent before using the library in production.
| Method | Result |
|---|---|
getAll() |
The complete stored object, or null. |
getUtmParameters() |
Stored UTM parameters only. |
getAdPlatformParameters() |
Stored advertising platform parameters only. |
getRef() |
The explicit or inferred referral label. |
getReferrer() |
The original HTTP referrer URL. |
getLandingPage() |
The complete first landing page URL. |
getTimestamp() |
The ISO timestamp recorded on the first visit. |
clear() |
Removes the stored attribution data. |
const tracker = new AttributionTracker({ consent: hasMarketingConsent });
form.addEventListener('submit', () => {
const field = document.createElement('input');
field.type = 'hidden';
field.name = 'attribution';
field.value = JSON.stringify(tracker.getAll());
form.append(field);
});For a complete HTML example that adds individual hidden fields and previews the submitted payload, see examples/form-hidden-fields.html. The same form shape works with Formspree or a conventional server endpoint.
The form attribution guide explains how to keep the first touch for a return visit and attach selected fields at submission time.
If you use Google Tag Manager, see the GTM consent and form handoff recipe.
For the App Router, the Next.js example uses a consent-aware Client Component and sends selected values to a Server Action.
const tracker = new AttributionTracker({
consent: true,
useSessionStorage: true
});- This is first-touch browser storage, not a complete multi-touch attribution system.
- It does not connect activity across browsers, devices, or cleared storage.
- Browser privacy controls can shorten or block storage.
- JavaScript-set cookies behave differently from server-set cookies in some browsers.
- The built-in registrable-domain helper covers common multi-part domains. It is not a complete public suffix implementation.
- The library does not submit attribution to a form, analytics service, or CRM unless your application does so.
| Area | Support | Notes |
|---|---|---|
| Browsers | Current Chrome, Edge, Firefox, and Safari | Requires URL, URLSearchParams, cookies or sessionStorage, and modern JavaScript syntax. |
| Storage | First-party cookie or sessionStorage |
Cookie storage is the default. Session storage lasts for the browser session. |
| Consent integration | Boolean or callback | Connect the callback to the site's consent manager. |
| GPC and DNT | Automatic blocking | Applied when an explicit consent value or callback has not already supplied the decision. |
| Campaign parameters | Five standard UTM fields plus ref |
Add project-specific query parameters with additionalParams. |
| Advertising click IDs | Google, Facebook and Meta, X and Twitter, and Reddit | The exact supported parameters are listed under What it stores. |
| Network requests | None | The library only stores and returns attribution data. |
| Server-side or cross-device identity | Not included | Send selected fields to your own backend if you need server-side processing. |
The project has no runtime dependencies. Node.js 20 or newer is required for development.
npm test
npm run buildThe build writes:
dist/attribution-tracker.esm.jsfor package importsdist/attribution-tracker.jsfor script tags and CDNstracker.jsfor backward compatibility
See CONTRIBUTING.md before opening a pull request.