Tracking Approaches Overview
TikTok offers two primary methods for sending conversion data: browser-based Pixel (client-side) and server-based Events API (server-side).
| Aspect | Client-Side (Pixel) | Server-Side (Events API) |
|---|---|---|
| Implementation | JavaScript in browser | HTTP API from server |
| Ad blockers | Can be blocked | Not affected |
| Data accuracy | Dependent on browser | More reliable |
| User privacy | Limited control | Full control |
| Setup complexity | Easy | Moderate |
| Real-time | Immediate | Near-immediate |
| Cost | Free | Free (API calls) |
Client-Side Tracking (TikTok Pixel)
What is Client-Side Tracking?
JavaScript code runs in user's browser, capturing events and sending them to TikTok's servers.
How It Works
User clicks ad → Lands on site → Pixel loads → Events fire → Data sent to TikTok
Implementation
<!-- TikTok Pixel (Client-Side) -->
<script>
!function (w, d, t) {
w.TiktokAnalyticsObject=t;var ttq=w[t]=w[t]||[];
// ... pixel code ...
ttq.load('YOUR_PIXEL_ID');
ttq.page();
}(window, document, 'ttq');
</script>
<!-- Event tracking -->
<script>
ttq.track('CompletePayment', {
value: 99.99,
currency: 'USD',
order_id: 'ORDER_12345'
});
</script>
Advantages
Easy Implementation
- Copy/paste JavaScript code
- No backend development required
- Works immediately
- No API credentials needed
Automatic Data Collection
- User agent automatically captured
- IP address automatically included
- Referrer URL tracked
- Browser info included
Real-Time Tracking
- Events fire immediately
- No server dependency
- Instant feedback in browser console
- Works with browser dev tools
Rich Browser Context
- Cookie data available
- Local storage accessible
- DOM access for data extraction
- JavaScript capabilities
Disadvantages
Ad Blocker Vulnerability
- 20-40% of users have ad blockers
- Events completely blocked
- No fallback mechanism
- Data loss
Browser Limitations
- Requires JavaScript enabled
- Cookie restrictions (Safari ITP, Firefox ETP)
- GDPR/CCPA compliance complexity
- Cross-domain challenges
Data Accuracy Issues
- Client-side can be manipulated
- Browser errors can prevent firing
- Network issues can block requests
- Timing issues on slow connections
Privacy Concerns
- Limited control over data sent
- Browser fingerprinting concerns
- Cookie tracking restrictions
- User opt-out complexity
Best Use Cases
- Simple websites without backend infrastructure
- Quick setup when speed matters
- Engagement tracking (page views, clicks)
- Lightweight implementation needs
- Desktop traffic (less ad blocking)
Server-Side Tracking (Events API)
What is Server-Side Tracking?
Your server sends conversion data directly to TikTok's API, bypassing the browser entirely.
How It Works
User action → Server processes → Server calls TikTok API → Data received by TikTok
Implementation
// Node.js example
const axios = require('axios');
const crypto = require('crypto');
async function sendTikTokEvent(eventData) {
const payload = {
pixel_code: process.env.TIKTOK_PIXEL_ID,
event: 'CompletePayment',
event_id: `ORDER_${eventData.orderId}_${Date.now()}`,
timestamp: new Date().toISOString(),
context: {
user_agent: eventData.userAgent,
ip: eventData.ipAddress,
page: {
url: eventData.pageUrl,
referrer: eventData.referrer
},
user: {
email: hashSHA256(eventData.email),
phone_number: hashSHA256(eventData.phone),
external_id: eventData.userId,
ttp: eventData.ttpCookie
}
},
properties: {
value: eventData.value,
currency: eventData.currency,
content_type: 'product',
contents: eventData.items.map(item => ({
content_id: item.sku,
quantity: item.quantity,
price: item.price
}))
}
};
const response = await axios.post(
'https://business-api.tiktok.com/open_api/v1.3/event/track/',
{
event_source: 'web',
event_source_id: process.env.TIKTOK_PIXEL_ID,
data: [payload]
},
{
headers: {
'Access-Token': process.env.TIKTOK_ACCESS_TOKEN,
'Content-Type': 'application/json'
}
}
);
return response.data;
}
function hashSHA256(data) {
return crypto.createHash('sha256')
.update(data.toLowerCase().trim())
.digest('hex');
}
Advantages
Ad Blocker Proof
- Server-to-server communication
- Cannot be blocked by browser extensions
- 100% event delivery (barring server errors)
- No client dependencies
Data Reliability
- Server controls all data
- No browser quirks
- Consistent execution
- Better error handling
Privacy Control
- Choose exactly what to send
- Hash PII before transmission
- Respect user consent server-side
- Full audit trail
Enhanced Attribution
- Access to complete user data
- CRM integration possible
- Offline conversion tracking
- Better match quality
Security
- Sensitive data never exposed to browser
- API keys secured server-side
- No client-side manipulation
- Encrypted transmission
Disadvantages
Implementation Complexity
- Requires backend development
- API authentication setup
- More moving parts
- Testing complexity
Server Dependency
- Relies on your server being up
- Network latency considerations
- API rate limits
- Error handling needed
Missing Browser Context
- No automatic user agent
- Must capture IP address manually
- Referrer must be passed from client
- Cookie access requires bridge
Maintenance
- API version updates
- Access token rotation
- Monitoring required
- Debug complexity
Best Use Cases
- High-value transactions (eCommerce)
- Ad blocker heavy audiences
- B2B conversions (professional audiences)
- Offline conversions (CRM data)
- Privacy-sensitive industries
- Mobile apps with backend
Hybrid Approach (Recommended)
Why Use Both?
Combining client-side Pixel with server-side Events API provides:
- Maximum coverage - Pixel catches what API misses, API catches blocked Pixels
- Better match quality - More data points for attribution
- Redundancy - Backup if one method fails
- Improved accuracy - Cross-validation of data
Hybrid Architecture
User action
├── Browser fires Pixel event (client-side)
└── Server fires Events API call (server-side)
↓
Deduplication via event_id
↓
Single event counted by TikTok
Implementation
Client-Side (Browser):
// Generate unique event ID
const eventId = `ORDER_${orderId}_${Date.now()}`;
// Fire pixel event
ttq.track('CompletePayment', {
value: 199.98,
currency: 'USD',
order_id: 'ORDER_12345',
event_id: eventId // Deduplication key
});
// Send event ID to server
fetch('/api/track-conversion', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
eventId: eventId,
orderId: 'ORDER_12345',
value: 199.98,
email: userEmail,
phone: userPhone,
ttpCookie: getCookie('_ttp'),
userAgent: navigator.userAgent,
url: window.location.href,
referrer: document.referrer
})
});
Server-Side (Node.js):
// Express route
app.post('/api/track-conversion', async (req, res) => {
const {
eventId,
orderId,
value,
email,
phone,
ttpCookie,
userAgent,
url,
referrer
} = req.body;
// Send to TikTok Events API with same event_id
const payload = {
pixel_code: process.env.TIKTOK_PIXEL_ID,
event: 'CompletePayment',
event_id: eventId, // SAME as client-side
timestamp: new Date().toISOString(),
context: {
user_agent: userAgent,
ip: req.ip,
page: {
url: url,
referrer: referrer
},
user: {
email: hashSHA256(email),
phone_number: hashSHA256(phone),
external_id: orderId,
ttp: ttpCookie
}
},
properties: {
value: value,
currency: 'USD',
order_id: orderId
}
};
try {
await axios.post(
'https://business-api.tiktok.com/open_api/v1.3/event/track/',
{
event_source: 'web',
event_source_id: process.env.TIKTOK_PIXEL_ID,
data: [payload]
},
{
headers: {
'Access-Token': process.env.TIKTOK_ACCESS_TOKEN
}
}
);
res.json({ success: true });
} catch (error) {
console.error('TikTok API error:', error);
res.status(500).json({ error: 'Failed to send event' });
}
});
Event Deduplication
TikTok automatically deduplicates events with the same event_id:
// Both events have same event_id
const eventId = 'ORDER_12345_1234567890';
// Client-side
ttq.track('CompletePayment', {
event_id: eventId, // e.g., "ORDER_12345_1234567890"
value: 99.99
});
// Server-side
{
event_id: eventId, // Same ID
event: 'CompletePayment',
properties: { value: 99.99 }
}
// Result: Only 1 conversion counted
Decision Matrix
Choose Client-Side Only If:
- Simple website with no backend
- Low-value conversions (signups, content engagement)
- Desktop-heavy traffic
- Quick implementation needed
- No developer resources
- Testing/proof of concept
Choose Server-Side Only If:
- Ad blocker heavy audience (25%+)
- High-value transactions
- Privacy regulations require it
- Mobile app conversions
- Offline conversion tracking
- CRM integration needed
Choose Hybrid Approach If:
- eCommerce with significant revenue
- Want maximum data coverage
- Have development resources
- Need redundancy
- Want best Event Quality Score
- Mixed traffic (desktop + mobile)
Performance Comparison
| Metric | Client-Side | Server-Side | Hybrid |
|---|---|---|---|
| Event coverage | 60-80% | 95-99% | 99%+ |
| Data accuracy | Good | Excellent | Excellent |
| Attribution quality | Good | Very Good | Excellent |
| Implementation time | 1-2 hours | 1-2 days | 2-3 days |
| Maintenance effort | Low | Medium | Medium |
| Event Quality Score | 6-7 | 7-8 | 8-10 |
Cost Considerations
Client-Side Costs
- Free implementation
- No API calls
- Potential revenue loss from blocked events
Server-Side Costs
- Free API (no per-call charges)
- Development time (setup and maintenance)
- Server resources (minimal)
Hybrid Costs
- Development time (one-time)
- Ongoing maintenance (minimal)
- Best ROI for performance advertisers
Migration Path
From Client-Side to Hybrid
Week 1: Planning
- Audit current pixel implementation
- Identify conversion events
- Plan server architecture
Week 2: Development
- Set up Events API endpoint
- Implement event deduplication
- Add error handling
Week 3: Testing
- Test deduplication
- Verify both methods fire
- Monitor Event Quality Score
Week 4: Launch
- Deploy to production
- Monitor for 7 days
- Compare before/after metrics
Testing Checklist
## Hybrid Implementation Test
### Client-Side
- [ ] Pixel loads on all pages
- [ ] Events fire correctly
- [ ] Event IDs generated properly
- [ ] Data sent to server endpoint
### Server-Side
- [ ] API credentials configured
- [ ] Events received by TikTok
- [ ] Deduplication working
- [ ] Error handling in place
### Integration
- [ ] Same event_id used by both
- [ ] User data properly hashed
- [ ] _ttp cookie captured and sent
- [ ] No duplicate conversions in reporting
### Monitoring
- [ ] Event Quality Score improved
- [ ] Conversion volume consistent
- [ ] Attribution working correctly
- [ ] Alerts configured for failures
Best Practices
General
- Start with client-side for quick wins
- Add server-side for critical events
- Always deduplicate with event_id
- Monitor Event Quality Score
- Test thoroughly before production
Client-Side Best Practices
- Load pixel early in
<head> - Use async loading (built into pixel)
- Handle errors gracefully
- Test across browsers
- Monitor ad blocker rates
Server-Side Best Practices
- Hash all PII before sending
- Include _ttp cookie for matching
- Pass user agent and IP
- Implement retry logic for failures
- Rotate access tokens regularly
- Monitor API errors
- Log all requests for debugging
Hybrid Best Practices
- Use identical event_id on both sides
- Include timestamp in event_id
- Capture browser data client-side
- Send to server via AJAX/fetch
- Fire server event after validation
- Monitor deduplication in reporting
Troubleshooting
Client-Side Issues
| Issue | Solution |
|---|---|
| Pixel not loading | Check for JavaScript errors |
| Events not firing | Verify event syntax |
| Ad blocker interference | Implement server-side backup |
Server-Side Issues
| Issue | Solution |
|---|---|
| API errors | Check access token and format |
| Events not attributing | Verify pixel ID matches |
| Low match quality | Include more user identifiers |
Deduplication Issues
| Issue | Solution |
|---|---|
| Duplicate conversions | Check event_id matches |
| Some events deduplicated incorrectly | Ensure unique event_id per event |
| Deduplication not working | Verify same pixel code on both sides |
Next Steps
- Assess your needs using decision matrix
- Choose implementation approach
- Follow setup guides for chosen method
- Test thoroughly before launch
- Monitor Event Quality Score
- Iterate and improve based on data