Form Attribution is a lightweight script that automatically captures and adds marketing attribution data to your forms as hidden fields.
Quick Start
Add the script to your website before the closing
</body> tag:
<script src="https://cdn.jsdelivr.net/npm/form-attribution@latest/dist/script.min.js"></script>
That's it! The script will automatically:
- Capture common URL parameters and metadata (e.g. landing page)
- Store the data in the user's browser temporarily
- Inject hidden fields into all forms on the page
Data Attributes
Configure the script by adding optional data attributes to the script tag:
<script src="/dist/script.min.js"
data-storage="localStorage"
data-field-prefix="attr_"
data-extra-params="gclid,fbclid"
data-exclude-forms=".no-track"
data-debug="true">
</script>
| Attribute | Default | Description |
|---|---|---|
data-storage
|
sessionStorage
|
Storage method: sessionStorage,
localStorage, or cookie
|
data-field-prefix
|
""
|
Prefix for hidden field names (e.g., attr_
creates attr_utm_source)
|
data-extra-params
|
""
|
Comma-separated list of additional URL parameters to capture |
data-exclude-forms
|
""
|
CSS selector for forms to exclude from injection |
data-storage-key
|
form_attribution_data
|
Custom key name for stored data |
data-debug
|
false
|
Enable console logging and debug panel |
data-privacy
|
true
|
Set to "false"to disable GPC/DNT privacy
signal detection
|
data-click-ids
|
false
|
Set to "true"to automatically capture ad
platform click IDs
|
Storage Options
Choose where attribution data is persisted between page loads:
Session Storage (default)
Data persists for the browser session only.
<script src="/dist/script.min.js" data-storage="sessionStorage"></script>
Local Storage
Data persists until explicitly cleared.
<script src="/dist/script.min.js" data-storage="localStorage"></script>
Cookies
Data accessible server-side and can span subdomains.
<script src="/dist/script.min.js" data-storage="cookie"></script>
Privacy Controls
By default, the script respects user privacy preferences:
-
Global Privacy Control (GPC): Disables
tracking when
navigator.globalPrivacyControlis true - Do Not Track (DNT): Disables tracking when DNT is enabled
When privacy signals are detected, no data is captured or stored.
Disable Privacy Signal Detection
If you need to disable privacy signal detection (not recommended):
<script src="/dist/script.min.js" data-privacy="false"></script>
Click ID Tracking
Enable automatic capture of ad platform click IDs:
<script src="/dist/script.min.js" data-click-ids="true"></script>
When enabled, the following parameters are automatically tracked:
| Parameter | Platform |
|---|---|
gclid
|
Google Ads |
fbclid
|
Meta Ads |
msclkid
|
Microsoft Advertising |
ttclid
|
TikTok Ads |
li_fat_id
|
LinkedIn Ads |
twclid
|
Twitter/X Ads |
Debug Panel
The debug panel provides a visual interface for inspecting attribution data, viewing tracked forms, and monitoring activity in real-time.
Enabling the Debug Panel
Add data-debug="true"to the script tag:
<script src="/dist/script.min.js" data-debug="true"></script>
Features
- Data Tab: View all captured UTM parameters and metadata
- Forms Tab: See all forms on the page and their injection status (click to highlight)
- Log Tab: Real-time activity log with timestamps
- Copy: Export attribution data as JSON to clipboard
- Clear: Remove all stored attribution data
- Refresh: Re-inject data into all forms
The panel can be minimized, dragged to reposition, and its state persists across page reloads.
data-debugbefore deploying
to production.
JavaScript API
Form Attribution exposes a global FormAttribution
object for programmatic access to attribution data and control.
Methods
| Method | Returns | Description |
|---|---|---|
getData()
|
Object|null
|
Get all captured attribution data |
getParam(name)
|
string|null
|
Get a specific parameter value |
getForms()
|
Array
|
Get list of tracked forms with their status |
clear()
|
void
|
Clear all stored attribution data |
refresh()
|
void
|
Re-inject data into all forms |
on(event, callback)
|
Object
|
Register a callback for events (chainable, supports multiple listeners) |
off(event, callback)
|
Object
|
Unregister a previously registered callback (chainable) |
Properties
| Property | Type | Description |
|---|---|---|
config
|
Object
|
Current configuration (read-only) |
github
|
string
|
GitHub repository URL |
docs
|
string
|
Documentation URL |
Events
| Event | Payload | Description |
|---|---|---|
onReady
|
{ data, config }
|
Fired when initialization is complete |
onCapture
|
{ data }
|
Fired when new data is captured |
onUpdate
|
{ data }
|
Fired when data is updated |
Example Usage
// Wait for initialization
FormAttribution.on('onReady', ({ data, config }) => {
console.log('Attribution ready:', data);
});
// Get all attribution data
const data = FormAttribution.getData();
console.log(data);
// { utm_source: 'google', utm_medium: 'cpc', ... }
// Get a specific parameter
const source = FormAttribution.getParam('utm_source');
console.log(source); // 'google'
// Get tracked forms
const forms = FormAttribution.getForms();
forms.forEach(form => {
// Status: 'Injected' (has data), 'Ready' (no data yet), or 'Excluded'
const status = form.excluded ? 'excluded' : form.injected ? 'injected' : 'ready';
console.log(form.name, status);
});
// Clear data (useful for testing)
FormAttribution.clear();
// Re-inject into forms
FormAttribution.refresh();
// Access current config
console.log(FormAttribution.config.storage); // 'sessionStorage'
// Remove a callback
const myHandler = ({ data }) => console.log('Captured:', data);
FormAttribution.on('onCapture', myHandler);
// Later...
FormAttribution.off('onCapture', myHandler);
Captured Parameters
URL Parameters (default)
| Parameter | Description |
|---|---|
utm_source
|
Traffic source (e.g., google, newsletter) |
utm_medium
|
Marketing medium (e.g., cpc, email) |
utm_campaign
|
Campaign name |
utm_term
|
Paid search keywords |
utm_content
|
Content variant for A/B testing |
utm_id
|
Campaign ID |
ref
|
Referrer tracking parameter |
Metadata (automatically captured)
| Parameter | Description |
|---|---|
landing_page
|
First page URL visited |
current_page
|
Current page URL (where form was submitted) |
referrer_url
|
Document referrer |
first_touch_timestamp
|
ISO 8601 timestamp of first visit |
Injected Fields
Hidden fields are injected with the following attributes:
<input type="hidden"
name="utm_source"
value="google"
data-form-attribution="true"
data-form-attribution-managed="true">
- Existing hidden fields with matching names are updated (no duplicates created)
- User-visible form fields are never modified
- All values are HTML-entity encoded for XSS protection
Storage Fallbacks
The script uses intelligent fallbacks when a storage type isn't available:
| Requested | Fallback Chain |
|---|---|
localStorage
|
localStorage → sessionStorage → cookie → memory |
sessionStorage
|
sessionStorage → cookie → memory |
cookie
|
cookie → memory |