Integrate Hotjar with Optimizely Web Experimentation

Loading...·9 min read

Hotjar provides session recordings, heatmaps, and user feedback tools that reveal how visitors interact with your site. Integrating Hotjar with Optimizely Web Experimentation lets you filter recordings and heatmaps by experiment variation — so you can watch real users experience each variation and understand the behavioral differences behind your test metrics.

Optimizely offers a native Hotjar integration through its addons library, and you can also build a custom integration using the track_layer_decision callback and Hotjar's Events API. This guide covers both approaches, explains when to use each, and walks through a structured workflow for analyzing experiment behavior in Hotjar.

Choosing Your Integration Method

Optimizely provides two ways to connect Hotjar to your experiments. Pick one — do not enable both, as this causes duplicate events in Hotjar.

Native Integration

Custom Integration

Setup time

~5 minutes

~10 minutes

Tag format

prefix_variationID (numeric IDs)

Human-readable experiment and variation names

Heatmap targeting

Manual setup per variation per experiment

Automatic via events

Recording filtering

By tag

By event name

Survey targeting

Not supported

Supported (events can trigger surveys)

Multi-experiment filtering

Complex (generic tags)

Clean (one event per experiment)

Maintenance

None after setup

None after setup

flowchart TD
    A["Need Hotjar + Optimizely?"] --> B{"Do you need human-readable\nvariation names in Hotjar?"}
    B -->|No| C{"Need to trigger surveys\nby experiment variation?"}
    B -->|Yes| D["Use Custom Integration"]
    C -->|No| E["Use Native Integration"]
    C -->|Yes| D

Option A: Native Integration

The native integration uses Optimizely's built-in Hotjar extension to tag recordings and fire events automatically. It is the simpler approach but uses numeric variation IDs instead of human-readable names.

Prerequisites

  • Hotjar tracking code installed on your site

  • Optimizely Web Experimentation snippet installed

  • Access to Optimizely project settings

Step 1: Install the Integration

  1. In Optimizely, go to Settings > Integrations.

  2. Search for or download the Hotjar Heatmaps and Recordings extension from the Optimizely addons library.

  3. Enable the extension.

Step 2: Enable for Your Experiment

  1. Open your experiment and go to the Integrations tab.

  2. Set Recordings to ON and check the Tracked box.

  3. Click Save.

Optimizely now tags all Hotjar recordings with experiment and campaign information for visitors who enter the experiment.

Step 3: Set Up Heatmaps (Optional)

Heatmaps require additional configuration per variation:

  1. In your experiment, click API Names in the Variations section to find each variation's numeric ID.

  2. In the experiment's Integrations tab, enable the Heatmaps field.

  3. Enter an event prefix — a short name for your experiment (e.g., homepageRedesign).

  4. In Hotjar, create one heatmap per variation:

    • Set targeting to Event.

    • Enter the event name as prefix_variationID (e.g., homepageRedesign_8575810288).

    • Add a Custom Screenshot URL appending the force variation parameter: www.example.com/my-page/?optimizely_x=VARIATION_ID.

  5. Save and generate each heatmap.

Step 4: Verify

  1. Open your site in an incognito window.

  2. Confirm you are bucketed into the experiment (check window.optimizely.get('state').getExperimentStates() in the console).

  3. In Hotjar, go to Recordings and filter by the experiment tag. You should see your session appear within a few minutes.

Option B: Custom Integration

The custom integration uses Optimizely's Custom Analytics Integration framework to send human-readable experiment and variation names to Hotjar as events. These events can filter recordings, target heatmaps, and trigger surveys.

Prerequisites

  • Hotjar tracking code installed on your site

  • Optimizely Web Experimentation snippet installed

  • Access to create Custom Analytics Integrations in Optimizely

Step 1: Create the Integration

  1. In Optimizely, go to Settings > Integrations.

  2. Click Create Analytics Integration > Using JSON.

  3. Paste the following JSON configuration:

{
  "plugin_type": "analytics_integration",
  "name": "Hotjar Experiment Events",
  "form_schema": [],
  "description": "Sends experiment and variation names to Hotjar as events",
  "options": {
    "track_layer_decision": "var state = window['optimizely'].get('state');\nvar campaignObject = state.getDecisionObject({'campaignId': campaignId});\n\nif (campaignObject !== null) {\n  var utils = window['optimizely'].get('utils');\n  utils.waitUntil(function() {\n    return typeof hj === 'function';\n  }).then(function() {\n    var expName = (campaignObject.experiment || String(campaignId)).replace(/[^a-zA-Z0-9_\\- .]/g, '_');\n    var varName = (campaignObject.variation || String(variationId)).replace(/[^a-zA-Z0-9_\\- .]/g, '_');\n    hj('event', expName + ' - ' + varName);\n  });\n}\n"
  }
}
  1. Click Create Extension.

  2. Toggle the integration to Enabled.

  3. Optionally check Enable by default for all new experiments.

What the Callback Does

