MediaMath Server-Side vs Client-Side | OpsBlu Docs

MediaMath Server-Side vs Client-Side

Comparison and implementation guidance for server-side and client-side MediaMath pixel tracking.

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

Combine both methods for maximum coverage and reliability:

Implementation Strategy

  1. Client-side: Primary tracking for real-time attribution
  2. Server-side: Backup for critical conversions
  3. 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

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

  • Client-side: Form submissions
  • Server-side: Qualified lead updates from CRM

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

  1. Start with client-side, add server-side for critical conversions
  2. Use order IDs to prevent duplicate conversion counting
  3. Implement retry logic for failed server-side pixels
  4. Monitor both methods to identify tracking gaps
  5. Test server-side pixels in staging before production
  6. Document your setup for team reference
  7. Set up alerts for pixel firing failures
  8. Use server-side for PII to avoid browser exposure
  9. Implement consent management for client-side pixels
  10. 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