FullStory Data Layer Setup | OpsBlu Docs

FullStory Data Layer Setup

Configure Google Tag Manager data layer to work seamlessly with FullStory for enhanced event tracking and user identification.

Overview

The data layer is a JavaScript object that holds information about your page, users, and events. When using Google Tag Manager (GTM) with FullStory, a properly configured data layer enables you to:

  • Send user properties from GTM to FullStory
  • Track custom events based on data layer changes
  • Dynamically identify users without hardcoding FullStory calls
  • Centralize your tracking logic

Data Layer Basics

What is a Data Layer?

The data layer is a global JavaScript array that stores structured data:

window.dataLayer = window.dataLayer || [];

You push data into it like this:

dataLayer.push({
  'event': 'user_login',
  'userId': 'user_12345',
  'userEmail': 'user@example.com',
  'userPlan': 'premium'
});

GTM listens to the data layer and fires tags based on what you push.

Setting Up Data Layer for FullStory

Step 1: Initialize Data Layer (Before GTM)

Place this before your GTM container snippet:

<head>
  <script>
    window.dataLayer = window.dataLayer || [];
  </script>

  <!-- Google Tag Manager -->
  <script>(function(w,d,s,l,i){...GTM snippet...})(window,document,'script','dataLayer','GTM-XXXX');</script>
  <!-- End Google Tag Manager -->
</head>

Step 2: Push User Data to Data Layer

When a user logs in or when user data is available:

dataLayer.push({
  'event': 'user_identified',
  'userId': 'user_12345',
  'userEmail': 'user@example.com',
  'userPlan': 'premium',
  'userSignupDate': '2024-01-15',
  'userCompany': 'Acme Corp'
});

Step 3: Create GTM Variables

In Google Tag Manager, create variables to access data layer values:

  1. Variables > New > Data Layer Variable
  2. Create these variables:
    • Data Layer Variable Name: userIdGTM Variable Name: DL - User ID
    • Data Layer Variable Name: userEmailGTM Variable Name: DL - User Email
    • Data Layer Variable Name: userPlanGTM Variable Name: DL - User Plan
    • Data Layer Variable Name: userSignupDateGTM Variable Name: DL - Signup Date

Step 4: Create FullStory Identify Tag

Create a Custom HTML tag in GTM that calls FS.identify():

Tag Configuration:

<script>
  if (window.FS && {{DL - User ID}}) {
    FS.identify({{DL - User ID}}, {
      email_str: {{DL - User Email}},
      plan_str: {{DL - User Plan}},
      signupDate_str: {{DL - Signup Date}}
    });
  }
</script>

Trigger: Custom Event user_identified

Result: When user_identified event is pushed to the data layer, FullStory automatically identifies the user.

Tracking Custom Events via Data Layer

Step 1: Push Events to Data Layer

// When user clicks a button
dataLayer.push({
  'event': 'button_click',
  'buttonName': 'Sign Up CTA',
  'buttonLocation': 'homepage',
  'buttonColor': 'blue'
});

// When user completes purchase
dataLayer.push({
  'event': 'purchase_complete',
  'orderId': 'order_789',
  'revenue': 149.99,
  'itemCount': 3
});

Step 2: Create GTM Trigger

In GTM:

  1. Triggers > New
  2. Trigger Type: Custom Event
  3. Event Name: button_click
  4. Save

Step 3: Create FullStory Event Tag

Tag Configuration:

<script>
  if (window.FS) {
    FS.event({{Event}}, {
      buttonName: {{DL - Button Name}},
      buttonLocation: {{DL - Button Location}},
      buttonColor: {{DL - Button Color}}
    });
  }
</script>

Trigger: Custom Event button_click

Variables to create:

  • DL - Button Name (Data Layer Variable: buttonName)
  • DL - Button Location (Data Layer Variable: buttonLocation)
  • DL - Button Color (Data Layer Variable: buttonColor)