The track_layer_decision callback fires every time Optimizely makes a variation decision. Here is the logic broken down:

// 1. Get the current experiment state
var state = window['optimizely'].get('state');
var campaignObject = state.getDecisionObject({'campaignId': campaignId});

if (campaignObject !== null) {
  // 2. Wait for Hotjar to be ready (it may load after Optimizely)
  var utils = window['optimizely'].get('utils');
  utils.waitUntil(function() {
    return typeof hj === 'function';
  }).then(function() {
    // 3. Sanitize names (Hotjar allows: a-z, A-Z, 0-9, _, -, space, period)
    var expName = (campaignObject.experiment || String(campaignId))
      .replace(/[^a-zA-Z0-9_\- .]/g, '_');
    var varName = (campaignObject.variation || String(variationId))
      .replace(/[^a-zA-Z0-9_\- .]/g, '_');

    // 4. Send event to Hotjar
    hj('event', expName + ' - ' + varName);
  });
}

Why waitUntil is required: Hotjar's tracking script may load after Optimizely makes its first decision. Without waitUntil, that decision's event is silently lost — the hj() function does not exist yet. The waitUntil pattern polls until hj is available, then fires the event.

Why sanitize names: Hotjar event names only accept alphanumeric characters, underscores, dashes, spaces, and periods. Experiment names in Optimizely can contain characters like colons or slashes that Hotjar rejects. The regex replaces invalid characters with underscores.

Step 2: Enable for Your Experiment

  1. Open your experiment and go to the Integrations tab.

  2. Find Hotjar Experiment Events and toggle it ON.

  3. Save.

Step 3: Verify

  1. Open your site in an incognito window.

  2. Open the browser console and confirm Optimizely is running:

window.optimizely.get('state').getExperimentStates()
  1. Verify Hotjar received the event. In Hotjar, go to Events and look for your experiment name within a few minutes.

  2. Check Recordings and filter by the event name to confirm sessions are tagged.

Filtering Recordings by Variation

Once the integration is sending data, filter recordings to analyze behavior per variation:

With the Native Integration

  1. In Hotjar, go to Recordings.

  2. Use the tag filter and select your experiment's tag.

  3. Recordings are tagged with experiment and variation IDs.

With the Custom Integration

  1. In Hotjar, go to Recordings.

  2. Click Filters > Events.

  3. Select your experiment event (e.g., Homepage Hero Test - Blue CTA).

  4. Hotjar shows only recordings where that event fired during the session.

Building an Experiment Analysis Workflow

Most teams set up the integration, skim a few recordings, and move on. A structured workflow extracts significantly more value.

Step 1: Set Up Filters Before the Test Starts

Before launching your experiment, create saved filters or segments in Hotjar for each variation. This way, data accumulates from day one and you can monitor behavioral patterns throughout the test.

For the custom integration:

  1. In Hotjar, go to Recordings > Filters > Events.

  2. Select your control variation event.

  3. Save the filter. Name it clearly: [Experiment Name] - Control.

  4. Repeat for each treatment variation.

Step 2: Establish Baseline Behavior

Before analyzing treatment variations, understand how users behave with the current experience:

  1. Switch to your Control filter.

  2. Watch 15-20 session recordings. Note:

    • Where do users pause or hesitate? Look for mouse hovering without clicking, or scrolling back up to re-read.

    • What is the typical scroll depth? How far down the page do most users get?

    • Where do users click? Are they clicking elements you expect, or trying to click non-interactive elements?

    • What is the path to conversion? How many steps does a typical converting user take?

  3. Check the heatmap for click distribution and scroll depth.

  4. Note Hotjar's rage click detection and engagement metrics.

Document these observations. They become your comparison baseline.

Step 3: Compare Treatment Variations

Switch to each treatment filter and look for behavioral differences:

What to Compare

Control Behavior

Treatment Behavior

What It Means

Scroll depth

60% reach CTA

80% reach CTA

New layout keeps attention longer

Rage clicks

2% of sessions

8% of sessions

New element is confusing or broken

Dead clicks

Low on hero image

High on hero image

Users expect the new hero image to be clickable

Time to first click

4 seconds

8 seconds

New design creates decision paralysis

Quick-backs

5% of sessions

15% of sessions

Users see something unexpected, hit back

Step 4: Combine Quantitative and Qualitative Data

flowchart TD
    A["Optimizely declares a winner"] --> B{"Check Hotjar recordings"}
    B --> C{"Rage clicks or dead clicks increased?"}
    C -->|Yes| D["Fix UX issues before shipping"]
    C -->|No| E{"Scroll depth and engagement improved?"}
    E -->|Yes| F["Strong winner - ship with confidence"]
    E -->|No| G{"Conversion up but engagement down?"}
    G -->|Yes| H["Investigate: short-term gain may not sustain"]
    G -->|No| I["Neutral behavioral impact - ship based on metrics"]

Advanced Techniques

Trigger Surveys by Variation

