Tracking Methods Overview
Snapchat offers two primary methods for tracking conversions:
- Client-Side: Snap Pixel (JavaScript in browser)
- Server-Side: Conversions API (CAPI - Server to Snapchat)
Comparison Table
| Feature | Client-Side (Pixel) | Server-Side (CAPI) |
|---|---|---|
| Implementation | JavaScript snippet | Server API calls |
| Data Source | Browser | Your server |
| Ad Blockers | Can be blocked | Immune |
| Privacy Restrictions | Affected by browser policies | Not affected |
| Setup Complexity | Simple | Moderate to complex |
| Data Quality | Depends on browser | Full control |
| Real-time | Yes | Yes |
| Attribution | Browser cookies | UUID matching |
| PII Handling | Client-side hashing | Server-side hashing |
| Reliability | ~70-85% | ~95-100% |
Client-Side Tracking (Snap Pixel)
How It Works
User clicks ad → Lands on website → Pixel loads in browser
↓
Pixel sets cookie (_scid)
↓
User takes action (purchase)
↓
Pixel sends event to Snapchat
↓
Snapchat attributes conversion
Advantages
1. Easy Implementation
<!-- Simple JavaScript snippet -->
<script type='text/javascript'>
(function(e,t,n){if(e.snaptr)return;var a=e.snaptr=function()
{a.handleRequest?a.handleRequest.apply(a,arguments):a.queue.push(arguments)};
a.queue=[];var s='script';var r=t.createElement(s);r.async=!0;
r.src=n;var u=t.getElementsByTagName(s)[0];
u.parentNode.insertBefore(r,u);})(window,document,
'https://sc-static.net/scevent.min.js');
snaptr('init', 'YOUR_PIXEL_ID');
snaptr('track', 'PAGE_VIEW');
</script>
2. Automatic Cookie Management
- Snapchat handles cookie creation and management
- Click ID automatically captured
- Attribution window automatically applied
3. Real-Time User Behavior
// Capture micro-interactions
snaptr('track', 'VIEW_CONTENT', { /* ... */ });
snaptr('track', 'ADD_CART', { /* ... */ });
snaptr('track', 'START_CHECKOUT', { /* ... */ });
4. No Server Infrastructure Required
Disadvantages
1. Ad Blocker Impact
// Ad blockers prevent pixel from loading
// Result: No tracking, lost conversions
Impact: ~15-30% of users may block pixels
2. Browser Restrictions
- Safari ITP limits cookie duration
- Firefox Enhanced Tracking Protection
- Cookie consent requirements (GDPR)
3. Limited Data Access
// Can only access browser-visible data
// Cannot access:
// - Server-side calculations
// - Database information
// - Offline conversions
4. Client-Side Vulnerabilities
Best Use Cases
- Simple websites and blogs
- Lead generation forms
- Content sites
- Fast implementation needed
- No development resources available
Server-Side Tracking (Conversions API)
How It Works
User clicks ad → Lands on website → Pixel sets cookie
↓
User completes purchase
↓
Your server processes order
↓
Server sends event to Snapchat API
↓
Snapchat attributes conversion
Implementation
Node.js Example
const axios = require('axios');
const crypto = require('crypto');
// Hash function for PII
function hashSHA256(data) {
return crypto.createHash('sha256')
.update(data.toLowerCase().trim())
.digest('hex');
}
// Send conversion event
async function sendConversionEvent(orderData) {
const payload = {
data: [{
event_type: 'PURCHASE',
event_conversion_type: 'WEB',
event_tag: 'event_tag',
timestamp: Date.now(),
// User identification
hashed_email: hashSHA256(orderData.customerEmail),
hashed_phone_number: hashSHA256(orderData.customerPhone),
hashed_ip_address: hashSHA256(orderData.ipAddress),
user_agent: orderData.userAgent,
uuid_c1: orderData.snapClickId, // From _scid cookie
// Event data
price: orderData.total.toString(),
currency: orderData.currency,
transaction_id: orderData.orderId,
item_ids: orderData.items.map(item => item.sku),
number_items: orderData.items.length.toString(),
// Deduplication
client_dedup_id: `${orderData.orderId}_${Date.now()}`,
// Additional context
page_url: orderData.pageUrl,
referrer_url: orderData.referrer
}]
};
try {
const response = await axios.post(
'https://tr.snapchat.com/v2/conversion',
payload,
{
headers: {
'Authorization': `Bearer ${process.env.SNAP_ACCESS_TOKEN}`,
'Content-Type': 'application/json'
},
timeout: 5000
}
);
console.log('CAPI Success:', response.data);
return response.data;
} catch (error) {
console.error('CAPI Error:', error.response?.data || error.message);
throw error;
}
}
// Usage in order processing
app.post('/api/orders', async (req, res) => {
// Process order
const order = await createOrder(req.body);
// Send to Snapchat CAPI
await sendConversionEvent({
customerEmail: order.email,
customerPhone: order.phone,
ipAddress: req.ip,
userAgent: req.headers['user-agent'],
snapClickId: req.cookies._scid,
total: order.total,
currency: 'USD',
orderId: order.id,
items: order.items,
pageUrl: `${req.protocol}://${req.get('host')}/confirmation`,
referrer: req.headers.referer
});
res.json({ success: true, orderId: order.id });
});
Python Example
import requests
import hashlib
import time
import os
def hash_sha256(data):
"""Hash PII with SHA256"""
if not data:
return ''
return hashlib.sha256(data.lower().strip().encode()).hexdigest()
def send_conversion_event(order_data):
"""Send conversion event to Snapchat CAPI"""
url = 'https://tr.snapchat.com/v2/conversion'
headers = {
'Authorization': f"Bearer {os.environ['SNAP_ACCESS_TOKEN']}",
'Content-Type': 'application/json'
}
payload = {
'data': [{
'event_type': 'PURCHASE',
'event_conversion_type': 'WEB',
'event_tag': 'event_tag',
'timestamp': int(time.time() * 1000),
# User identification
'hashed_email': hash_sha256(order_data['customer_email']),
'hashed_phone_number': hash_sha256(order_data['customer_phone']),
'hashed_ip_address': hash_sha256(order_data['ip_address']),
'user_agent': order_data['user_agent'],
'uuid_c1': order_data.get('snap_click_id', ''),
# Event data
'price': str(order_data['total']),
'currency': order_data['currency'],
'transaction_id': order_data['order_id'],
'item_ids': [item['sku'] for item in order_data['items']],
'number_items': str(len(order_data['items'])),
# Deduplication
'client_dedup_id': f"{order_data['order_id']}_{int(time.time())}",
# Additional context
'page_url': order_data['page_url']
}]
}
try:
response = requests.post(url, json=payload, headers=headers, timeout=5)
response.raise_for_status()
print(f"CAPI Success: {response.json()}")
return response.json()
except requests.exceptions.RequestException as e:
print(f"CAPI Error: {e}")
raise
# Usage
def process_order(order_data):
# ... process order logic ...
# Send to Snapchat CAPI
send_conversion_event({
'customer_email': order_data['email'],
'customer_phone': order_data['phone'],
'ip_address': request.remote_addr,
'user_agent': request.headers.get('User-Agent'),
'snap_click_id': request.cookies.get('_scid'),
'total': order_data['total'],
'currency': 'USD',
'order_id': order_data['id'],
'items': order_data['items'],
'page_url': f"{request.scheme}://{request.host}/confirmation"
})
Advantages
1. Immune to Ad Blockers
// Server-side: Ad blockers have no effect
// Direct server-to-Snapchat communication
2. Complete Data Access
// Access to full order data, customer data, inventory, etc.
await sendConversionEvent({
customerLifetimeValue: 5000,
customerTier: 'premium',
inventoryData: productStock,
marginData: orderMargin
// Any server-side data
});
3. Enhanced Privacy Control
// Hash PII server-side (more secure)
// Control exactly what data is sent
// No client-side data exposure
4. Higher Reliability
- Not affected by JavaScript errors
- Not affected by page load issues
- Guaranteed execution in server environment
5. Offline Conversions
// Track phone orders, in-store purchases, etc.
await sendConversionEvent({
event_type: 'PURCHASE',
event_conversion_type: 'OFFLINE',
// ... offline conversion data
});
Disadvantages
1. More Complex Setup
- Requires server-side development
- API authentication setup
- Error handling and logging
- Infrastructure for API calls
2. Attribution Challenges
// Must manually capture and pass Snap click ID
const snapClickId = req.cookies._scid; // May be missing
if (!snapClickId) {
console.warn('No Snap click ID - attribution may fail');
}
3. Missing Behavioral Data
// Cannot track:
// - Scroll depth
// - Time on page
// - Click patterns
// - Video watch percentage
4. Development Resources Required
- Backend developers needed
- Testing and QA
- Ongoing maintenance
- Monitoring and alerting
Best Use Cases
- E-commerce with server-side processing
- High-value conversions (enterprise SaaS)
- Subscription businesses
- Offline conversion tracking
- Markets with high ad blocker usage
- GDPR/privacy-focused implementations
Hybrid Approach (Recommended)
Why Use Both?
Combining Pixel and CAPI provides:
- Maximum Coverage - Pixel catches what CAPI misses, and vice versa
- Redundancy - Backup if one method fails
- Better Attribution - More data points for Snapchat
- Behavioral + Conversion - Pixel for micro-conversions, CAPI for macro
Implementation Architecture
User Journey:
1. Click Snapchat ad → Pixel sets cookie (_scid)
2. Browse products → Pixel tracks VIEW_CONTENT, ADD_CART
3. Start checkout → Pixel tracks START_CHECKOUT
4. Complete purchase → BOTH Pixel and CAPI track PURCHASE
↓
Event Deduplication prevents double-counting
Hybrid Implementation
Client-Side (Pixel)
// In browser - track all events including purchase
const eventId = `ORDER_${orderId}_${Date.now()}`;
snaptr('track', 'PURCHASE', {
'price': orderTotal,
'currency': 'USD',
'transaction_id': orderId,
'client_dedup_id': eventId, // Deduplication key
'item_ids': itemSkus
});
// Also send eventId to server for CAPI
fetch('/api/track-purchase', {
method: 'POST',
body: JSON.stringify({
orderId: orderId,
eventId: eventId // Same ID for deduplication
})
});
Server-Side (CAPI)
// On server - track same purchase with same deduplication ID
app.post('/api/track-purchase', async (req, res) => {
const { orderId, eventId } = req.body;
const order = await getOrder(orderId);
await sendConversionEvent({
client_dedup_id: eventId, // MUST match client-side
event_type: 'PURCHASE',
transaction_id: orderId,
price: order.total.toString(),
currency: 'USD',
// ... other data
});
res.json({ success: true });
});
Event Deduplication
Critical: Use same client_dedup_id in both Pixel and CAPI to prevent double-counting.
// Generate consistent deduplication ID
function generateDedupId(orderId) {
const timestamp = Date.now();
return `ORDER_${orderId}_${timestamp}`;
}
// Client-side
const dedupId = generateDedupId(orderId);
document.cookie = `snap_dedup_id=${dedupId}; max-age=300`; // 5 minutes
snaptr('track', 'PURCHASE', {
'client_dedup_id': dedupId,
// ... event data
});
// Server-side
const dedupId = req.cookies.snap_dedup_id;
await sendConversionEvent({
client_dedup_id: dedupId, // Same ID
// ... event data
});
Decision Matrix
Choose Client-Side Only If:
- Simple website (blog, portfolio, landing page)
- No backend development resources
- Quick implementation needed
- Budget constraints
- Low ad blocker usage in target audience
Choose Server-Side Only If:
- High ad blocker usage (>30%)
- Privacy-first market (EU)
- Offline conversions needed
- Enterprise security requirements
- Server infrastructure already exists
Choose Hybrid If:
- E-commerce business
- High conversion value
- Need maximum accuracy
- Have development resources
- Want behavioral tracking + conversion tracking
- Operating in multiple markets
Performance Comparison
Data Quality Score
Typical event quality scores by implementation:
| Method | Event Quality Score | Coverage |
|---|---|---|
| Pixel Only | 6-7/10 | 70-85% |
| CAPI Only | 8-9/10 | 95-100% |
| Hybrid | 9-10/10 | 98-100% |
Attribution Accuracy
| Method | Attribution Accuracy |
|---|---|
| Pixel Only | ~75% |
| CAPI Only | ~85% |
| Hybrid | ~95% |
Migration Guide
From Pixel to Hybrid
Phase 1: Keep existing Pixel (Week 1)
- Document current pixel setup
- Identify conversion events
- Test pixel still works
Phase 2: Implement CAPI (Week 2-3)
- Set up server infrastructure
- Implement CAPI for PURCHASE event
- Add deduplication logic
- Test in development
Phase 3: Deploy and Monitor (Week 4)
- Deploy CAPI to production
- Monitor Events Manager for duplicates
- Verify deduplication working
- Compare conversion counts
Phase 4: Expand (Week 5+)
- Add more events to CAPI
- Implement offline conversions
- Optimize based on Event Quality Score
Monitoring and Validation
Check Events Manager
## Hybrid Implementation Checklist
### Events Manager
- [ ] Events appear from both sources (Pixel & CAPI)
- [ ] Event details show "Web (Direct & Server)"
- [ ] No duplicate purchases (deduplication working)
- [ ] Event Quality Score improved
### Client-Side
- [ ] Pixel loads successfully
- [ ] All micro-conversions tracked (VIEW_CONTENT, ADD_CART)
- [ ] Deduplication ID generated
### Server-Side
- [ ] CAPI events send successfully
- [ ] API returns success (200 status)
- [ ] Deduplication ID matches client-side
- [ ] Error handling in place
Debug Both Methods
// Client-side debug
snaptr('debug', true); // Enable console logging
// Server-side debug
console.log('CAPI Request:', {
event_type: 'PURCHASE',
client_dedup_id: dedupId,
transaction_id: orderId
});
console.log('CAPI Response:', response.data);
Best Practices
- Always use deduplication when implementing hybrid
- Hash PII server-side when possible (more secure)
- Monitor event quality in Events Manager
- Test thoroughly before production deployment
- Implement error handling for CAPI calls
- Log failed events for retry or analysis
- Keep pixel as backup even with CAPI
Cost Considerations
| Aspect | Pixel | CAPI | Hybrid |
|---|---|---|---|
| Implementation Time | 1-2 days | 1-2 weeks | 2-3 weeks |
| Developer Resources | Junior | Senior | Senior |
| Infrastructure Costs | $0 | $10-50/mo | $10-50/mo |
| Maintenance | Low | Medium | Medium |
| Total Value | Medium | High | Highest |
Next Steps
- Assess your needs using the decision matrix
- Start with Pixel if unsure (can add CAPI later)
- Plan CAPI implementation if needed
- Implement deduplication from the start
- Monitor and optimize using Events Manager