E-Commerce Data Layer Integration

Enhanced E-Commerce Data Layer

If you use GTM's Enhanced E-Commerce, you can send product data to FullStory:

// Product view
dataLayer.push({
  'event': 'productView',
  'ecommerce': {
    'detail': {
      'products': [{
        'id': 'P12345',
        'name': 'Widget Pro',
        'price': '49.99',
        'brand': 'Acme',
        'category': 'Electronics'
      }]
    }
  }
});

// Add to cart
dataLayer.push({
  'event': 'addToCart',
  'ecommerce': {
    'add': {
      'products': [{
        'id': 'P12345',
        'name': 'Widget Pro',
        'price': '49.99',
        'quantity': 1
      }]
    }
  }
});

// Purchase
dataLayer.push({
  'event': 'purchase',
  'ecommerce': {
    'purchase': {
      'actionField': {
        'id': 'T12345',
        'revenue': '149.99',
        'shipping': '5.00',
        'tax': '10.00'
      },
      'products': [{
        'id': 'P12345',
        'name': 'Widget Pro',
        'price': '49.99',
        'quantity': 1
      }]
    }
  }
});

Send E-Commerce Events to FullStory

GTM Tag for Product View:

<script>
  if (window.FS && {{ecommerce.detail.products.0.id}}) {
    FS.event('Product Viewed', {
      product_id: {{ecommerce.detail.products.0.id}},
      product_name: {{ecommerce.detail.products.0.name}},
      product_price: {{ecommerce.detail.products.0.price}}
    });
  }
</script>

Trigger: Custom Event productView

Advanced Data Layer Patterns

User Properties Update

When user properties change (e.g., subscription upgrade):

dataLayer.push({
  'event': 'user_properties_updated',
  'userId': 'user_12345',
  'userPlan': 'enterprise',  // Updated from 'premium'
  'upgradedAt': new Date().toISOString()
});

GTM Tag to sync to FullStory:

<script>
  if (window.FS && {{DL - User ID}}) {
    FS.identify({{DL - User ID}}, {
      plan_str: {{DL - User Plan}},
      upgradedAt_str: {{DL - Upgraded At}}
    });
  }
</script>

Page Metadata

Send page-level information:

dataLayer.push({
  'pageCategory': 'product',
  'pageSubcategory': 'electronics',
  'contentAuthor': 'John Doe',
  'publishDate': '2024-01-15'
});

Track in FullStory as custom user vars:

<script>
  if (window.FS) {
    FS.setVars('page', {
      category: {{DL - Page Category}},
      subcategory: {{DL - Page Subcategory}},
      author: {{DL - Content Author}}
    });
  }
</script>

SPA (Single Page Application) Data Layer

For React, Vue, Angular apps with client-side routing:

Virtual Page Views

// On route change
dataLayer.push({
  'event': 'virtualPageview',
  'pagePath': '/dashboard',
  'pageTitle': 'User Dashboard'
});

GTM Tag:

<script>
  if (window.FS) {
    FS.event('Page View', {
      path: {{Page Path}},
      title: {{Page Title}}
    });
  }
</script>

Trigger: Custom Event virtualPageview

Best Practices

Use Consistent Naming

Good:

dataLayer.push({
  'event': 'button_click',
  'buttonName': 'Sign Up',
  'buttonLocation': 'header'
});

Bad:

dataLayer.push({
  'event': 'click',
  'btn': 'Sign Up',
  'loc': 'header'
});

Push Events, Not Just Data

Always include an event key when you want to trigger tags:

// Good - triggers GTM tags
dataLayer.push({
  'event': 'user_login',
  'userId': '12345'
});

// Bad - won't trigger tags
dataLayer.push({
  'userId': '12345'
});

Avoid PII in Data Layer

Don't push sensitive data like full credit card numbers or SSNs:

