Outbrain Data Layer Setup | OpsBlu Docs

Outbrain Data Layer Setup

Configure data layer implementation to pass dynamic conversion data and event parameters to Outbrain.

Data Layer Overview

A data layer is a JavaScript object that stores structured information about user interactions, page content, and conversion data. By implementing a clean, consistent data layer, you can dynamically populate Outbrain tracking parameters without hardcoding values in your pixel implementation.

Why Use a Data Layer?

  • Dynamic values: Pass order totals, product IDs, and user data without template modifications
  • Separation of concerns: Marketing team controls tracking logic without touching application code
  • Consistency: Standardize data structure across multiple tracking platforms (Outbrain, GA4, Meta)
  • Flexibility: Update tracking parameters via tag manager without code deployments
  • Debugging: Easily inspect data layer in browser console to verify values

Data Layer Structure

Page-Level Data Layer

Store persistent information about the current page and user context:

window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  'page': {
    'type': 'product',              // Page type: home, product, category, checkout, confirmation
    'category': 'Electronics',       // Content or product category
    'language': 'en',                // Site language
    'country': 'US'                  // User country
  },
  'user': {
    'id': 'USER-12345',              // Internal user ID (if logged in)
    'status': 'logged_in',           // Authentication status
    'customerType': 'returning'      // New, returning, VIP, etc.
  }
});

Event-Based Data Layer

Push event-specific data when user actions occur:

// When user completes purchase
window.dataLayer.push({
  'event': 'purchase',
  'ecommerce': {
    'transaction_id': 'ORD-2024-001',
    'value': 149.99,
    'currency': 'USD',
    'tax': 10.50,
    'shipping': 5.00,
    'items': [
      {
        'item_id': 'PROD-ABC-123',
        'item_name': 'Wireless Mouse',
        'item_category': 'Electronics',
        'price': 29.99,
        'quantity': 2
      },
      {
        'item_id': 'PROD-XYZ-789',
        'item_name': 'Keyboard',
        'item_category': 'Electronics',
        'price': 89.99,
        'quantity': 1
      }
    ]
  }
});

Implementation Patterns

Pattern 1: Server-Side Rendering

For traditional server-rendered pages, generate data layer in template:

PHP Example:

<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  'page': {
    'type': '<?php echo $pageType; ?>',
    'category': '<?php echo htmlspecialchars($category); ?>'
  },
  'ecommerce': {
    'transaction_id': '<?php echo $order->id; ?>',
    'value': <?php echo $order->total; ?>,
    'currency': '<?php echo $order->currency; ?>'
  }
});
</script>

Python/Django Example:

<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  'ecommerce': {
    'transaction_id': '{{ order.id }}',
    'value': {{ order.total }},
    'currency': '{{ order.currency }}'
  }
});
</script>

Ruby/Rails Example:

<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  'ecommerce': {
    'transaction_id': '<%= @order.id %>',
    'value': <%= @order.total %>,
    'currency': '<%= @order.currency %>'
  }
});
</script>

Pattern 2: Client-Side JavaScript

For SPAs or dynamic content, populate data layer via JavaScript:

// On page load or route change
function initializeDataLayer(pageData) {
  window.dataLayer = window.dataLayer || [];
  window.dataLayer.push({
    'page': {
      'type': pageData.type,
      'category': pageData.category
    },
    'user': {
      'id': getCurrentUserId(),
      'status': isUserLoggedIn() ? 'logged_in' : 'guest'
    }
  });
}

// On conversion event
function trackPurchase(orderData) {
  window.dataLayer.push({
    'event': 'purchase',
    'ecommerce': {
      'transaction_id': orderData.id,
      'value': orderData.total,
      'currency': orderData.currency
    }
  });
}

Pattern 3: React / Vue / Angular

React Example:

import { useEffect } from 'react';

