Reddit Ads Data Layer Setup | OpsBlu Docs

Reddit Ads Data Layer Setup

Implementing data layer architecture for Reddit Pixel event parameters and dynamic values.

Data Layer Fundamentals

A data layer is a JavaScript object that stores structured data about the page, user actions, and business events. It acts as a bridge between your website's backend data and tracking tags (like Reddit Pixel), enabling dynamic event parameters without hardcoding values.

Why Use a Data Layer

  • Separation of Concerns: Keeps tracking logic separate from business logic
  • Tag Manager Integration: Powers Google Tag Manager variable mapping
  • Data Consistency: Ensures same data structure across all pages
  • Easier Maintenance: Update tracking without changing pixel code
  • Dynamic Values: Pass real-time data to events (prices, IDs, user info)

Data Layer Structure

Standard Implementation

Place data layer declaration BEFORE Reddit Pixel base code:

<script>
// Initialize data layer
window.dataLayer = window.dataLayer || [];

// Push page-level data
dataLayer.push({
  'pageType': 'product',
  'pageName': 'Product Detail - Widget Pro',
  'productId': 'SKU_123',
  'productName': 'Widget Pro',
  'productPrice': 99.99,
  'productCategory': 'Electronics',
  'currency': 'USD',
  'userStatus': 'logged_in',
  'userId': 'user_12345'
});
</script>

<!-- Reddit Pixel Base Code -->
<script>
!function(w,d){if(!w.rdt){var p=w.rdt=function(){p.sendEvent?p.sendEvent.apply(p,arguments):p.callQueue.push(arguments)};p.callQueue=[];var t=d.createElement("script");t.src="https://www.redditstatic.com/ads/pixel.js",t.async=!0;var s=d.getElementsByTagName("script")[0];s.parentNode.insertBefore(t,s)}}(window,document);
rdt('init', 'PIXEL_ID');
rdt('track', 'PageView');
</script>

Event-Based Data Layer Pushes

Push event-specific data when user actions occur:

// Add to Cart event
dataLayer.push({
  'event': 'addToCart',
  'productId': 'SKU_123',
  'productName': 'Widget Pro',
  'productPrice': 99.99,
  'quantity': 1,
  'currency': 'USD'
});

// Trigger Reddit Pixel event from dataLayer
rdt('track', 'AddToCart', {
  value: dataLayer[dataLayer.length - 1].productPrice,
  currency: dataLayer[dataLayer.length - 1].currency,
  itemCount: dataLayer[dataLayer.length - 1].quantity
});

Page-Level Data Layers

Homepage

<script>
dataLayer.push({
  'pageType': 'home',
  'pageName': 'Homepage',
  'currency': 'USD',
  'userStatus': 'guest'
});
</script>

Product Detail Page

<script>
dataLayer.push({
  'pageType': 'product',
  'pageName': 'Product Detail',
  'product': {
    'id': 'SKU_123',
    'name': 'Widget Pro',
    'price': 99.99,
    'category': 'Electronics',
    'brand': 'WidgetCo',
    'variant': 'Blue',
    'inStock': true
  },
  'currency': 'USD'
});
</script>

Category Page

<script>
dataLayer.push({
  'pageType': 'category',
  'pageName': 'Electronics',
  'categoryName': 'Electronics',
  'productCount': 24,
  'currency': 'USD'
});
</script>

Cart Page

<script>
dataLayer.push({
  'pageType': 'cart',
  'pageName': 'Shopping Cart',
  'cart': {
    'items': [
      { 'id': 'SKU_123', 'name': 'Widget Pro', 'price': 99.99, 'quantity': 2 },
      { 'id': 'SKU_456', 'name': 'Widget Lite', 'price': 49.99, 'quantity': 1 }
    ],
    'itemCount': 3,
    'total': 249.97
  },
  'currency': 'USD'
});
</script>

Order Confirmation Page

<script>
dataLayer.push({
  'pageType': 'purchase',
  'pageName': 'Order Confirmation',
  'transaction': {
    'id': 'ORDER_12345',
    'total': 249.97,
    'subtotal': 249.97,
    'shipping': 0,
    'tax': 0,
    'currency': 'USD',
    'items': [
      { 'id': 'SKU_123', 'name': 'Widget Pro', 'price': 99.99, 'quantity': 2 },
      { 'id': 'SKU_456', 'name': 'Widget Lite', 'price': 49.99, 'quantity': 1 }
    ]
  }
});