// Bad
dataLayer.push({
  'creditCard': '4111111111111111',
  'ssn': '123-45-6789'
});

// Good
dataLayer.push({
  'paymentMethod': 'visa',
  'lastFourDigits': '1111'
});

Test in GTM Preview Mode

Before publishing:

  1. Preview mode in GTM
  2. Navigate your site
  3. Verify data layer pushes trigger FullStory tags
  4. Check that FullStory events appear correctly

Troubleshooting

Common Data Layer Issues

Issue Symptoms Possible Causes Solutions
Events not firing Data layer pushes but FullStory events don't appear - FullStory not loaded
- GTM trigger misconfigured
- Tag not firing
- Event name mismatch
- Check typeof FS === 'function'
- Verify trigger event name (case-sensitive)
- Use GTM Preview mode to debug
- Check tag firing conditions
User not identified Events appear but not linked to user - User ID not a string
- FS.identify() tag not firing
- User ID is null or undefined
- Identify fires after events
- Convert user ID to string: userId.toString()
- Check GTM trigger for identify tag
- Validate user ID exists before pushing
- Ensure identify runs before events
Variables undefined GTM variables show as undefined - Data layer key name mismatch
- Variable not set before tag fires
- Typo in variable name
- Data pushed after page load
- Match exact key names (case-sensitive)
- Push data before GTM loads
- Check for typos in variable configuration
- Use dataLayer.push() not reassignment
GTM tag not firing Tag doesn't appear in Preview mode - Trigger conditions not met
- Tag paused or disabled
- Firing order wrong
- Exception blocking tag
- Review trigger conditions in GTM
- Enable tag if paused
- Check tag sequencing/priority
- Remove or adjust exceptions
Property type errors Properties not showing correctly in FullStory - Missing type suffixes (_str, _int, etc.)
- Wrong type for value
- Invalid property format
- Add _str, _int, _real, _bool, _date suffixes
- Convert values to correct type
- Review FullStory property naming rules
E-commerce data not tracking Enhanced e-commerce pushes but events missing - FullStory tag not listening to e-commerce events
- Product data structure incorrect
- Missing GTM triggers for e-commerce
- Create separate tags for each e-commerce event
- Validate data structure matches Enhanced E-commerce spec
- Set up triggers for productView, addToCart, etc.
Data layer state issues Previous values appearing in new events - Data layer not clearing between pushes
- Variables persisting across events
- Push undefined to clear values: {key: undefined}
- Use event-scoped variables
- Avoid relying on persisted state
SPA route changes not tracking Virtual pageviews missing in FullStory - Route change events not pushed
- History API not tracked
- GTM not listening to route changes
- Push virtualPageview event on route change
- Use GTM History Change trigger
- Implement router hooks to push events
Timing issues Events fire before FullStory loads - Data layer pushes too early
- FullStory loads after events
- Race condition
- Wrap FullStory calls in if (window.FS) check
- Queue events until FullStory ready
- Use GTM tag sequencing
Integration with other tags Conflicts with GA4, Segment, or other analytics - Multiple tags using same data layer
- Variable name conflicts
- Event name collisions
- Use namespaced event names
- Check tag firing order
- Coordinate variable naming across tags

Events Not Firing

Step-by-step debugging:

  1. Verify data layer push:

    // In console, check data layer
    console.log(window.dataLayer);
    
    // Monitor new pushes
    const originalPush = window.dataLayer.push;
    window.dataLayer.push = function() {
      console.log('Data layer push:', arguments[0]);
      return originalPush.apply(this, arguments);
    };
    
  2. Check GTM trigger:

    • Open GTM Preview mode
    • Navigate to your site
    • Look for your custom event in the Summary
    • If not firing: review trigger configuration
  3. Verify FullStory loaded:

    console.log(typeof FS);  // Should return "function"
    
  4. Check tag execution:

    • In GTM Preview, click on your event
    • Check "Tags Fired" section
    • If tag didn't fire: review firing conditions
  5. Inspect Network requests:

    • Open DevTools > Network
    • Filter by fullstory
    • Trigger your event
    • Look for POST to /rec/bundle

