Pixel SDK
The Pruuv Pixel is a lightweight JavaScript snippet (~4 KB) that you add to your landing pages. It automatically captures UTM parameters and ad platform click IDs on page load, then sends a conversion event to Pruuv when you call Pruuv.track().
Pruuv.track() is what actually delivers those click IDs to Pruuv so matched conversions can be sent back to your ad platforms. Without track(), Pruuv has no data to send.Quick start
1. Add the snippet to your landing page
Paste the following before the closing </body> tag on every landing page where you want to track conversions:
<script>
window.PruuvConfig = {
stageId: 'YOUR_STAGE_ID',
token: 'YOUR_WEBHOOK_TOKEN'
};
</script>
<script src="https://app.pruuv.io/pixel.min.js" async></script>Replace YOUR_STAGE_ID and YOUR_WEBHOOK_TOKEN with the values from Connections > Conversion & CRM Data > Funnel Webhooks in your Pruuv dashboard.
2. (Optional) Identify the visitor
Call Pruuv.identify() when you know who the visitor is — for example, when they submit a form step or log in. This stores their identity in a first-party cookie so subsequent track() calls don't need to repeat it. The userId becomes the reference field in the funnel event, enabling cross-session identity stitching.
// Call when you know who the user is (form step, login, etc.)
Pruuv.identify('crm-contact-id', {
email: 'jane@example.com',
phone: '+441234567890',
name: 'Jane Smith',
company: 'Acme Ltd'
});
// Then track() with no identity fields needed — they're stored
Pruuv.track('Lead', {
value: 250,
currency: 'GBP'
});3. Fire a conversion event
Call Pruuv.track() at the moment a lead or sale is confirmed — for example, after a form is successfully submitted. If you called identify() earlier, email and phone are already stored and will be sent automatically.
Pruuv.track('Lead', {
email: 'jane@example.com', // hashed in browser — or omit if identify() was called
phone: '+441234567890', // hashed in browser — or omit if identify() was called
value: 250, // revenue value
currency: 'GBP', // ISO 4217 currency code
order_id: 'CRM-REF-001' // your internal reference (overrides identify userId)
});All fields are optional except the event name. The pixel handles everything else automatically.
Full API reference
Pruuv.identify(userId, traits)
| Parameter | Type | Description |
|---|---|---|
| userId | string (required) | Your internal contact or lead ID — becomes the reference field in the funnel event. Use your CRM contact ID, email, or any stable identifier. |
| traits.email | string | Email address. Hashed with SHA-256 before sending. |
| traits.phone | string | Phone number in E.164 format. Hashed before sending. |
| traits.name | string | Display name (not sent in the webhook — for local reference only). |
| traits.company | string | Company name (not sent in the webhook — for local reference only). |
Identity is stored in a 90-day first-party cookie and localStorage. It persists across page loads untilPruuv.reset() is called.
identify() multiple times is safe — the most recent call wins. If the same visitor calls identify() with different userIds across sessions (e.g. after switching accounts), each event is stored independently.Pruuv.track(eventName, options)
| Parameter | Type | Description |
|---|---|---|
| eventName | string (required) | Arbitrary event name — e.g. 'Lead', 'Appointment', 'Sale'. Stored in the funnel event for filtering. |
| options.email | string | Overrides stored identity email for this call. Hashed before sending. |
| options.phone | string | Overrides stored identity phone for this call. Hashed before sending. |
| options.value | number | Revenue or conversion value. |
| options.currency | string | ISO 4217 currency code (e.g. GBP, USD, EUR). |
| options.order_id | string | Your order or CRM reference. Overrides identity userId as the event reference. |
| options.reference | string | Explicit event reference. Takes priority over order_id and identity userId. |
Reference resolution order: options.reference → options.order_id → identity.userId → pruuv_{timestamp}
Pruuv.reset()
Clears the stored identity. Call this on logout so subsequent events are not associated with the previous user. Does not clear click ID cookies — those persist for attribution purposes.
First-touch vs last-touch attribution
The Pruuv Pixel automatically maintains two attribution signals:
| Signal | Cookie | Behaviour |
|---|---|---|
| Last touch | _pruuv_session | Updated on every visit where click IDs or UTMs are present. Sent as the primary attribution in every track() call. |
| First touch | _pruuv_first_touch | Written once on the visitor's very first tracked visit. Never overwritten. Sent as first_touch alongside last-touch when the two differ. |
When a visitor clicks a Google ad, then later clicks a Meta ad and converts, Pruuv records both: the Meta click as last-touch (used for conversion sending) and the Google click as first-touch (surfaced in agent analysis and cross-channel reporting). Both signals are stored in the funnel event automatically — no extra code required.
Native attribution (pruuv_aid)
Pruuv's native attribution path lets you track conversions back to a specific ad creative without relying on platform click IDs. Instead of waiting for a gclid or ttclid in the URL, you embed a Pruuv-generated ID (pruuv_aid) directly in your ad's destination URL template. The pixel captures it automatically on landing.
This approach is platform-agnostic — it works with any ad network that supports URL parameters, and does not depend on the ad platform's click ID system. It is particularly useful when click IDs are stripped by ad blockers or browser privacy settings.
Setup: add pruuv_aid to your ad URL template
In your ad platform's URL template field, add pruuv_aidas a custom parameter. Use the ad's own dynamic substitution macro to fill it per creative. Here are examples for each platform:
| Platform | URL template parameter |
|---|---|
| Meta Ads | ?pruuv_aid={{ad.id}} |
| Google Ads | ?pruuv_aid={creative} |
| TikTok Ads | ?pruuv_aid=__ADID__ |
| Any platform | ?pruuv_aid=YOUR_STATIC_AD_ID |
The value can be a platform macro (so each ad gets its own ID automatically) or a static string you define per campaign. The pixel reads whatever value is in the URL parameter — it does not validate the format.
How it works
On page load, the pixel reads the pruuv_aid URL parameter and stores it in the session cookie alongside other click IDs. When Pruuv.track() is called, the pruuv_aid is included in the webhook payload. Pruuv then matches the event to the specific ad in the pruuv_native_ads table, enabling attribution to that creative, ad set, and campaign — fully server-side, no pixel ID required.
pruuv_aid and a gclid / ttclid are present, the platform click ID is used for conversion sending (Google Upload / TikTok Events API) while pruuv_aid is used for creative-level attribution reporting. You do not need to choose — the pixel captures both.Manual override in track()
If you need to pass a pruuv_aid that was not in the URL (e.g. stored in your own session state), you can pass it directly in track():
Pruuv.track('Lead', {
pruuv_aid: 'your-ad-id-here',
email: 'jane@example.com',
value: 250,
currency: 'GBP'
});An explicit pruuv_aid passed to track() overrides any value captured automatically from the URL.
How it works
On every page load
The pixel runs silently as soon as the page loads. It reads the following URL parameters and stores them in first-party cookies (90-day expiry):
| Parameter | Platform | Cookie |
|---|---|---|
| utm_source, utm_medium, utm_campaign, utm_content, utm_term | All | _pruuv_session |
| gclid, wbraid, gbraid | Google Ads | _pruuv_session |
| ttclid | TikTok Ads | _pruuv_session |
| msclkid | Microsoft Ads | _pruuv_session |
| fbclid | Meta Ads | _fbc |
Two special cookies are also maintained:
_pruuv_first_touch— a snapshot of the very first click that brought this visitor. Written once and never overwritten._fbp— Meta's browser ID. Generated on first visit and persists for 90 days. Required for Meta Conversions API matching.
On Pruuv.track()
When you call track(), the pixel:
- Reads stored click IDs and UTMs from cookies (last-touch)
- Reads stored identity from
_pruuv_identity— merges with any values you pass explicitly - SHA-256 hashes email and phone in the browser — PII never leaves in plaintext
- If the visitor's first-touch differs from their current session, includes it as
first_touchin the payload - Sends a single POST to your Pruuv webhook with all signals included
Framework examples
React / Next.js
async function handleSubmit(data) {
const result = await submitForm(data)
if (result.ok) {
window.Pruuv?.track('Lead', {
email: data.email,
value: 250,
currency: 'GBP',
order_id: result.referenceId
})
}
}The optional chaining (?.) means the call is a no-op if the pixel is not loaded.
HTML form
<form id="contact-form">
<!-- your fields -->
<button type="submit">Get a quote</button>
</form>
<script>
document.getElementById('contact-form').addEventListener('submit', function(e) {
e.preventDefault();
var email = this.querySelector('[name="email"]').value;
// submit your form here, then on success:
Pruuv.track('Lead', { email: email, currency: 'GBP' });
});
</script>Google Tag Manager
Create a Custom HTML tag triggered on your form success event or thank-you page:
<script>
Pruuv.track('Lead', {
email: '{{DLV - email}}',
value: {{DLV - lead_value}},
currency: 'GBP',
order_id: '{{DLV - reference}}'
});
</script>Privacy
- Email and phone are hashed with SHA-256 in the browser before being sent — Pruuv never stores plaintext PII
- The pixel sets first-party cookies only — no third-party cookies, no cross-site tracking
- No data is sent to any third party by the pixel — all data goes directly to your Pruuv webhook endpoint
- The pixel does not load any external scripts or resources
Troubleshooting
No events appearing in Pruuv
- Check the browser network tab — look for a POST to
/api/webhooks/funnel/...and inspect the response - Verify
window.PruuvConfig.stageIdandwindow.PruuvConfig.tokenare set before the pixel loads - Confirm the token matches the one shown in Connections > Funnel Webhooks
Events appear but click IDs are missing
- Ensure the pixel snippet is on the landing page — the page the user arrives on after clicking the ad — not just the thank-you page
- Click IDs are only available in the URL on the initial landing. They cannot be recovered if the user navigates before the pixel loads
Meta conversion matching rate is low
- Ensure
fbcandfbpare being captured — they are only available via the browser pixel - Include
emailorphoneinPruuv.track()for additional matching signals - Server-side-only integrations will always have lower Meta match rates without the fbc/fbp cookies