// Fire Reddit Purchase event from dataLayer
rdt('track', 'Purchase', {
  value: dataLayer[0].transaction.total,
  currency: dataLayer[0].transaction.currency,
  transactionId: dataLayer[0].transaction.id,
  itemCount: dataLayer[0].transaction.items.reduce((sum, item) => sum + item.quantity, 0)
});
</script>

Event-Specific Data Layers

Add to Cart

function addToCart(productId, productName, price, quantity) {
  // Update cart in backend
  // ...

  // Push to dataLayer
  dataLayer.push({
    'event': 'addToCart',
    'ecommerce': {
      'currencyCode': 'USD',
      'add': {
        'products': [{
          'id': productId,
          'name': productName,
          'price': price,
          'quantity': quantity
        }]
      }
    }
  });

  // Fire Reddit Pixel event
  rdt('track', 'AddToCart', {
    value: price * quantity,
    currency: 'USD',
    itemCount: quantity
  });
}

Form Submission (Lead)

document.getElementById('lead-form').addEventListener('submit', function(e) {
  e.preventDefault();

  const formData = new FormData(e.target);

  dataLayer.push({
    'event': 'leadFormSubmit',
    'formType': 'contact',
    'formName': 'Contact Us',
    'leadSource': 'website'
  });

  // Fire Reddit Lead event
  rdt('track', 'Lead');

  // Submit form
  e.target.submit();
});

User Registration

function onRegistrationComplete(userId, email) {
  dataLayer.push({
    'event': 'signUp',
    'userId': userId,
    'userType': 'new',
    'registrationMethod': 'email'
  });

  // Fire Reddit SignUp event
  rdt('track', 'SignUp');
}

Product View

function trackProductView(product) {
  dataLayer.push({
    'event': 'productView',
    'ecommerce': {
      'currencyCode': 'USD',
      'detail': {
        'products': [{
          'id': product.id,
          'name': product.name,
          'price': product.price,
          'category': product.category
        }]
      }
    }
  });

  // Fire Reddit ViewContent event
  rdt('track', 'ViewContent', {
    value: product.price,
    currency: 'USD',
    itemCount: 1
  });
}

Google Tag Manager Integration

Variable Configuration

Create GTM variables from dataLayer:

Product Price Variable:

  • Variable Type: Data Layer Variable
  • Data Layer Variable Name: product.price
  • Variable Name: DLV - Product Price

Product ID Variable:

  • Variable Type: Data Layer Variable
  • Data Layer Variable Name: product.id
  • Variable Name: DLV - Product ID

Transaction Total Variable:

  • Variable Type: Data Layer Variable
  • Data Layer Variable Name: transaction.total
  • Variable Name: DLV - Transaction Total

Transaction ID Variable:

  • Variable Type: Data Layer Variable
  • Data Layer Variable Name: transaction.id
  • Variable Name: DLV - Transaction ID

Currency Variable:

  • Variable Type: Data Layer Variable
  • Data Layer Variable Name: currency
  • Default Value: USD
  • Variable Name: DLV - Currency

Tag Configuration

Reddit Purchase Event Tag:

<script>
rdt('track', 'Purchase', {
  value: {{DLV - Transaction Total}},
  currency: {{DLV - Currency}},
  transactionId: '{{DLV - Transaction ID}}',
  itemCount: {{DLV - Item Count}}
});
</script>

Trigger: Custom Event equals purchase

Reddit AddToCart Event Tag:

<script>
rdt('track', 'AddToCart', {
  value: {{DLV - Product Price}},
  currency: {{DLV - Currency}},
  itemCount: {{DLV - Product Quantity}}
});
</script>

Trigger: Custom Event equals addToCart

Helper Functions

Get Latest DataLayer Value:

function getDataLayerValue(key) {
  // Find most recent dataLayer entry with the key
  for (let i = dataLayer.length - 1; i >= 0; i--) {
    if (dataLayer[i][key] !== undefined) {
      return dataLayer[i][key];
    }
  }
  return null;
}

// Usage
const productPrice = getDataLayerValue('product.price');

Calculate Item Count:

function calculateItemCount() {
  const transaction = getDataLayerValue('transaction');
  if (transaction && transaction.items) {
    return transaction.items.reduce((sum, item) => sum + item.quantity, 0);
  }
  return 0;
}

Server-Side Data Layer

Node.js/Express Example

// routes/product.js
app.get('/product/:id', async (req, res) => {
  const product = await getProduct(req.params.id);

  res.render('product', {
    product: product,
    dataLayer: {
      pageType: 'product',
      product: {
        id: product.id,
        name: product.name,
        price: product.price,
        category: product.category
      },
      currency: 'USD'
    }
  });
});

Template (EJS):

<script>
dataLayer.push(<%- JSON.stringify(dataLayer) %>);
</script>

PHP Example

<?php
// product.php
$product = getProduct($_GET['id']);

$dataLayer = [
  'pageType' => 'product',
  'product' => [
    'id' => $product['id'],
    'name' => $product['name'],
    'price' => $product['price'],
    'category' => $product['category']
  ],
  'currency' => 'USD'
];
?>

<script>
dataLayer.push(<?php echo json_encode($dataLayer); ?>);
</script>

Python/Django Example

# views.py
def product_detail(request, product_id):
    product = Product.objects.get(id=product_id)

    data_layer = {
        'pageType': 'product',
        'product': {
            'id': product.id,
            'name': product.name,
            'price': float(product.price),
            'category': product.category
        },
        'currency': 'USD'
    }

    return render(request, 'product.html', {
        'product': product,
        'data_layer': json.dumps(data_layer)
    })

Template:

<script>
dataLayer.push({{ data_layer|safe }});
</script>

Advanced Data Layer Patterns

User Identification Layer

// Set user data on login
function setUserData(user) {
  dataLayer.push({
    'userId': user.id,
    'userEmail': hashEmail(user.email),  // Hashed for privacy
    'userStatus': 'logged_in',
    'userType': user.isNew ? 'new' : 'returning',
    'membershipLevel': user.membership
  });
}

// Use in Reddit Pixel for advanced matching
rdt('init', 'PIXEL_ID', {
  email: getDataLayerValue('userEmail'),
  externalId: getDataLayerValue('userId')
});

Custom Dimension Tracking

dataLayer.push({
  'event': 'purchase',
  'customDimensions': {
    'paymentMethod': 'credit_card',
    'shippingMethod': 'express',
    'discountCode': 'SUMMER20',
    'customerSegment': 'vip'
  }
});

Enhanced Ecommerce Data Layer

// Product Impressions
dataLayer.push({
  'event': 'productImpressions',
  'ecommerce': {
    'currencyCode': 'USD',
    'impressions': [
      {
        'id': 'SKU_123',
        'name': 'Widget Pro',
        'price': 99.99,
        'category': 'Electronics',
        'position': 1
      },
      {
        'id': 'SKU_456',
        'name': 'Widget Lite',
        'price': 49.99,
        'category': 'Electronics',
        'position': 2
      }
    ]
  }
});

// Product Click
dataLayer.push({
  'event': 'productClick',
  'ecommerce': {
    'click': {
      'actionField': {'list': 'Search Results'},
      'products': [{
        'id': 'SKU_123',
        'name': 'Widget Pro',
        'price': 99.99,
        'category': 'Electronics'
      }]
    }
  }
});

Data Layer Validation

Console Debugging

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

// Inspect current dataLayer
console.table(dataLayer);

// Get specific value
console.log('Product Price:', getDataLayerValue('product.price'));

Validation Checklist

  • DataLayer declared before GTM or Reddit Pixel
  • All numeric values are numbers (not strings)
  • Currency codes are strings (ISO 4217 format)
  • Transaction IDs are unique strings
  • User identifiers hashed for privacy
  • No undefined or null values
  • Consistent property naming (camelCase)
  • Events pushed on correct user actions

Best Practices

Structure

  1. Initialize Early: Declare window.dataLayer before any tracking tags
  2. Consistent Naming: Use camelCase for all property names
  3. Nested Objects: Group related data (product, transaction, user)
  4. Event Names: Clear, descriptive event names for dataLayer pushes

Data Quality

  1. Type Safety: Ensure correct data types (number for prices, string for IDs)
  2. Validation: Validate data before pushing to dataLayer
  3. No PII: Hash or pseudonymize personally identifiable information
  4. Fallbacks: Provide default values for optional fields

Performance

  1. Minimal Pushes: Only push data when it changes
  2. Async Loading: Don't block page load waiting for data
  3. Lazy Loading: Push detailed data only when needed
  4. Batch Updates: Combine related data in single push

Maintenance

  1. Documentation: Document dataLayer schema and expected values
  2. Version Control: Track dataLayer changes in code repository
  3. Testing: Validate dataLayer in dev/staging before production
  4. Monitoring: Alert on missing or malformed dataLayer data

Privacy & Compliance

  1. Hash PII: Use SHA-256 for emails, phone numbers
  2. Consent: Check user consent before pushing tracking data
  3. Data Minimization: Only collect necessary data
  4. Retention: Document data retention policies
  5. Access Control: Limit who can modify dataLayer implementation