User Not Identified

Common issues and fixes:

Issue: User ID not a string

// Incorrect - Number
dataLayer.push({ userId: 12345 });

// Correct - String
dataLayer.push({ userId: '12345' });
// Or
dataLayer.push({ userId: String(12345) });

Issue: Identify tag not firing

  • Check GTM trigger is set to custom event user_identified
  • Verify trigger conditions don't have conflicting rules
  • Ensure tag priority is set correctly

Issue: User properties missing type suffixes

// Incorrect
FS.identify(userId, {
  email: user.email,      // Missing _str
  plan: user.plan         // Missing _str
});

// Correct
FS.identify(userId, {
  email_str: user.email,
  plan_str: user.plan
});

Variable Configuration Issues

Verify GTM variables:

  1. Go to Variables in GTM
  2. Check User-Defined Variables
  3. For each data layer variable:
    • Variable Type: "Data Layer Variable"
    • Data Layer Variable Name: exact key from dataLayer.push()
    • Example: If you push { userId: '123' }, variable name is userId

Test variables in Preview mode:

  1. Enable GTM Preview
  2. Navigate to page
  3. Click on event in Summary
  4. Go to Variables tab
  5. Check Data Layer Variables section
  6. Verify values are correct

Debugging Data Layer in GTM Preview

Step 1: Enable Preview Mode

  1. In GTM, click Preview
  2. Enter your website URL
  3. Site opens with debug panel

Step 2: Monitor Data Layer

  1. In debug panel, click on any event
  2. Go to Data Layer tab
  3. Expand each object to see all keys/values

Step 3: Check Tag Firing

  1. Select your custom event from timeline
  2. Check "Tags Fired" section
  3. If FullStory tag is there: it fired successfully
  4. If in "Tags Not Fired": review why

Step 4: Inspect Variables

  1. Click on your event
  2. Go to Variables tab
  3. Find your data layer variables
  4. Verify values match what you pushed

Best Practices for Debugging

Add console logging:

// Log all data layer pushes
function logDataLayerPush(data) {
  console.log('[Data Layer]', data);
  dataLayer.push(data);
}

// Usage
logDataLayerPush({
  event: 'button_click',
  buttonName: 'Sign Up'
});

Validate before pushing:

function pushToDataLayer(data) {
  // Validate required fields
  if (!data.event) {
    console.error('Missing event key:', data);
    return;
  }

  // Validate user ID is string if present
  if (data.userId && typeof data.userId !== 'string') {
    console.warn('User ID should be string:', data.userId);
    data.userId = String(data.userId);
  }

  dataLayer.push(data);
}

Test in staging first:

  • Always test data layer changes in staging
  • Use GTM Preview mode to validate
  • Check FullStory dashboard for events
  • Verify user identification works
  • Only then deploy to production

GTM Container Issues

Container not loading:

  • Verify GTM snippet in <head> section
  • Check GTM container ID is correct
  • Ensure no JavaScript errors blocking GTM

Container published but changes not live:

  • Hard refresh browser (Cmd+Shift+R or Ctrl+Shift+R)
  • Clear browser cache
  • Verify correct container version is live
  • Check GTM Preview shows latest version

Multiple containers on same page:

  • Can cause conflicts
  • Use separate container IDs
  • Coordinate data layer naming

Getting Help

If issues persist:

  1. GTM Community: support.google.com/tagmanager
  2. FullStory Support: support@fullstory.com
  3. Stack Overflow: Tag with google-tag-manager and fullstory

Include in support requests:

  • GTM container ID (if safe to share)
  • Data layer push code
  • GTM Preview screenshots
  • Console errors
  • Expected vs actual behavior

Next Steps:

Additional Resources: