Overview
MediaMath supports both client-side (browser-based) and server-side (server-to-server) pixel tracking. Understanding when to use each approach is essential for accurate attribution, privacy compliance, and optimal campaign performance.
Client-Side Tracking
How It Works
- JavaScript pixel loads in user's browser
- Pixel fires directly from browser to MediaMath servers
- Third-party cookies set by MediaMath domain
- User device information captured automatically
- Real-time tracking and attribution
Implementation
<!-- Client-Side MediaMath Pixel -->
<script type="text/javascript">
(function() {
var mtm = document.createElement('script');
mtm.type = 'text/javascript';
mtm.async = true;
mtm.src = 'https://pixel.mathtag.com/event/js?mt_id=ADVERTISER_ID&mt_adid=PIXEL_ID&mt_exem=&mt_excl=&v1=99.99&v2=ORDER_12345&v3=USD&s1=&s2=&s3=';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(mtm, s);
})();
</script>
Advantages
- Easy implementation: Simple script tag deployment
- Automatic user tracking: Browser cookies handle user identification
- Device information: User agent, IP address captured automatically
- Real-time attribution: Immediate data in TerminalOne
- Dynamic retargeting: Product-level data for personalized ads
- No server dependencies: Works without backend infrastructure
Limitations
- Ad blockers: 20-40% of pixels may be blocked
- Third-party cookie restrictions: ITP, ETP limit tracking
- Privacy regulations: GDPR/CCPA compliance required
- Client-side delays: Page load affects pixel firing
- Limited control: Cannot modify data after firing
- Fraud vulnerability: Client-side pixels easier to spoof
Server-Side Tracking
How It Works
- Server makes HTTP request to MediaMath pixel endpoint
- No browser involvement - server-to-server communication
- User identification via first-party data or device ID
- Full control over data sent to MediaMath
- Privacy-friendly implementation
Implementation
Image Pixel Method
import requests
def fire_mediamath_pixel_server(advertiser_id, pixel_id, conversion_data):
"""Fire MediaMath pixel from server"""
url = 'https://pixel.mathtag.com/event/img'
params = {
'mt_id': advertiser_id,
'mt_adid': pixel_id,
'mt_exem': '',
'mt_excl': '',
'v1': conversion_data.get('value', ''),
'v2': conversion_data.get('order_id', ''),
'v3': conversion_data.get('currency', ''),
's1': '',
's2': '',
's3': ''
}
try:
response = requests.get(url, params=params, timeout=5)
if response.status_code == 200:
print(f"✓ MediaMath pixel fired: {conversion_data['order_id']}")
return True
else:
print(f"✗ Pixel error: {response.status_code}")
return False
except Exception as e:
print(f"✗ Failed to fire pixel: {e}")
return False
# Usage
fire_mediamath_pixel_server(
advertiser_id='123456',
pixel_id='789012',
conversion_data={
'value': '99.99',
'order_id': 'ORDER_12345',
'currency': 'USD'
}
)
Node.js Implementation
const axios = require('axios');
async function fireMediaMathPixelServer(advertiserId, pixelId, conversionData) {
const url = 'https://pixel.mathtag.com/event/img';
const params = {
mt_id: advertiserId,
mt_adid: pixelId,
mt_exem: '',
mt_excl: '',
v1: conversionData.value || '',
v2: conversionData.orderId || '',
v3: conversionData.currency || '',
s1: '',
s2: '',
s3: ''
};
try {
const response = await axios.get(url, { params, timeout: 5000 });
if (response.status === 200) {
console.log(`✓ MediaMath pixel fired: ${conversionData.orderId}`);
return true;
}
} catch (error) {
console.error(`✗ Failed to fire pixel:`, error.message);
return false;
}
}
// Usage
fireMediaMathPixelServer('123456', '789012', {
value: '99.99',
orderId: 'ORDER_12345',
currency: 'USD'
});
PHP Implementation
<?php
function fire_mediamath_pixel_server($advertiser_id, $pixel_id, $conversion_data) {
$url = 'https://pixel.mathtag.com/event/img';
$params = [
'mt_id' => $advertiser_id,
'mt_adid' => $pixel_id,
'mt_exem' => '',
'mt_excl' => '',
'v1' => $conversion_data['value'] ?? '',
'v2' => $conversion_data['order_id'] ?? '',
'v3' => $conversion_data['currency'] ?? '',
's1' => '',
's2' => '',
's3' => ''
];
$query_string = http_build_query($params);
$pixel_url = $url . '?' . $query_string;
$context = stream_context_create([
'http' => [
'method' => 'GET',
'timeout' => 5
]
]);
$result = @file_get_contents($pixel_url, false, $context);
if ($result !== false) {
error_log("✓ MediaMath pixel fired: {$conversion_data['order_id']}");
return true;
} else {
error_log("✗ Failed to fire MediaMath pixel");
return false;
}
}
// Usage
fire_mediamath_pixel_server('123456', '789012', [
'value' => '99.99',
'order_id' => 'ORDER_12345',
'currency' => 'USD'
]);
?>
Advantages
- Bypasses ad blockers: Server requests not blocked
- Privacy-friendly: No third-party cookies in browser
- Reliable tracking: Not affected by client-side issues
- Data control: Full control over data sent
- Fraud prevention: Harder to spoof server-side
- Offline conversions: Track phone orders, in-store sales
- Post-processing: Modify conversion data before sending
Limitations
- Implementation complexity: Requires backend development
- User identification: Must handle user ID management
- No automatic device data: Must collect and send manually
- Delayed attribution: Slight delay vs. real-time client-side
- Server dependencies: Requires backend infrastructure
- More moving parts: Increases system complexity
Hybrid Approach (Recommended)
Combine both methods for maximum coverage and reliability:
Implementation Strategy
- Client-side: Primary tracking for real-time attribution
- Server-side: Backup for critical conversions
- Deduplication: Use order ID to prevent double-counting
Hybrid Implementation
// Client-side: Fire pixel immediately
function trackConversionClientSide(orderData) {
var mtm = document.createElement('script');
mtm.type = 'text/javascript';
mtm.async = true;
mtm.src = 'https://pixel.mathtag.com/event/js?' +
'mt_id=ADVERTISER_ID' +
'&mt_adid=PIXEL_ID' +
'&mt_exem=' +
'&mt_excl=' +
'&v1=' + orderData.value +
'&v2=' + orderData.orderId +
'&v3=' + orderData.currency +
'&s1=&s2=&s3=';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(mtm, s);
// Also send to server for backup
sendToServerForBackup(orderData);
}
function sendToServerForBackup(orderData) {
fetch('/api/conversions/backup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
orderId: orderData.orderId,
value: orderData.value,
currency: orderData.currency,
timestamp: Date.now()
})
});
}
# Server-side: Backup pixel firing
from flask import Flask, request
import time
app = Flask(__name__)
@app.route('/api/conversions/backup', methods=['POST'])
def backup_conversion():
data = request.json
# Store in database
db.conversions.insert_one({
'order_id': data['order_id'],
'value': data['value'],
'currency': data['currency'],
'client_timestamp': data['timestamp'],
'server_timestamp': time.time(),
'pixel_fired': False
})
# Schedule server-side pixel firing after 1 hour (for deduplication)
schedule_pixel_firing.delay(data['order_id'], delay=3600)
return {'status': 'queued'}
def schedule_pixel_firing(order_id, delay):
"""Fire server-side pixel after delay to check if client-side succeeded"""
time.sleep(delay)
# Check if conversion already attributed
conversion = db.conversions.find_one({'order_id': order_id})
if not conversion.get('pixel_fired'):
# Client-side didn't fire - use server-side backup
fire_mediamath_pixel_server(
advertiser_id='ADVERTISER_ID',
pixel_id='PIXEL_ID',
conversion_data=conversion
)
db.conversions.update_one(
{'order_id': order_id},
{'$set': {'pixel_fired': True, 'method': 'server_side_backup'}}
)
User Identification for Server-Side
Method 1: First-Party Cookie ID
def fire_pixel_with_user_id(user_cookie_id, conversion_data):
"""Include user identifier in server-side pixel"""
params = {
'mt_id': 'ADVERTISER_ID',
'mt_adid': 'PIXEL_ID',
'mt_exem': '',
'mt_excl': '',
'v1': conversion_data['value'],
'v2': conversion_data['order_id'],
'v3': user_cookie_id, # Use v3 for user ID
's1': '',
's2': '',
's3': ''
}
response = requests.get('https://pixel.mathtag.com/event/img', params=params)
return response.status_code == 200
Method 2: Device ID (Mobile Apps)
def fire_pixel_mobile_app(device_id, conversion_data, platform='ios'):
"""Fire pixel for mobile app conversions"""
params = {
'mt_id': 'ADVERTISER_ID',
'mt_adid': 'PIXEL_ID',
'mt_exem': '',
'mt_excl': '',
'v1': conversion_data['value'],
'v2': conversion_data['order_id'],
'v3': f"{platform}:{device_id}",
's1': '',
's2': '',
's3': ''
}
response = requests.get('https://pixel.mathtag.com/event/img', params=params)
return response.status_code == 200
Use Case Recommendations
E-commerce
Recommended: Hybrid approach
- Client-side: Real-time purchase tracking
- Server-side: Returns, refunds, high-value orders
Lead Generation
Recommended: Client-side primary
Mobile Apps
Recommended: Server-side
- Server-side: In-app purchases
- App SDK: User engagement events
Subscription Services
Recommended: Server-side
- Server-side: Subscription events, renewals
- Scheduled: Recurring revenue tracking
Offline Sales
Recommended: Server-side only
- Server-side: Store sales uploads
- CRM integration: Phone order tracking
Decision Matrix
| Scenario | Client-Side | Server-Side | Hybrid |
|---|---|---|---|
| Basic website tracking | ✓ | ||
| High ad blocker audience | ✓ | ✓ | |
| Privacy-first approach | ✓ | ||
| Offline conversions | ✓ | ||
| Real-time bidding | ✓ | ✓ | |
| Mobile app tracking | ✓ | ||
| Critical conversions | ✓ | ||
| Dynamic retargeting | ✓ | ✓ |
Performance Comparison
| Metric | Client-Side | Server-Side | Hybrid |
|---|---|---|---|
| Implementation Time | 1-2 days | 3-5 days | 4-7 days |
| Tracking Accuracy (with blockers) | 60-80% | 95-99% | 95-99% |
| Real-time Attribution | Yes | Slight delay | Yes |
| Privacy Compliance | Moderate | High | High |
| Maintenance | Low | Medium | Medium |
| Cost | Low | Medium | Medium |
Best Practices
- Start with client-side, add server-side for critical conversions
- Use order IDs to prevent duplicate conversion counting
- Implement retry logic for failed server-side pixels
- Monitor both methods to identify tracking gaps
- Test server-side pixels in staging before production
- Document your setup for team reference
- Set up alerts for pixel firing failures
- Use server-side for PII to avoid browser exposure
- Implement consent management for client-side pixels
- Regular audits of tracking accuracy across both methods
Troubleshooting
Client-Side Issues
- Ad blockers: Check browser extensions, test in incognito
- Pixel not firing: Verify JavaScript loads, check console errors
- Cookie blocking: Test in Safari/Firefox, implement first-party fallback
Server-Side Issues
- Timeout errors: Increase timeout, implement async firing
- User identification: Verify user ID passing correctly
- Attribution gaps: Check conversion window settings in TerminalOne
Hybrid Issues
- Duplicate conversions: Ensure order ID deduplication logic
- Inconsistent data: Validate data format across both methods
- Increased complexity: Maintain clear documentation