function CheckoutConfirmation({ order }) {
  useEffect(() => {
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
      'event': 'purchase',
      'ecommerce': {
        'transaction_id': order.id,
        'value': order.total,
        'currency': order.currency,
        'items': order.items.map(item => ({
          'item_id': item.sku,
          'item_name': item.name,
          'price': item.price,
          'quantity': item.quantity
        }))
      }
    });
  }, [order]);

  return <div>Thank you for your order!</div>;
}

Vue Example:

export default {
  mounted() {
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
      event: 'purchase',
      ecommerce: {
        transaction_id: this.order.id,
        value: this.order.total,
        currency: this.order.currency
      }
    });
  }
}

Connecting Data Layer to Outbrain

Direct JavaScript Integration

Read from data layer and pass to Outbrain pixel:

// Wait for data layer to be populated
window.addEventListener('load', function() {
  const ecommerce = window.dataLayer.find(item => item.ecommerce)?.ecommerce;

  if (ecommerce && ecommerce.transaction_id) {
    obApi('track', 'Conversion', {
      orderValue: ecommerce.value,
      orderId: ecommerce.transaction_id,
      currency: ecommerce.currency
    });
  }
});

Google Tag Manager Integration

Create GTM variables to read data layer values:

Step 1: Create Data Layer Variables in GTM

  1. Go to Variables > New > Data Layer Variable
  2. Create variables for each value:
    • DLV - Transaction ID → Data Layer Variable Name: ecommerce.transaction_id
    • DLV - Order Value → Data Layer Variable Name: ecommerce.value
    • DLV - Currency → Data Layer Variable Name: ecommerce.currency
    • DLV - Product ID → Data Layer Variable Name: ecommerce.items.0.item_id

Step 2: Use Variables in Outbrain Tag

<script type="text/javascript">
  obApi('track', 'Conversion', {
    orderValue: {{DLV - Order Value}},
    orderId: '{{DLV - Transaction ID}}',
    currency: '{{DLV - Currency}}',
    productId: '{{DLV - Product ID}}'
  });
</script>

Step 3: Set Trigger to Fire on Data Layer Event

  1. Create trigger: Custom Event with event name: purchase
  2. This trigger fires when window.dataLayer.push({ event: 'purchase' }) executes

Data Layer Schema for Outbrain

Required Fields

{
  'event': 'purchase',                    // Event name (purchase, lead, signup)
  'ecommerce': {
    'transaction_id': 'ORD-12345',        // Unique order ID (string)
    'value': 149.99,                      // Total order value (number, not string)
    'currency': 'USD'                     // ISO 4217 currency code (string)
  }
}

Optional Fields

{
  'event': 'purchase',
  'ecommerce': {
    'transaction_id': 'ORD-12345',
    'value': 149.99,
    'currency': 'USD',
    'tax': 10.50,                         // Tax amount
    'shipping': 5.00,                     // Shipping cost
    'discount': 15.00,                    // Discount applied
    'coupon': 'SAVE15',                   // Coupon code used
    'payment_method': 'credit_card',      // Payment type
    'items': [                            // Product details
      {
        'item_id': 'PROD-123',
        'item_name': 'Widget',
        'item_category': 'Electronics',
        'price': 29.99,
        'quantity': 2
      }
    ]
  },
  'user': {
    'id': 'USER-789',                     // Internal user ID
    'email_hash': 'abc123...',            // SHA-256 hashed email (for enhanced matching)
    'customer_type': 'returning'          // Customer segment
  }
}

Lead Generation Schema

{
  'event': 'lead',
  'lead': {
    'lead_id': 'LEAD-2024-456',           // Unique lead identifier
    'value': 50,                          // Estimated lead value
    'currency': 'USD',
    'lead_type': 'Contact Form',          // Type of lead
    'industry': 'Technology',             // Lead's industry
    'company_size': '50-200'              // Company size bracket
  }
}

Engagement Event Schema

