Troubleshooting Overview
This guide helps you diagnose and resolve common issues with Snapchat Ads tracking, from pixel installation problems to attribution discrepancies.
Snap Pixel Issues
Pixel Not Loading
Symptoms
- Snap Pixel Helper shows no pixel detected
- No network requests to sc-static.net
- Events not appearing in Events Manager
Diagnostic Steps
- Check Browser Console
// Open DevTools Console (F12)
// Look for JavaScript errors
// Common errors:
// - snaptr is not defined
// - Failed to load resource: sc-static.net
// - Content Security Policy violations
- Verify Pixel Code Installation
// In browser console, check if snaptr is loaded:
typeof snaptr
// Should return: "function"
// Check if pixel initialized:
snaptr.queue
// Should return an array
- Check Network Tab
- Open DevTools > Network tab
- Filter by "sc-static.net"
- Verify
scevent.min.jsloads successfully - Check for blocked requests
Common Causes & Solutions
| Issue | Cause | Solution |
|---|---|---|
| Script blocked | Ad blocker or browser extension | Test in incognito mode without extensions |
| CSP violation | Content Security Policy blocks external scripts | Add sc-static.net to CSP allowlist |
| Incorrect pixel ID | Wrong pixel ID in code | Verify pixel ID in Ads Manager > Events Manager |
Script not in <head> |
Pixel code placed in wrong location | Move to <head> section before closing tag |
| Syntax error | Malformed JavaScript | Copy fresh code from Events Manager |
Solution: Fix Pixel Loading
<!-- Correct placement: Inside <head> tag -->
<head>
<meta charset="UTF-8">
<title>Page Title</title>
<!-- Snap Pixel Code - Place BEFORE closing </head> -->
<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_ACTUAL_PIXEL_ID');
snaptr('track', 'PAGE_VIEW');
</script>
</head>
Events Not Firing
Symptoms
- Pixel loads but specific events don't appear
- Test Events tool shows no events
- Events appear with delay or inconsistently
Diagnostic Steps
Use Snap Pixel Helper
- Install Snap Pixel Helper Chrome Extension
- Visit your website
- Click extension icon
- Verify events fire when expected
Check Event Syntax
// CORRECT: Standard event names
snaptr('track', 'PURCHASE'); // Uppercase
snaptr('track', 'ADD_CART');
snaptr('track', 'VIEW_CONTENT');
// INCORRECT: Wrong case or spelling
snaptr('track', 'purchase'); // lowercase - won't work
snaptr('track', 'CHECKOUT'); // non-standard event name
snaptr('track', 'AddCart'); // wrong format
- Verify Event Parameters
// Check in console before event fires
console.log('Tracking PURCHASE with params:', {
'price': 99.99,
'currency': 'USD',
'transaction_id': 'ORDER_12345'
});
snaptr('track', 'PURCHASE', {
'price': 99.99,
'currency': 'USD',
'transaction_id': 'ORDER_12345'
});
Common Causes & Solutions
| Issue | Cause | Solution |
|---|---|---|
| Event fires before pixel loads | Race condition | Wrap event in pixel ready callback |
| Wrong event name | Typo or non-standard name | Use standard event names (uppercase) |
| Missing parameters | Required params not included | Include price, currency, item_ids |
| Event fires multiple times | Duplicate event calls | Add deduplication logic |
| SPA navigation issues | Events don't fire on route change | Fire PAGE_VIEW on route changes |
Solution: Event Timing
// Wait for pixel to be ready before firing events
snaptr('init', 'YOUR_PIXEL_ID', {}, function() {
// Pixel is loaded and ready
console.log('Snap Pixel ready');
});
// For events triggered by user actions
document.getElementById('checkout-btn').addEventListener('click', function() {
// Ensure snaptr is defined
if (typeof snaptr !== 'undefined') {
snaptr('track', 'START_CHECKOUT', {
'price': cartTotal,
'currency': 'USD'
});
} else {
console.error('Snap Pixel not loaded');
}
});
Advanced Matching Issues
Symptoms
- Low match rates reported
- Events not attributing to users
- Audience sizes smaller than expected
Diagnostic Steps
- Verify Hashing Implementation
// Test your hashing function
function testHashing() {
const testEmail = 'Test@Example.com';
const hashed = hashSHA256(testEmail);
// Should be lowercase, trimmed, then hashed
console.log('Original:', testEmail);
console.log('Hashed:', hashed);
// Verify it matches expected format
// SHA256 should be 64 hex characters
if (hashed.length !== 64) {
console.error('Hash length incorrect:', hashed.length);
}
}
- Check User Data Format
// CORRECT: Properly formatted and hashed
snaptr('init', 'YOUR_PIXEL_ID', {
'user_email': hashSHA256('user@example.com'), // Hashed
'user_phone_number': hashSHA256('+15551234567') // Hashed with country code
});
// INCORRECT: Common mistakes
snaptr('init', 'YOUR_PIXEL_ID', {
'user_email': 'user@example.com', // Not hashed
'user_phone_number': '555-1234' // Missing country code, not hashed
});
Solution: Correct Hashing
// Use CryptoJS or native crypto
function hashSHA256(data) {
if (!data) return '';
// Step 1: Convert to lowercase
data = data.toLowerCase();
// Step 2: Trim whitespace
data = data.trim();
// Step 3: Hash with SHA256
if (typeof CryptoJS !== 'undefined') {
return CryptoJS.SHA256(data).toString();
} else if (typeof crypto !== 'undefined' && crypto.subtle) {
// Modern browsers with Web Crypto API
return crypto.subtle.digest('SHA-256', new TextEncoder().encode(data))
.then(hash => {
return Array.from(new Uint8Array(hash))
.map(b => b.toString(16).padStart(2, '0'))
.join('');
});
}
console.error('No hashing library available');
return '';
}
// Initialize with hashed data
snaptr('init', 'YOUR_PIXEL_ID', {
'user_email': hashSHA256('user@example.com'),
'user_phone_number': hashSHA256('+15551234567')
});
Conversions API Issues
CAPI Events Not Tracking
Symptoms
- Server-side events don't appear in Events Manager
- API returns errors
- Events appear but don't attribute
Diagnostic Steps
- Check API Response
async function debugCAPIEvent(eventData) {
try {
const response = await sendSnapEvent(eventData);
console.log('CAPI Response:', response);
// Check for errors in response
if (response.errors) {
console.error('CAPI Errors:', response.errors);
response.errors.forEach(error => {
console.error(`Error: ${error.message}`);
console.error(`Field: ${error.field}`);
});
}
// Check success
if (response.data && response.data.success) {
console.log('Event sent successfully');
}
return response;
} catch (error) {
console.error('CAPI Request Failed:', error.message);
console.error('Status:', error.response?.status);
console.error('Response:', error.response?.data);
}
}
- Validate Payload Structure
// Correct CAPI payload structure
const validPayload = {
data: [{
event_type: 'PURCHASE', // Required: Standard event name
event_conversion_type: 'WEB', // Required: WEB, MOBILE_APP, OFFLINE
event_tag: 'event_tag', // Required: From Snap Ads Manager
timestamp: Date.now(), // Required: Unix timestamp in milliseconds
hashed_email: hashSHA256(email), // Recommended
hashed_phone_number: hashSHA256(phone), // Recommended
hashed_ip_address: hashSHA256(ipAddress), // Recommended
user_agent: userAgent, // Recommended
uuid_c1: snapClickId, // Recommended: _scid cookie value
price: '99.99', // String format
currency: 'USD', // ISO 4217 currency code
transaction_id: orderId, // For deduplication
item_ids: ['SKU_123'], // Array of strings
page_url: 'https://example.com/confirmation'
}]
};
Common Errors & Solutions
| Error Code | Message | Solution |
|---|---|---|
| 401 | Unauthorized | Verify access token is valid and not expired |
| 400 | Invalid event_type | Use standard event names (PURCHASE, ADD_CART, etc.) |
| 400 | Missing required field | Include event_type, event_conversion_type, event_tag, timestamp |
| 400 | Invalid timestamp | Use milliseconds since epoch (Date.now()) |
| 429 | Rate limit exceeded | Implement exponential backoff retry logic |
| 500 | Internal server error | Retry request, contact Snapchat support if persistent |
Solution: CAPI Error Handling
async function sendSnapEventWithRetry(eventData, maxRetries = 3) {
let lastError;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const payload = {
data: [{
event_type: eventData.eventType,
event_conversion_type: 'WEB',
event_tag: 'event_tag',
timestamp: Date.now(),
hashed_email: eventData.hashedEmail,
hashed_phone_number: eventData.hashedPhone,
user_agent: eventData.userAgent,
hashed_ip_address: eventData.hashedIp,
uuid_c1: eventData.snapClickId,
price: String(eventData.price),
currency: eventData.currency,
transaction_id: eventData.transactionId,
item_ids: eventData.itemIds
}]
};
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 // 5 second timeout
}
);
// Success
console.log(`CAPI event sent successfully on attempt ${attempt}`);
return response.data;
} catch (error) {
lastError = error;
// Don't retry on authentication errors
if (error.response?.status === 401 || error.response?.status === 403) {
console.error('Authentication error, not retrying');
throw error;
}
// Don't retry on bad request (fix data instead)
if (error.response?.status === 400) {
console.error('Bad request:', error.response.data);
throw error;
}
// Retry on server errors or rate limits
if (attempt < maxRetries) {
const backoffMs = Math.pow(2, attempt) * 1000; // Exponential backoff
console.log(`Retrying in ${backoffMs}ms (attempt ${attempt + 1}/${maxRetries})`);
await new Promise(resolve => setTimeout(resolve, backoffMs));
}
}
}
console.error(`Failed after ${maxRetries} attempts`);
throw lastError;
}
Event Deduplication Issues
Symptoms
- Events counted twice (pixel + CAPI)
- Purchase revenue doubled
- Inflated conversion counts
Diagnostic Steps
- Verify Deduplication IDs Match
// Browser-side (Pixel)
const dedupId = `ORDER_${orderId}_${timestamp}`;
console.log('Browser dedup ID:', dedupId);
snaptr('track', 'PURCHASE', {
'transaction_id': orderId,
'client_dedup_id': dedupId, // Critical for deduplication
'price': 99.99,
'currency': 'USD'
});
// Server-side (CAPI) - Must use EXACT same ID
console.log('Server dedup ID:', dedupId);
const payload = {
data: [{
client_dedup_id: dedupId, // MUST MATCH browser exactly
event_type: 'PURCHASE',
// ... rest of data
}]
};
- Check Event Manager for Duplicates
- Go to Events Manager > Test Events
- Send test event from both pixel and CAPI
- Verify only one event appears
- Check event details show both sources
Solution: Implement Deduplication
// Generate consistent deduplication ID
function generateDedupId(transactionId) {
// Use transaction ID + timestamp
// This must be generated ONCE and shared between browser and server
const timestamp = Date.now();
return `${transactionId}_${timestamp}`;
}
// On client-side (when order is placed)
const dedupId = generateDedupId(orderId);
// Store in cookie or send to server
document.cookie = `snap_dedup_id=${dedupId}; path=/; max-age=300`; // 5 minutes
// Track with pixel
snaptr('track', 'PURCHASE', {
'transaction_id': orderId,
'client_dedup_id': dedupId,
'price': orderTotal,
'currency': 'USD'
});
// On server-side (when processing order)
// Retrieve dedup ID from cookie or request
const dedupId = req.cookies.snap_dedup_id;
// Send to CAPI with same dedup ID
await sendSnapEvent({
client_dedup_id: dedupId, // Same ID as browser
event_type: 'PURCHASE',
transaction_id: orderId,
// ... rest of data
});
Attribution Issues
Conversions Not Attributing to Campaigns
Symptoms
- Events appear in Events Manager
- No conversions in campaign reporting
- Attribution window issues
Diagnostic Steps
Verify Event Configuration
- Go to Events Manager
- Select your pixel
- Click "Set Up Web Events"
- Verify PURCHASE is configured as a conversion event
Check Attribution Windows
- Ads Manager > Settings > Attribution
- Default: 1-day view, 28-day click
- Verify windows align with your business
Verify User Journey
// Track the user journey
console.log('User clicked ad?', document.cookie.includes('_scid'));
console.log('Snap click ID:', getCookie('_scid'));
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
}
Common Causes & Solutions
| Issue | Cause | Solution |
|---|---|---|
| Event not set as conversion | Event not configured in Events Manager | Configure event as conversion in Events Manager |
| Wrong attribution window | Event outside attribution window | Verify user clicked ad within attribution window |
| Missing click ID | _scid cookie not set or expired | Verify pixel loads immediately on landing |
| Cross-domain tracking issue | Cookie lost when changing domains | Implement cross-domain tracking |
| Conversion delay | Purchase happens days after click | Extend attribution window if appropriate |
Solution: Verify Attribution Setup
// On landing page (immediately after ad click)
// Verify Snap click ID is captured
(function checkAttribution() {
const scid = getCookie('_scid');
if (scid) {
console.log('Attribution successful - Click ID:', scid);
// Store for later use (optional)
sessionStorage.setItem('snap_click_id', scid);
} else {
console.warn('No Snap click ID found - event may not attribute');
}
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
}
})();
// On conversion page - include click ID in CAPI
const snapClickId = getCookie('_scid') || sessionStorage.getItem('snap_click_id');
await sendSnapEvent({
uuid_c1: snapClickId, // Critical for attribution
event_type: 'PURCHASE',
// ... rest of data
});
Revenue Discrepancies
Symptoms
- Revenue in Snapchat doesn't match actual sales
- Conversion values incorrect
- Currency conversion issues
Diagnostic Steps
- Verify Price Format
// Check what's being sent
const orderTotal = 99.99;
// CORRECT: Number or string
snaptr('track', 'PURCHASE', {
'price': 99.99, // Number
'currency': 'USD'
});
// Or
snaptr('track', 'PURCHASE', {
'price': '99.99', // String
'currency': 'USD'
});
// INCORRECT: Wrong format
snaptr('track', 'PURCHASE', {
'price': '$99.99', // Don't include currency symbol
'currency': 'USD'
});
- Check Currency Codes
// Use ISO 4217 currency codes
const validCurrencies = ['USD', 'EUR', 'GBP', 'CAD', 'AUD', 'JPY'];
function validateCurrency(currency) {
if (!validCurrencies.includes(currency)) {
console.error('Invalid currency code:', currency);
return false;
}
return true;
}
- Audit Event Parameters
// Log all purchase events for debugging
const originalTrack = window.snaptr;
window.snaptr = function(method, event, params) {
if (method === 'track' && event === 'PURCHASE') {
console.log('PURCHASE Event Debug:', {
price: params.price,
currency: params.currency,
transaction_id: params.transaction_id,
timestamp: new Date().toISOString()
});
// Verify price is numeric
if (isNaN(parseFloat(params.price))) {
console.error('Price is not a number:', params.price);
}
}
return originalTrack.apply(this, arguments);
};
Solution: Correct Revenue Tracking
// Calculate order total correctly
function trackPurchase(order) {
// Ensure numeric value
const orderTotal = parseFloat(order.total);
if (isNaN(orderTotal) || orderTotal <= 0) {
console.error('Invalid order total:', order.total);
return;
}
// Format to 2 decimal places
const formattedTotal = orderTotal.toFixed(2);
console.log('Tracking purchase:', {
total: formattedTotal,
currency: order.currency,
orderId: order.id
});
snaptr('track', 'PURCHASE', {
'price': formattedTotal, // Always use formatted number
'currency': order.currency.toUpperCase(), // Uppercase currency code
'transaction_id': order.id,
'number_items': order.items.length,
'item_ids': order.items.map(item => item.sku)
});
}
Cross-Domain Tracking Issues
Symptoms
- Users lost when moving between domains
- Conversions not attributing across domains
- Multiple sessions for same user
Diagnostic Steps
- Check Cookie Domain Settings
// Verify cookie domain configuration
snaptr('init', 'YOUR_PIXEL_ID', {
'cookie_domain': '.example.com' // Share across subdomains
});
// Check if cookie is accessible
console.log('Cookies:', document.cookie);
console.log('_scid cookie:', getCookie('_scid'));
- Verify Pixel on All Domains
- Visit each domain in your funnel
- Check Pixel Helper on each page
- Verify same pixel ID used everywhere
Solution: Configure Cross-Domain Tracking
See Cross-Domain Tracking Guide for detailed implementation.
Testing & Validation Tools
Snap Pixel Helper
Chrome Extension for debugging pixel implementation:
- Install from Chrome Web Store
- Click extension icon on any page
- Shows: Pixel loaded, events fired, parameters sent
- Color indicators: Green (good), Yellow (warning), Red (error)
Test Events Tool
Events Manager Feature for testing before launch:
- Go to Events Manager
- Select your pixel
- Click "Test Events" tab
- Enter your website URL
- Browse your site
- Verify events appear in real-time
Browser DevTools
Console Debugging:
// Check if pixel is loaded
typeof snaptr // Should return 'function'
// Enable debug mode
snaptr('debug', true);
// Check pixel queue
snaptr.queue
// Monitor network requests
// DevTools > Network > Filter: 'sc-static.net'
Network Tab Debugging:
- Open DevTools (F12)
- Go to Network tab
- Filter by "tr.snapchat.com"
- Trigger conversion event
- Click request to see:
- Request payload
- Response status
- Headers
Manual Testing Checklist
## Pre-Launch Testing Checklist
### Pixel Loading
- [ ] Pixel loads on all page types
- [ ] No JavaScript console errors
- [ ] Network requests succeed
- [ ] Pixel Helper shows green checkmark
### Event Firing
- [ ] PAGE_VIEW fires on all pages
- [ ] VIEW_CONTENT fires on product pages
- [ ] ADD_CART fires when adding to cart
- [ ] START_CHECKOUT fires at checkout
- [ ] PURCHASE fires on confirmation page
### Event Parameters
- [ ] All events include required parameters
- [ ] Price values are numeric
- [ ] Currency codes are valid (ISO 4217)
- [ ] Transaction IDs are unique
- [ ] Item IDs match product catalog
### Advanced Matching
- [ ] Email hashing implemented correctly
- [ ] Phone number hashing implemented
- [ ] Hash format verified (64 char hex)
### Attribution
- [ ] _scid cookie set on ad click
- [ ] Cookie persists through checkout
- [ ] Events appear in Test Events tool
- [ ] Events appear in Events Manager
### CAPI (if implemented)
- [ ] Server events send successfully
- [ ] API returns 200 status
- [ ] Deduplication configured
- [ ] Events appear in Events Manager
### Cross-Browser Testing
- [ ] Chrome (desktop & mobile)
- [ ] Safari (desktop & mobile/iOS)
- [ ] Firefox
- [ ] Edge
### Privacy & Compliance
- [ ] Consent management implemented
- [ ] PII properly hashed
- [ ] Privacy policy updated
Common Error Messages
| Error | Meaning | Solution |
|---|---|---|
| "snaptr is not defined" | Pixel script not loaded | Verify pixel code in <head>, check for JS errors |
| "Invalid pixel ID" | Wrong or malformed pixel ID | Copy correct ID from Events Manager |
| "Event type not recognized" | Non-standard event name | Use standard events: PURCHASE, ADD_CART, etc. |
| "Missing required parameter" | Event missing required field | Include price, currency for commerce events |
| "Unauthorized" (CAPI) | Invalid or expired access token | Generate new access token in Business Manager |
| "Rate limit exceeded" | Too many API requests | Implement rate limiting, exponential backoff |
Getting Additional Help
Snapchat Support Resources
- Business Help Center: businesshelp.snapchat.com
- Marketing API Docs: marketingapi.snapchat.com/docs
- Developer Portal: developers.snap.com
- Snap Pixel Helper: Chrome extension for debugging
- Support Chat: Available in Ads Manager (bottom right)
Community Resources
- Snapchat Ads Community Forum
- Stack Overflow - Tag: [snapchat-ads]
- Developer Discord servers
- Agency partner support
When to Contact Support
Contact Snapchat Support if:
- Persistent pixel loading issues after troubleshooting
- API errors not documented
- Attribution discrepancies after verification
- Events Manager showing incorrect data
- Account-level issues or billing questions