Lead Tracking (Signup)
Track referred signups with the browser helper or the server-side lead API
Lead tracking connects a signup to the affiliate click that drove it — turning anonymous referral traffic into an identified customer record.
What Lead Tracking Does
When signup tracking succeeds, Affitor:
- links the signup to the tracked click/customer relationship
- stores your internal customer identifier for later payment attribution
- advances the customer journey from click → lead
Use the same customer identifier across all three contexts:
| Context | Field |
|---|---|
| Browser helper | customerKey |
| Lead API | customer_key |
| Stripe metadata later | affitor_customer_key |
Prerequisites
Before tracking a signup:
- the visitor arrived through an affiliate-tracked flow
- the tracker created a click/customer relationship first
- your signup flow has a stable internal user/customer ID to pass to Affitor
A tracked click means the browser already has affitor_click_id from the pageview/click step.
Option A — Browser-side signup()
Use this when signup completes in the browser and the tracker script is loaded on the page.
Basic example
if (window.affitor) {
await window.affitor.signup('user_123', 'user@example.com');
} else {
window.affitorQueue = window.affitorQueue || [];
window.affitorQueue.push(['signup', 'user_123', 'user@example.com']);
}What the arguments mean
| Argument | Required | Meaning |
|---|---|---|
customerKey | Yes (recommended for all real integrations) | your internal user/customer ID |
email | Recommended | customer email; used for hashed/masked attribution support |
The customerKey you pass here should be the same identifier you later use as:
customer_keyin the tracking APIaffitor_customer_keyin Stripe metadata
Example inside a signup flow
document.getElementById('signup-form').addEventListener('submit', async function(e) {
e.preventDefault();
const email = document.getElementById('email').value;
// Your own signup logic first
const result = await createAccount(email);
if (result.success) {
if (window.affitor) {
await window.affitor.signup(result.userId, email);
} else {
window.affitorQueue = window.affitorQueue || [];
window.affitorQueue.push(['signup', result.userId, email]);
}
}
});When to use browser-side signup
- your frontend knows when signup succeeds
- the tracker is installed on the page
- you want the simplest supported implementation
Option B — Server-side Lead API
Use this when account creation happens on your backend, or when you want your server to send the lead event.
Endpoint
POST https://api.affitor.com/api/v1/track/lead
Authorization: Bearer YOUR_PROGRAM_API_KEY
Content-Type: application/jsonRequest body
{
"click_id": "cust_42_1234567890",
"customer_key": "usr_abc123",
"email": "user@example.com"
}Rules
Outside test mode, provide at least one of click_id or customer_key. Send both whenever possible for reliable downstream payment attribution.
Response
{
"success": true,
"message": "Lead tracked successfully"
}Node.js example
app.post('/signup', async (req, res) => {
const { email, password } = req.body;
const newUser = await createUser({ email, password });
const clickId = req.cookies.affitor_click_id;
await fetch('https://api.affitor.com/api/v1/track/lead', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.AFFITOR_API_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
click_id: clickId,
customer_key: newUser.id,
email: newUser.email,
}),
});
res.json({ success: true });
});Python example
requests.post(
'https://api.affitor.com/api/v1/track/lead',
headers={
'Authorization': f'Bearer {AFFITOR_API_TOKEN}',
'Content-Type': 'application/json',
},
json={
'click_id': request.cookies.get('affitor_click_id'),
'customer_key': str(new_user.id),
'email': new_user.email,
},
)Browser Mode vs Server Mode
| Mode | Best for | Auth |
|---|---|---|
signup(customerKey, email) | frontend/browser signup flows | no Bearer token in your integration |
POST /api/v1/track/lead | backend-driven signup flows | Bearer program API key recommended |
Both modes must identify the same customer with the same internal ID.
Test Mode
Create a test lead event to verify your integration without affecting production attribution.
curl -X POST https://api.affitor.com/api/v1/track/lead \
-H "Content-Type: application/json" \
-d '{
"click_id": "test_lead_001",
"customer_key": "test_customer",
"additional_data": {
"test_mode": true,
"program_id": "YOUR_PROGRAM_ID"
}
}'Test mode behavior
- creates a test lead event marked
is_test: true - does not create a real production lead/customer transition
- verifiable through dashboard/test-event tooling
Test mode response
{
"success": true,
"message": "Test lead event tracked successfully",
"data": {
"eventId": 456,
"programId": 1,
"test_mode": true
}
}Common Failure Modes
Lead not attributed
Check that:
- the visitor came through a tracked affiliate click
customerKey/customer_keymatches your real internal user IDaffitor_click_idwas available when expected- you are not testing only in debug mode
Wrong identifier used later in payments
Mismatched identifiers are the most common cause of broken attribution. The same internal ID must be used across:
signup(customerKey, email)customer_keyin server-side tracking callsaffitor_customer_keyin Stripe metadata
Duplicate signup tracking
To prevent duplicates:
- call signup tracking only after account creation succeeds
- guard against duplicate frontend submissions
- deduplicate your signup flow before retrying tracking calls
What to Do Next
Once lead tracking is working, set up sale tracking: