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("¤cyCode=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 │
└──────────────────────────────────────────────────────────────┘
Recommended Event Ownership
| 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
- Adobe Experience Platform Debugger
- Launch Preview mode
- Browser Network tab (filter for
b/ss)
Server-Side Validation
Use Assurance (Griffon) for Edge implementations:
- Create Assurance session
- Connect server environment
- 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
- Trigger client-side journey
- Complete transaction (server-side)
- 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) |