{
  'event': 'signup',
  'user': {
    'user_id': 'USER-2024-789',
    'email_hash': 'hashed_email',
    'signup_method': 'email',             // email, google, facebook
    'account_type': 'free'                // free, trial, paid
  }
}

Data Validation & Testing

Browser Console Inspection

// View entire data layer
console.log(window.dataLayer);

// Find specific event
const purchaseEvent = window.dataLayer.find(item => item.event === 'purchase');
console.log(purchaseEvent);

// Check specific value
console.log(window.dataLayer.find(item => item.ecommerce)?.ecommerce?.value);

GTM Preview Mode Validation

  1. Enter GTM Preview mode
  2. Navigate to conversion page
  3. In GTM debug panel, select the event (e.g., "purchase")
  4. Check Data Layer tab to verify all expected values are present
  5. Check Variables tab to confirm GTM variables read correct values
  6. Verify Outbrain tag fires with correct parameters

Data Layer Listener for Debugging

// Log all data layer pushes
(function() {
  const originalPush = window.dataLayer.push;
  window.dataLayer.push = function() {
    console.log('Data Layer Push:', arguments);
    return originalPush.apply(window.dataLayer, arguments);
  };
})();

Common Data Layer Issues

Issue: Data Layer Not Defined

Symptom: Cannot read property 'push' of undefined

Solution: Initialize data layer before any pushes:

window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ /* data */ });

Issue: Values Are Strings Instead of Numbers

Symptom: GTM or Outbrain receives "149.99" instead of 149.99

Solution: Ensure numeric values are not quoted:

// Wrong
'value': '149.99'

// Correct
'value': 149.99
'value': parseFloat(orderTotal)

Issue: Data Layer Pushed After Tag Fires

Symptom: GTM tag fires but variables are undefined or empty

Solution: Push to data layer before triggering event:

// Push data first
window.dataLayer.push({
  'ecommerce': { /* data */ }
});

// Then push event (triggers GTM tags)
window.dataLayer.push({
  'event': 'purchase'
});

Issue: Special Characters Breaking JSON

Symptom: JavaScript errors or malformed data

Solution: Escape or sanitize user-input values:

function sanitize(str) {
  return String(str).replace(/['"\\]/g, '');
}

window.dataLayer.push({
  'ecommerce': {
    'coupon': sanitize(userInput)
  }
});

Data Layer Best Practices

Naming Conventions

  • Use snake_case for consistency with GA4: transaction_id, order_value
  • Be descriptive: item_category not cat, customer_type not type
  • Namespace custom properties: custom_lead_score, custom_attribution_source

Data Types

  • Strings: Wrap in quotes: 'USD', 'ORD-12345'
  • Numbers: No quotes: 149.99, 2, 0
  • Booleans: Use true/false: is_logged_in: true
  • Arrays: Use brackets: items: [...]

Timing

  • Initialize base data layer in <head> before any tracking scripts
  • Push page-level data on initial page load
  • Push event-level data immediately before or during user action
  • For SPAs, clear/reset data layer on route changes to avoid stale data

Privacy & Security

  • Never include plaintext emails, phone numbers, or PII
  • Hash sensitive data with SHA-256 before adding to data layer
  • Respect user consent: don't populate data layer if user opted out
  • Sanitize user input to prevent XSS attacks via data layer injection

Data Layer Implementation Checklist

  • Data layer initialized before any tracking scripts load
  • Required fields present: transaction_id, value, currency
  • Numeric values are numbers, not strings
  • Currency codes are uppercase ISO 4217 (USD, EUR, GBP)
  • Unique transaction IDs for deduplication
  • Event name matches GTM trigger configuration
  • Data layer structure documented for team reference
  • Tested in browser console and GTM preview mode
  • Privacy compliance: no plaintext PII, consent respected
  • Single-page app: data layer updates on route changes
  • Server-side rendering: values properly escaped/sanitized
  • Fallback values or error handling for missing data