The custom integration enables a powerful workflow: trigger Hotjar surveys only for users in a specific variation. This lets you collect qualitative feedback about a design change from the people actually seeing it.

  1. In Hotjar, create a new Survey.

  2. Under targeting, select Event and choose your variation event (e.g., Pricing Page Redesign - New Layout).

  3. The survey appears only to users bucketed into that variation.

Use this to ask targeted questions: "How easy was it to find the pricing information?" only to users seeing the new pricing layout.

User Attribute Tagging with Identify API

For richer segmentation, supplement events with user attributes using Hotjar's Identify API. This is useful when you want to cross-filter recordings by experiment variation AND user properties (plan type, account age, etc.).

Modify the custom integration to also send an identify call:

{
  "plugin_type": "analytics_integration",
  "name": "Hotjar Experiment Events with Attributes",
  "form_schema": [],
  "description": "Sends experiment data as both events and user attributes",
  "options": {
    "track_layer_decision": "var state = window['optimizely'].get('state');\nvar campaignObject = state.getDecisionObject({'campaignId': campaignId});\n\nif (campaignObject !== null) {\n  var utils = window['optimizely'].get('utils');\n  utils.waitUntil(function() {\n    return typeof hj === 'function';\n  }).then(function() {\n    var expName = (campaignObject.experiment || String(campaignId)).replace(/[^a-zA-Z0-9_\\- .]/g, '_');\n    var varName = (campaignObject.variation || String(variationId)).replace(/[^a-zA-Z0-9_\\- .]/g, '_');\n    hj('event', expName + ' - ' + varName);\n    var attrs = {};\n    attrs['opti_' + expName] = varName;\n    hj('identify', null, attrs);\n  });\n}\n"
  }
}

This sends each experiment as a user attribute (e.g., opti_Homepage Hero Test = Blue CTA), enabling filtering in Hotjar's User Attributes panel. The null user ID means Hotjar uses its own anonymous session identifier.

Limit: Hotjar supports up to 100 user attributes per site. If you run many concurrent experiments, the events-only approach is more scalable.

Heatmap Targeting by Event

With the custom integration, you can create variation-specific heatmaps without the manual per-variation setup that the native integration requires:

  1. In Hotjar, create a new Heatmap.

  2. Under Session Targeting, select Event.

  3. Choose your variation event (e.g., Hero Test - Variation B).

  4. Hotjar collects heatmap data only from sessions in that variation.

This gives you side-by-side click and scroll heatmaps for each variation without needing variation IDs or custom screenshot URLs.

What Hotjar Cannot Tell You

Understanding the limitations prevents over-reliance on behavioral data:

  • Statistical significance: Hotjar does not calculate significance. Use Optimizely's stats engine for that. Hotjar reveals why variations behave differently, not whether the difference is real.

  • Server-side experiments: Hotjar is client-side JavaScript only. It works with Optimizely Web Experimentation, not Feature Experimentation server-side SDKs.

  • Revenue attribution: Hotjar tracks behavior, not transactions. It cannot tell you which variation generated more revenue — only how users behaved differently.

  • Mobile apps: Hotjar is web-only. For mobile experiments, use tools like Firebase or Amplitude.

  • Event properties: Hotjar's Events API does not support key-value properties on events. Each event is a simple string. Use the Identify API for structured attributes.

Troubleshooting

Events Not Appearing in Hotjar

  1. Wait a few minutes — events are not always real-time.

  2. Verify Hotjar is loaded: open browser console, run typeof hj === 'function'.

  3. Verify Optimizely is loaded: run typeof window.optimizely !== 'undefined'.

  4. Confirm the experiment is running (not paused or draft).

  5. Confirm the integration is enabled for the specific experiment (check the experiment's Integrations tab).

  6. Check for JavaScript errors in the console — a sanitization issue or typo in the JSON can silently fail.

Tags Show Numeric IDs Instead of Names

You are using the native integration, which sends variation IDs. Switch to the custom integration for human-readable names. Alternatively, your Optimizely project may have Mask descriptive names enabled — go to Settings > Privacy and disable it.

Duplicate Events in Hotjar

You have both the native integration and a custom integration enabled for the same experiment. Disable one. Having both causes each session to receive duplicate tags, skewing your behavioral analysis.

Event Names Truncated or Missing Characters

Hotjar event names have a 250-character limit and only accept alphanumeric characters, underscores, dashes, spaces, and periods. The custom integration's regex sanitization handles most cases, but very long experiment names may be truncated. Keep experiment names under 100 characters.

Data Discrepancies Between Optimizely and Hotjar

Expect 5-15% differences in visitor counts. Common causes:

  • Different counting: Optimizely counts visitors, Hotjar counts sessions.

  • Ad blockers: May block one script but not the other.

  • Session sampling: Hotjar may sample on high-traffic sites depending on your plan.

  • Script load order: If Hotjar fails to load, the waitUntil will keep polling but the event is lost if the page navigates away first.

Investigate if discrepancies exceed 20%.