Hotjar Troubleshooting & Debugging
Common Issues & Solutions
Hotjar Not Tracking or Recording
Symptoms
- No recordings appearing in dashboard
- Heatmaps show zero data
- Real-time view shows no active users
Diagnosis Steps
1. Verify Installation
Open browser DevTools (F12) and check console for errors:
// Check if Hotjar loaded
console.log(typeof hj); // Should return "function"
console.log(window._hjSettings); // Should show your site ID
2. Check Network Requests
In DevTools Network tab, filter by "hotjar" and look for:
script.hotjar.com- Script loaded successfullyinsights.hotjar.com- Data being sent
3. Review Site Settings
In Hotjar dashboard:
- Go to Sites & Organizations
- Verify site status is "Installed"
- Check that site URL matches your domain
Common Causes & Fixes
| Issue | Cause | Solution |
|---|---|---|
| Script blocked by ad blocker | User has ad/tracking blocker enabled | Inform users, test in incognito mode |
| Wrong Site ID | Incorrect hjid in tracking code |
Verify Site ID in Hotjar settings |
| Content Security Policy (CSP) | CSP headers block external scripts | Add script.hotjar.com and *.hotjar.com to CSP |
| Script loaded after user leaves | Async loading too slow | Move script higher in <head> |
| Privacy settings | Cookie consent not granted | Implement consent management properly |
Fix Example: CSP Headers
Content-Security-Policy:
script-src 'self' https://script.hotjar.com;
connect-src 'self' https://*.hotjar.com https://*.hotjar.io;
img-src 'self' https://*.hotjar.com;
font-src 'self' https://script.hotjar.com;
style-src 'self' 'unsafe-inline';
Recordings Not Capturing
Symptoms
- Hotjar is installed but specific sessions aren't recorded
- Recording quota not being consumed
- Filters return no results
Diagnosis
Check Recording Settings:
- Go to Recordings > Settings
- Verify sampling rate (e.g., 100% = record all sessions)
- Check URL targeting rules
- Review device/browser filters
Common Scenarios:
Sampling Too Low
Setting: Record 10% of sessions
Result: Only 1 in 10 visitors recorded
Fix: Increase sampling to 50% or 100%
URL Filters Too Restrictive
Setting: Only record URLs containing "/checkout"
Result: Homepage sessions ignored
Fix: Broaden filters or create multiple recordings
Triggering Conditions Not Met
Setting: Only record if event "purchase_completed" fires
Result: Sessions without that event aren't captured
Fix: Remove event trigger or verify event fires correctly
Solutions
Broaden Your Filters:
// Remove restrictive targeting
// Before: Only /checkout/*
// After: All pages, segment later
Verify Events Fire:
// Test event in console
hj('event', 'test_event');
// Check if recording starts
Check Quota:
- Recordings stop when monthly quota is reached
- Upgrade plan or wait for quota reset
Heatmaps Show No Data
Symptoms
- Heatmap displays "No data available"
- Click/scroll maps are empty
- Page has traffic but heatmap is blank
Diagnosis Steps
1. Check Data Collection Period
- Heatmaps require time to accumulate data (usually 30+ pageviews)
- Verify date range includes recent traffic
2. Verify URL Matching
Common Issue: URL mismatch
Example:
Heatmap URL: https://example.com/page
Actual URL: https://example.com/page?utm_source=email
Fix: Use wildcard matching or remove query parameters
3. Review Filters
- Device filters (mobile vs desktop)
- Geographic filters
- Custom event filters
Solutions
URL Wildcard Matching:
Instead of: https://example.com/product
Use: https://example.com/product*
Matches: /product, /product?id=123, /product/details
Combine Similar Pages:
If you have:
/product/123
/product/456
/product/789
Create dynamic heatmap:
/product/*
Aggregates data across all product pages
Wait for Sufficient Data:
- Minimum: 30 pageviews
- Recommended: 100+ for statistical significance
- High-traffic pages: 1,000+ for detailed insights
Events Not Firing
Symptoms
- Custom events don't appear in filters
- Event-triggered recordings not starting
- Surveys not displaying on event
Diagnosis
Test Event Manually:
// Open console on your site
hj('event', 'test_event');
// Check network tab for request to:
// insights.hotjar.com/api/v2/events
Check Event Name:
// ✅ Correct
hj('event', 'signup_completed');
// ❌ Common mistakes
hj('events', 'signup_completed'); // Wrong function name
hj('event'); // Missing event name
hj('event', signupCompleted); // Variable instead of string
hj('event', 'signup completed'); // Spaces not recommended
Verify Timing:
// ❌ Event fires before Hotjar loads
hj('event', 'page_loaded'); // Might fail if hj not ready
// ✅ Check if Hotjar loaded first
if (typeof hj !== 'undefined') {
hj('event', 'page_loaded');
}
// ✅ Or wrap in timeout
window.addEventListener('load', function() {
setTimeout(() => hj('event', 'page_loaded'), 1000);
});
Solutions
Event Naming Best Practices:
// Use snake_case
hj('event', 'form_submitted');
// Not camelCase or spaces
hj('event', 'formSubmitted'); // Works, but inconsistent
hj('event', 'form submitted'); // Avoid
Debugging Event Flow:
// Add console logs
function trackEvent(eventName) {
console.log('Tracking event:', eventName);
if (typeof hj !== 'undefined') {
hj('event', eventName);
console.log('Event sent successfully');
} else {
console.error('Hotjar not loaded');
}
}
// Usage
trackEvent('button_clicked');
GTM Event Troubleshooting:
If using GTM:
- Enable Preview Mode
- Trigger the event on your site
- Check Tags tab to see if Hotjar tag fired
- Review Variables to ensure event name is correct
- Check Console for errors
Identify API Not Working
Symptoms
- User attributes not showing in recordings
- Can't filter by identified users
- User ID doesn't appear in session details
Diagnosis
Check Identify Call Format:
// ✅ Correct
hj('identify', 'USER_ID_123', {
'email': 'user@example.com',
'plan': 'premium'
});
// ❌ Common mistakes
hj('identify', null, { email: 'user@example.com' }); // Missing user ID
hj('identify', userObject); // Missing attributes object
hj('identify', '123'); // Missing attributes
hj('identify', 123, {}); // User ID should be string
Verify Timing:
// ❌ Called before Hotjar loads
hj('identify', userId, userAttributes);
// ✅ Wrapped in ready check
function identifyUser(userId, attributes) {
if (typeof hj !== 'undefined') {
hj('identify', userId, attributes);
} else {
console.warn('Hotjar not ready, retrying...');
setTimeout(() => identifyUser(userId, attributes), 500);
}
}
Check Attribute Limits:
- Maximum 100 attributes per user
- Attribute values must be strings, numbers, or booleans
- No nested objects
Solutions
Proper Identify Implementation:
// On user login
function onUserLogin(user) {
hj('identify', String(user.id), {
'email': user.email,
'plan': user.subscription.plan,
'signup_date': user.createdAt,
'role': user.role,
'company_size': user.company.employeeCount
});
}
// For SPAs, call on route change
router.afterEach(() => {
if (currentUser) {
hj('identify', String(currentUser.id), userAttributes);
}
});
Attribute Value Formatting:
// ✅ Correct types
hj('identify', 'user123', {
'age': 28, // Number
'premium': true, // Boolean
'country': 'USA', // String
'signup_date': '2024-01-15' // String (dates as ISO)
});
// ❌ Avoid
hj('identify', 'user123', {
'user_object': {id: 123}, // No nested objects
'tags': ['premium', 'annual'], // No arrays
'undefined_value': undefined // No undefined
});
Surveys Not Appearing
Symptoms
- Survey created but doesn't display to users
- Targeting conditions seem correct
- No responses being collected
Diagnosis
Check Survey Status:
- Go to Surveys in Hotjar
- Verify survey is Active (not paused or draft)
- Check start/end dates
Review Targeting:
Common Issues:
- URL targeting too specific (exact match vs wildcard)
- Device filter excludes all traffic (e.g., tablet-only on desktop site)
- Event trigger never fires
- Display frequency: "Once per user" + user already saw it
Test in Incognito:
- Cookies/localStorage might mark you as already seen
- Ad blockers might prevent display
- Consent settings might block survey
Solutions
URL Targeting Fixes:
❌ Too specific: https://example.com/page
✅ Use wildcard: https://example.com/page*
❌ Wrong protocol: http:// (site uses https://)
✅ Match protocol: https://
❌ Subdomain mismatch: www.example.com (tracking example.com)
✅ Use: *example.com/*
Display Frequency:
Setting: Show once per user
Problem: Tested survey already, won't show again
Fix: Clear cookies/localStorage or test in incognito
Event-Based Triggering:
// Verify event fires when expected
hj('event', 'checkout_completed');
// Check survey settings match event name exactly
Survey Setting: Show when event "checkout_completed" happens
Code: hj('event', 'checkout_completed'); // ✅ Match
Code: hj('event', 'checkoutCompleted'); // ❌ Mismatch
Device/Browser Testing:
Survey Settings:
- Device: All devices ✅
- Browser: All browsers ✅
If issues persist:
- Test on different browsers
- Check responsive design (survey might be off-screen)
- Review CSS conflicts
Cross-Domain Tracking Issues
Symptoms
- Sessions split across domains
- User journey fragmented
- Can't track user across subdomains
Diagnosis
Check Tracking Code:
// Both domains must have same Hotjar Site ID
// Domain 1 & Domain 2: hjid: 123456
// Verify in console
console.log(window._hjSettings.hjid); // Should match
Cookie Domain Settings: Hotjar cookies are domain-specific by default.
Solutions
Enable Cross-Domain Tracking:
This isn't automatic in Hotjar like it is in GA. You need to:
- Use the same Site ID on all domains
- Share user ID via URL parameter:
// On domain1.com (sending domain)
const userId = getUserId(); // Your user ID
const targetUrl = `https://domain2.com?user_id=${userId}`;
window.location.href = targetUrl;
// On domain2.com (receiving domain)
const urlParams = new URLSearchParams(window.location.search);
const userId = urlParams.get('user_id');
if (userId) {
hj('identify', userId, userAttributes);
}
Subdomain Tracking:
Hotjar automatically tracks across subdomains if you set cookies correctly:
// No code changes needed
// Hotjar cookies work across:
// www.example.com
// app.example.com
// blog.example.com
Just ensure all subdomains use the same Site ID.
Performance & Loading Issues
Symptoms
- Hotjar slows down page load
- Recording playback laggy
- High CPU usage during recording
Diagnosis
Check Script Loading:
<!-- ✅ Async loading (recommended) -->
<script async src="https://script.hotjar.com/..."></script>
<!-- ❌ Synchronous (blocks rendering) -->
<script src="https://script.hotjar.com/..."></script>
Monitor Impact:
// Measure load time
const start = performance.now();
// Hotjar loads
const end = performance.now();
console.log(`Hotjar load time: ${end - start}ms`);
Solutions
Optimize Loading:
// Lazy load Hotjar after page interactive
window.addEventListener('load', function() {
setTimeout(loadHotjar, 2000); // Delay 2 seconds
});
function loadHotjar() {
(function(h,o,t,j,a,r){
// Hotjar code here
})(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');
}
Reduce Recording Volume:
- Lower sampling rate (record 50% instead of 100%)
- Use URL filters to record only critical pages
- Avoid recording during peak traffic hours (if possible)
Minimize Event Tracking:
// ❌ Excessive tracking
document.addEventListener('mousemove', () => {
hj('event', 'mouse_moved'); // Fires hundreds of times
});
// ✅ Throttle or debounce
let lastEventTime = 0;
document.addEventListener('scroll', () => {
const now = Date.now();
if (now - lastEventTime > 1000) { // Max once per second
hj('event', 'user_scrolled');
lastEventTime = now;
}
});
Data Discrepancies
Symptoms
- Hotjar session count doesn't match Google Analytics
- Heatmap clicks don't align with elements
- Recording shows different content than live site
Common Causes
Session Definition Differences:
- GA4: Session timeout after 30 min of inactivity
- Hotjar: Session ends when user closes tab/browser
- Result: Counts won't match exactly
Ad Blockers:
- Hotjar blocked more often than GA
- ~20-30% of users may block Hotjar
- Result: Hotjar will always show fewer sessions
Sampling:
- If recording only 50% of sessions, counts will be lower
- Heatmaps accumulate over time, not real-time like GA
Dynamic Content:
// Content changes after Hotjar snapshot
// Heatmap shows old version, site has new version
// Solution: Create new heatmap after major updates
Solutions
Expect Discrepancies: Hotjar and GA measure differently. Use each for its strength:
- GA: Traffic volume, sources, conversions
- Hotjar: Behavior, UX issues, qualitative insights
Validate Heatmap Accuracy:
- Regenerate heatmap after site updates
- Check that snapshot matches current page
- Use browser extension to verify element positions
Reconcile Counts:
GA Sessions: 10,000
Hotjar Sessions: 6,000
Possible reasons:
- 30% blocked by ad blockers (3,000)
- 10% sampling rate adjustment (varies)
- Session definition differences
Debugging Tools & Techniques
Browser Developer Tools
Console Commands:
// Check Hotjar loaded
console.log(window.hj);
// View Hotjar settings
console.log(window._hjSettings);
// Manually trigger event
hj('event', 'debug_test');
// Trigger identify
hj('identify', 'test_user_123', { test: true });
// Force state change (SPAs)
hj('stateChange', '/new-page');
Network Tab: Filter by "hotjar" to see:
- Script loading (
script.hotjar.com) - Data being sent (
insights.hotjar.com,vc.hotjar.io) - API calls
Hotjar Debug Mode
Enable detailed logging:
// In browser console
localStorage.setItem('hjDebug', 'true');
// Refresh page, check console for:
// "Hotjar: event tracked: event_name"
// "Hotjar: identify called with userId"
// "Hotjar: recording started"
// Disable debug mode
localStorage.removeItem('hjDebug');
Testing Checklist
Before deploying Hotjar changes:
- Script loads without errors
- Recordings capture on target pages
- Heatmaps generate data
- Events fire when triggered
- Identify API updates user attributes
- Surveys display under correct conditions
- No console errors related to Hotjar
- Performance impact is acceptable
- Privacy/consent requirements met
- Cross-browser testing completed
Support Resources
Hotjar Help Center:
Community Forum:
Contact Support:
- Go to Hotjar dashboard
- Click "?" icon (bottom right)
- Select "Contact Support"
- Provide: Site ID, issue description, screenshots
Provide When Contacting Support:
- Hotjar Site ID
- URL where issue occurs
- Browser/device details
- Screenshots of console errors
- Network request details
- Steps to reproduce
Preventive Maintenance
Regular Health Checks
Monthly:
- Review recording quota usage
- Check for new console errors
- Verify integrations still work
- Update filters for new pages/features
Quarterly:
- Audit event taxonomy
- Remove unused surveys/recordings
- Review user feedback trends
- Update documentation
After Site Updates:
- Test Hotjar on staging before production
- Regenerate heatmaps for updated pages
- Verify events still fire correctly
- Check for new CSP or privacy issues
Documentation
Maintain a tracking plan that includes:
- List of custom events and their purpose
- Identify attributes and their definitions
- Recording/survey targeting rules
- Integration dependencies
- Known issues and workarounds
Monitoring & Alerts
Set up alerts for:
- Sudden drop in session volume
- Recording quota nearing limit
- High rate of negative feedback
- Survey response rate changes
Monitor via:
- Hotjar dashboard (weekly reviews)
- Slack/Teams notifications
- Google Analytics annotations
- Internal analytics dashboards
Additional Resources: