Adobe Analytics Server-Side vs Client-Side | OpsBlu Docs

Adobe Analytics Server-Side vs Client-Side

Server-side vs client-side tracking approaches for Adobe Analytics. Covers implementation trade-offs, data accuracy, privacy compliance, ad blocker.

Overview

Adobe Analytics supports data collection through client-side JavaScript (AppMeasurement/Web SDK), server-side APIs (Data Insertion API), and hybrid approaches using Adobe Experience Platform. Understanding when to use each method ensures accurate, complete analytics data.

Client-Side Collection

When to Use

  • Page views and navigation: Standard page loads and SPA route changes
  • User interactions: Clicks, scrolls, video engagement, form interactions
  • Browser context: Device info, screen resolution, referrer, user agent
  • Real-time visitor identification: ECID and visitor stitching
  • Launch rule-based tracking: Leveraging Adobe Launch (Tags) capabilities

Implementation Options

AppMeasurement

Traditional JavaScript library:

<script src="//assets.adobedtm.com/launch-xxxxx.min.js" async></script>
// Set variables
s.pageName = "example:home";
s.channel = "web";
s.events = "event1";

// Send page view
s.t();

// Send link tracking hit
s.tl(this, 'o', 'CTA Click');

Web SDK (Alloy.js)

Modern approach with XDM:

<script src="https://cdn1.adoberesources.net/alloy/2.x.x/alloy.min.js" async></script>
alloy("sendEvent", {
  xdm: {
    eventType: "web.webpagedetails.pageViews",
    web: {
      webPageDetails: {
        name: "example:home",
        siteSection: "homepage"
      }
    }
  }
});

Advantages

  • Full browser context automatically captured
  • Real-time visitor identification via ECID
  • Launch/Tags rules for flexible configuration
  • Immediate data in Real-Time reports
  • Integration with Target, Audience Manager
  • Session and visit logic handled automatically

Limitations

  • Subject to ad blockers (10-30% traffic impact)
  • Relies on JavaScript execution
  • Cannot capture server-only events
  • Data can be manipulated by users
  • Page unload events may be lost

Server-Side Collection

When to Use

  • Authoritative transactions: Orders, payments, refunds, cancellations
  • Backend events: Webhook callbacks, API interactions, cron jobs
  • Offline conversions: Phone orders, in-store purchases, CRM events
  • Data validation: Events requiring server verification before tracking
  • Ad blocker bypass: Critical conversions that must be captured
  • Bulk data import: Historical data or offline data integration

Data Insertion API

Send events directly to Adobe:

POST https://namespace.sc.omtrdc.net/b/ss/rsid/0

pageName=Order%20Confirmation&events=purchase&products=Electronics;SKU-12345;1;69.99&purchaseID=ORD-98765&mid=12345678901234567890123456789012345678

Java Implementation

import java.net.HttpURLConnection;
import java.net.URL;

public void trackPurchase(Order order, String visitorId) throws Exception {
    String endpoint = "https://namespace.sc.omtrdc.net/b/ss/rsid/0";

    StringBuilder payload = new StringBuilder();
    payload.append("pageName=").append(encode("Order Confirmation"));
    payload.append("&events=purchase");
    payload.append("&products=").append(buildProductString(order));
    payload.append("&purchaseID=").append(order.getId());
    payload.append("&mid=").append(visitorId);
    payload.append("&currencyCode=USD");

    URL url = new URL(endpoint);
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setRequestMethod("POST");
    conn.setDoOutput(true);

    try (OutputStream os = conn.getOutputStream()) {
        os.write(payload.toString().getBytes("UTF-8"));
    }

    int responseCode = conn.getResponseCode();
    // Handle response
}

Node.js Implementation

const https = require('https');

async function trackServerEvent(eventData, visitorId) {
  const params = new URLSearchParams({
    pageName: eventData.pageName,
    events: eventData.events,
    products: eventData.products,
    purchaseID: eventData.purchaseID,
    mid: visitorId,
    currencyCode: 'USD'
  });

  const options = {
    hostname: 'namespace.sc.omtrdc.net',
    port: 443,
    path: `/b/ss/${reportSuiteId}/0`,
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded'
    }
  };

  return new Promise((resolve, reject) => {
    const req = https.request(options, (res) => {
      resolve(res.statusCode === 200);
    });

    req.on('error', reject);
    req.write(params.toString());
    req.end();
  });
}

Required Parameters

Parameter Description Source
mid Marketing Cloud Visitor ID From client ECID cookie
pageName Page/event identifier Event context
events Event list Business event type
purchaseID Unique transaction ID Order system
currencyCode Currency for revenue Order system

Advantages

  • Immune to ad blockers
  • Server-validated data (no manipulation)
  • Capture backend-only events
  • Guaranteed delivery with retry logic
  • Works for non-browser contexts
  • Bulk/batch processing support

Limitations

  • No automatic browser context
  • No real-time visitor identification
  • Must manage visitor ID correlation
  • No Launch/Tags rule processing
  • More complex implementation

Edge Network Collection

Adobe Experience Platform Edge provides a middle-ground approach:

Architecture

Browser → Edge Network → Adobe Analytics + Other Destinations

Benefits

  • First-party data collection
  • Single SDK for multiple solutions
  • Server-side data enrichment
  • Better privacy controls
  • Reduced client-side JavaScript

Implementation

// Web SDK with Edge configuration
alloy("configure", {
  edgeDomain: "edge.example.com",
  datastreamId: "xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  orgId: "XXXXX@AdobeOrg"
});

alloy("sendEvent", {
  xdm: {
    eventType: "commerce.purchases",
    commerce: {
      order: {
        purchaseID: "ORD-98765"
      },
      purchases: { value: 1 }
    },
    productListItems: [{
      SKU: "SKU-12345",
      name: "Wireless Headphones",
      priceTotal: 69.99,
      quantity: 1
    }]
  }
});

Hybrid Architecture

Most implementations combine approaches:

┌──────────────────────────────────────────────────────────────┐
│                        USER JOURNEY                           │
├──────────────────────────────────────────────────────────────┤
│  Page View  →  Product View  →  Add to Cart  →  Purchase     │
│      ↓              ↓               ↓              ↓          │
│  [CLIENT]       [CLIENT]        [CLIENT]       [SERVER]       │
│  Launch          Launch          Launch        Data Insert    │
└──────────────────────────────────────────────────────────────┘
Event Type Collection Method Reason
Page views Client Needs browser context
Product views Client User interaction
Cart operations Client UI-driven events
Checkout steps Client User flow tracking
Purchase Server Authoritative transaction
Refunds Server Backend-only event
Subscription events Server System-triggered

Visitor ID Correlation

Critical for hybrid implementations:

Capturing ECID from Browser

// Get ECID for server-side use
var ecid = Visitor.getInstance("ORG_ID@AdobeOrg").getMarketingCloudVisitorID();

// Pass to server in checkout form
document.getElementById('ecid').value = ecid;

// Or via AJAX
fetch('/api/checkout', {
  method: 'POST',
  body: JSON.stringify({
    order: orderData,
    ecid: ecid
  })
});

Server-Side Usage

// Use ECID from client
String ecid = request.getParameter("ecid");

// Include in server-side hit
payload.append("&mid=").append(ecid);

Identity Stitching

When ECID isn't available, use custom visitor ID:

// Client-side: Set custom ID
s.visitorID = "custom_visitor_12345";

// Server-side: Use same ID
payload.append("&vid=").append(customVisitorId);

Deduplication Strategies

Option 1: Server-Only for Transactions

// Client: Track up to checkout
s.events = "scCheckout";
s.t();

// Server handles purchase tracking
// Client does NOT fire purchase event

Option 2: Purchase ID Deduplication

Adobe automatically deduplicates based on purchaseID:

// Both client and server can send with same purchaseID
// Adobe only counts once per unique purchaseID
s.purchaseID = "ORD-98765";
s.events = "purchase";

Option 3: Timestamp Validation

// Server-side with timestamp
long timestamp = order.getCompletedAt().toEpochMilli();
payload.append("&ts=").append(timestamp);

Validation and Testing

Client-Side Validation

  1. Adobe Experience Platform Debugger
  2. Launch Preview mode
  3. Browser Network tab (filter for b/ss)

Server-Side Validation

Use Assurance (Griffon) for Edge implementations:

  1. Create Assurance session
  2. Connect server environment
  3. Monitor hits and data

For Data Insertion API:

# Test endpoint (returns validation info)
curl -X POST "https://namespace.sc.omtrdc.net/b/ss/rsid/0/test" \
  -d "pageName=test&events=event1"

Hybrid Validation

  1. Trigger client-side journey
  2. Complete transaction (server-side)
  3. Verify in Reports:
    • Visit contains both client and server events
    • No duplicate purchases
    • Attribution preserved

Security Considerations

Report Suite Access

Server-side requests require no authentication (by design for 1x1 pixel compatibility), but:

  • Use IP whitelisting if possible
  • Implement rate limiting
  • Validate all input data

Input Validation

// Validate purchaseID format
if (!purchaseId.matches("^ORD-[0-9]{5,}$")) {
    throw new ValidationException("Invalid purchase ID");
}

// Validate numeric values
if (orderTotal < 0 || orderTotal > 1000000) {
    throw new ValidationException("Invalid order total");
}

// Sanitize text fields
String pageName = sanitize(eventData.getPageName());

Rate Limiting

const rateLimit = require('express-rate-limit');

const analyticsLimiter = rateLimit({
  windowMs: 60 * 1000,
  max: 100 // 100 events per minute per IP
});

app.post('/api/track', analyticsLimiter, trackEvent);

Decision Matrix

Scenario Recommended Approach
Page views Client (Launch/Web SDK)
User clicks Client (Link tracking)
Product interactions Client (Launch rules)
Ecommerce cart Client (Launch)
Purchase confirmation Server (Data Insertion)
Refunds/cancellations Server (Data Insertion)
Offline conversions Server (Bulk Data Insertion)
Subscription renewals Server (Data Insertion)
Critical conversions Server (bypass ad blockers)