Overview
Privacy-aware attribution primitives for web applications:
@absolutejs/attributionv0.1.0betaCommerce & GrowthPrivacy-aware click-ID capture, allowlisted link decoration, resilient Google tag loading, and consent-aware server conversion delivery.
@absolutejs/attribution keeps paid-click identity alive without turning attribution into a second analytics database. It captures validated Google click identifiers, stores only the identifiers and capture time, decorates links only for explicitly trusted origins, and provides a resilient Google tag controller. A separate server helper sends consent-aware conversions to Google Data Manager so applications can pair browser measurement with a retryable, idempotent backend job.
bun add @absolutejs/attributionPrivacy-aware attribution primitives for web applications:
capture gclid, gbraid, and wbraid without persisting full landing URLs;
forward identifiers only to explicitly allowlisted owned origins;
load the Google tag through a retrying idle → loading → ready/failed state
machine;
keep consent and conversion commands queued while the tag recovers;
emit identifier-free load telemetry; and
supplement browser tag conversions through Google Data Manager using the same
transaction ID for deduplication.
The package never sends full landing URLs or click identifiers through its telemetry callback. Server delivery requires an explicit access-token provider, destination, consent state, and click identifier.
Capture gclid, gbraid, and wbraid with strict validation and a configurable age limit. Full landing URLs are never stored.
Decorate outbound links only when their exact origin is in the caller-provided allowlist.
The Google tag controller exposes idle, loading, ready, waiting-online, failed, and closed states with bounded retries.
Default and updated Consent Mode commands are queued before tag configuration and remain available while the script recovers.
Track conversions with value, currency, destination, completion timeout, and a transaction ID that can also identify server delivery.
Send a validated, consent-aware conversion to Google Data Manager using an injected token provider and fetch implementation.
Explore the handoff from a paid landing page to browser and server conversion delivery. Each boundary is explicit, so attribution does not leak into unrelated links or telemetry.
Choose the smallest delivery surface that meets your reliability requirements. Browser and server delivery are complementary, not competing implementations.
Best for: Lightweight funnels where best-effort browser measurement is sufficient.
Tradeoffs: Simple and immediate, but extensions, privacy controls, offline clients, and upstream script failures can block delivery.
RequirementsThe package keeps each data surface narrow. Use this matrix when reviewing privacy behavior or deciding what application state to retain.
| Option | Click IDs | Full landing URL | Boundary |
|---|---|---|---|
| Stored snapshot | Yes | Never | sessionStorage + expiry |
| Decorated link | Yes | No | Explicitly allowlisted origins only |
| Load telemetry | Only a boolean | Never | Attempt, state, recovery |
| Data Manager request | Yes | Never | Explicit server destination |
Outcomes
Privacy-aware attribution primitives for web applications:
The package never sends full landing URLs or click identifiers through its telemetry callback. Server delivery requires an explicit access-token provider, destination, consent state, and click identifier.
Hardening checklist
Follow in order
Working example for Browser attribution.
import { createAttributionStore } from "@absolutejs/attribution";
import { createGoogleAdsTag } from "@absolutejs/attribution/google-ads";
const attribution = createAttributionStore();
attribution.capture();
const google = createGoogleAdsTag({
attribution,
consent: {
adPersonalization: "denied",
adStorage: "denied",
adUserData: "denied",
analyticsStorage: "denied",
},
id: "AW-123",
onTelemetry: (event) => console.info(event),
});
// Start after framework hydration/mount.
google.start();
const qualificationUrl = attribution.decorate("https://qualify.example.com", [
"https://qualify.example.com",
]);Working example for Durable Google conversion supplement.
import { sendGoogleAdsDataManagerConversion } from "@absolutejs/attribution/google-ads";
await sendGoogleAdsDataManagerConversion(
{
accessToken: getGoogleAccessToken,
accountId: process.env.GOOGLE_ADS_ACCOUNT_ID!,
conversionActionId: process.env.GOOGLE_ADS_CONVERSION_ACTION_ID!,
},
{
consent: { adPersonalization: "denied", adUserData: "denied" },
eventTimestamp: new Date().toISOString(),
identifiers: { gclid },
transactionId: paymentTransactionId,
},
);Capture a paid-click identifier, establish denied-by-default consent, and start the retrying Google tag after hydration.
import { createAttributionStore } from '@absolutejs/attribution';
import { createGoogleAdsTag } from '@absolutejs/attribution/google-ads';
const attribution = createAttributionStore();
attribution.capture();
const google = createGoogleAdsTag({
attribution,
consent: {
adPersonalization: 'denied',
adStorage: 'denied',
adUserData: 'denied',
analyticsStorage: 'denied'
},
id: 'AW-123456789',
onTelemetry: ({ attempt, event, recovered }) => {
observeTagLoad({ attempt, event, recovered });
}
});
// Call after framework hydration or mount.
google.start();Decorate an owned checkout origin, update consent from your consent UI, and use the order ID as the browser conversion transaction ID.
const checkoutUrl = attribution.decorate(
'https://checkout.example.com/upgrade',
['https://checkout.example.com']
);
google.updateConsent({
adPersonalization: 'denied',
adStorage: 'granted',
adUserData: 'granted',
analyticsStorage: 'granted'
});
google.trackConversion({
currency: 'USD',
sendTo: 'AW-123456789/purchase',
transactionId: order.id,
value: order.total
});Run Data Manager delivery inside your durable queue. Reuse the browser transaction ID so Google can deduplicate both paths.
import { sendGoogleAdsDataManagerConversion } from
'@absolutejs/attribution/google-ads';
const conversion = {
consent: {
adPersonalization: 'denied',
adUserData: 'granted'
},
currency: 'USD',
eventTimestamp: order.paidAt.toISOString(),
identifiers: order.attributionIdentifiers,
transactionId: order.id,
conversionValue: order.total
} as const;
await conversionQueue.add('google-ads-conversion', conversion);
// In the durable worker:
await sendGoogleAdsDataManagerConversion(
{
accessToken: getGoogleAccessToken,
accountId: env.GOOGLE_ADS_ACCOUNT_ID,
conversionActionId: env.GOOGLE_ADS_CONVERSION_ACTION_ID
},
conversion
);
Search the declarations exported by the current package type files. Expand a symbol to inspect its source-backed signature.
const GOOGLE_CLICK_ID_PARAMETERS: readonly ["gclid", "gbraid", "wbraid"];@absolutejs/attributionCurrent package surface
Import surface · click to copy