Prooflytics + Criteo: Retargeting Attribution Traced to Closed B2B Deals
Criteo is the largest retargeting and performance advertising platform. B2B SaaS companies use Criteo to bring back site visitors who did not convert on their first visit. The standard Criteo metric is conversions and ROAS. The problem: Criteo counts any target action on the site (form fill, registration) as a conversion - but not a closed B2B deal. The real question is how many CLOSED DEALS a Criteo campaign actually produced and what the CAC is. Prooflytics closes that gap.
Criteo operates on a first-party data model: the Criteo browser script (OneTag) collects events, and the Criteo Shopper Graph builds retargeting audiences. In B2B, retargeting is most effective when a visitor was browsing pricing or features pages - these are High Intent signals. But even with well-targeted audiences, without tying ad spend to CRM deals it is impossible to know which campaigns actually convert into revenue.
Criteo Events API (server-side) allows you to send conversion events directly from the server, bypassing ad blockers. It is complementary to OneTag (the browser script).
How Criteo Attribution Works
Criteo uses the criteo_write cookie and a click ID in the cto_bundle parameter (or a gclid-style parameter called cto_pld). When a user clicks an ad:
- Criteo sets a cookie containing click information
- A parameter is appended to the landing page URL (depending on your setup)
gum_caller_id - Criteo’s Universal Matching - is a more reliable mechanism: the user is identified via an email hash (User ID matching), not solely by cookie.
Prooflytics + Criteo Architecture
User clicks a Criteo ad
-> Landing page: OneTag (browser) records the click
-> Prooflytics JS captures Criteo click cookie + email at registration
Prooflytics backend
-> Store attribution: {email -> criteo_click_data, timestamp}
When the lead registers in CRM (HubSpot/Kommo)
-> Prooflytics enriches the lead with Criteo attribution
When the deal is closed (CRM webhook: closed_won)
-> Prooflytics sends a conversion to the Criteo Events API
-> Calculates CAC: Criteo spend / closed deals
Implementation: Capturing Criteo Attribution on the Client Side
Prooflytics JS (embedded on the site alongside Criteo OneTag):
(function() {
var PROOFLYTICS_KEY = 'YOUR_PROOFLYTICS_KEY';
var API_BASE = 'https://api.prooflytics.io/v1';
// Get Criteo user ID from the criteo_write cookie or URL parameter
function getCriteoData() {
var criteoId = null;
// Method 1: from URL parameter cto_pld (click payload)
var urlParams = new URLSearchParams(window.location.search);
var ctoPld = urlParams.get('cto_pld');
if (ctoPld) {
criteoId = ctoPld;
sessionStorage.setItem('prooflytics_criteo_id', ctoPld);
sessionStorage.setItem('prooflytics_criteo_ts', Date.now().toString());
}
// Method 2: from sessionStorage (if the user already clicked in this session)
if (!criteoId) {
criteoId = sessionStorage.getItem('prooflytics_criteo_id');
}
return criteoId;
}
// On successful registration/login - send attribution
window.prooflyticsTrackCriteo = function(email) {
var criteoId = getCriteoData();
if (!criteoId || !email) return;
var payload = {
email: email,
criteo_id: criteoId,
page_url: window.location.href,
referrer: document.referrer,
};
navigator.sendBeacon(
API_BASE + '/attribution/criteo',
JSON.stringify(Object.assign({}, payload, {api_key: PROOFLYTICS_KEY}))
);
};
})();
Call window.prooflyticsTrackCriteo(email) after a user successfully registers or logs in.
Implementation: Prooflytics Server - Receiving and Storing Attribution
import requests, time, os
from flask import Flask, request, jsonify
app = Flask(__name__)
CRITEO_PARTNER_ID = os.environ["CRITEO_PARTNER_ID"]
CRITEO_CLIENT_ID = os.environ["CRITEO_CLIENT_ID"]
CRITEO_CLIENT_SECRET = os.environ["CRITEO_CLIENT_SECRET"]
@app.route("/v1/attribution/criteo", methods=["POST"])
def receive_criteo_attribution():
data = request.json or {}
email = data.get("email", "")
criteo_id = data.get("criteo_id", "")
if not email or not criteo_id:
return jsonify({"error": "missing fields"}), 400
# Store attribution: email -> criteo_id
record = {
"email": email,
"criteo_id": criteo_id,
"page_url": data.get("page_url", ""),
"received_at": int(time.time()),
}
db.upsert("criteo_attribution", record, key="email")
return jsonify({"status": "ok"}), 200
Implementation: Sending a Conversion to the Criteo Events API on Deal Close
def get_criteo_token() -> str:
r = requests.post(
"https://api.criteo.com/oauth2/token",
json={
"client_id": CRITEO_CLIENT_ID,
"client_secret": CRITEO_CLIENT_SECRET,
"grant_type": "client_credentials",
}
)
return r.json()["access_token"]
def send_criteo_conversion(email: str, deal_value: float, deal_id: str):
attr = db.get("criteo_attribution", email=email)
if not attr:
return # no Criteo attribution found for this user
token = get_criteo_token()
event = {
"id": deal_id,
"channel": "web",
"timestamp": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
"eventType": "transactionConfirmation",
"currency": "USD",
"products": [{"id": "b2b_deal", "price": deal_value, "quantity": 1}],
"user": {
"email": email,
},
}
requests.post(
"https://api.criteo.com/2024-07/events/confirm",
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
"Criteo-Partner-Id": str(CRITEO_PARTNER_ID),
},
json={"events": [event]},
timeout=10,
)
# CRM webhook handler: deal closed_won
@app.route("/crm/deal-won", methods=["POST"])
def deal_won():
data = request.json or {}
email = data.get("contact_email", "")
deal_id = data.get("deal_id", "")
value = float(data.get("deal_value", 0))
if email:
send_criteo_conversion(email, value, deal_id)
return jsonify({"status": "ok"}), 200
What Marketers See in Prooflytics
After setup, the Prooflytics dashboard shows:
- Criteo campaigns by CAC: retargeting pricing page -> $1,240 CAC, retargeting features page -> $890 CAC
- Assist attribution: Criteo frequently appears as an assist touch (neither first nor last) in the customer journey
- Funnel: click -> registration -> qualified lead -> closed deal for each campaign
- Real ROAS: revenue from closed deals / Criteo spend
Real-World Case Study
A B2B SaaS company spending $8,000/month on Criteo retargeting. The Criteo Dashboard showed a ROAS of 4.2x (based on on-site conversion attribution). After integrating Prooflytics it turned out that of 340 form fills, only 18 became paying customers. Real ROAS: 1.8x. The team reallocated budget - increased targeting on the High Intent segment (pricing page visits) and reduced spend on broad retargeting.
Who This Is For
B2B SaaS companies spending at least $5,000/month on Criteo retargeting with a long sales cycle (30+ days). Especially relevant when weeks pass between a retargeting click and a closed deal - Criteo’s standard 30-day attribution window does not capture those conversions.
A similar approach is described for Prooflytics + Google Ads and Prooflytics + Meta Ads.
Frequently Asked Questions
Is OneTag required if you are only using the Events API?
OneTag (the browser script) is required for building retargeting audiences - without it, Criteo has no way to know who to retarget. The Events API is used only for conversions (post-click). Both are needed: OneTag for audience building, Events API for server-side conversion attribution (bypasses ad blockers).
How does attribution work if a customer uses multiple devices?
Criteo Universal Match uses an email hash for cross-device attribution. If you pass the email when sending a conversion, Criteo can match that conversion to a click that happened on a different device. This is exactly why Prooflytics collects the email at registration and passes it to the Events API at conversion time.
Does the Criteo Events API have rate limits?
Yes: 1,000 events per request, 100 requests per minute. For most B2B SaaS companies closing dozens of deals per month, this is not a concern. At higher volumes, batch your events.
Summary
Prooflytics + Criteo - real CAC from retargeting:
- JS: capture
cto_pldcookie/parameter + email at registration -> Prooflytics API - On closed_won in CRM: Criteo Events API with email-based attribution
- OAuth 2.0 Client Credentials for Criteo API authorization
- Dashboard: campaign CAC = Criteo spend / closed deals, real ROAS
If you want to see the true ROI of your retargeting campaigns all the way to closed deals - reach out to the Prooflytics team.