← Back to Table of Contents

Heat Map Analytics

Comprehensive heat map analytics system for visualizing user behavior patterns, click distributions, and engagement hotspots on your website.

Overview Types of Heatmaps Implementation Data Collection Visualization Analytics Dashboard API Endpoints Privacy Considerations

Overview

Heat map analytics provides visual representations of user behavior patterns on your website, helping you understand how users interact with your content, where they click, scroll, and focus their attention.

Types of Heatmaps

Click Heatmaps

Visualize where users click on your pages, identifying popular elements and potential usability issues.

Features

Scroll Heatmaps

Track how far users scroll down your pages, identifying content engagement and drop-off points.

Features

Attention Heatmaps

Track where users focus their attention using mouse movement and hover data.

Features

Implementation

Tracking Setup

1Initialize Heatmap Tracking

// Initialize heatmap tracking
HeatmapAnalytics.init({
  projectId: 'your-project-id',
  tracking: {
    clicks: true,
    scrolls: true,
    mouseMovement: true,
    hovers: true
  },
  sampling: {
    clickSampling: 1.0,      // 100% of clicks
    scrollSampling: 0.5,     // 50% of scroll events
    mouseSampling: 0.1,      // 10% of mouse movements
    hoverSampling: 0.2       // 20% of hover events
  },
  privacy: {
    anonymizeIp: true,
    respectDoNotTrack: true
  }
});

2Configure Data Collection

// Configure data collection settings
HeatmapAnalytics.configure({
  dataCollection: {
    batchSize: 100,          // Send data in batches of 100
    flushInterval: 5000,     // Send data every 5 seconds
    maxRetries: 3,           // Maximum retry attempts
    compression: true        // Compress data before sending
  },
  performance: {
    throttleEvents: true,    // Throttle events for performance
    maxEventsPerSecond: 100, // Maximum events per second
    debounceTime: 100        // Debounce time in milliseconds
  }
});

Event Tracking

Click Tracking

// Track click events
document.addEventListener('click', function(event) {
  const clickData = {
    x: event.clientX,
    y: event.clientY,
    target: event.target.tagName,
    targetClass: event.target.className,
    targetId: event.target.id,
    pageUrl: window.location.href,
    timestamp: Date.now(),
    viewportWidth: window.innerWidth,
    viewportHeight: window.innerHeight
  };
  
  HeatmapAnalytics.track('click', clickData);
});

Scroll Tracking

// Track scroll events
let lastScrollPosition = 0;
const scrollThreshold = 100; // Track every 100px
window.addEventListener('scroll', function() {
  const currentScrollPosition = window.scrollY;
  const scrollDirection = currentScrollPosition > lastScrollPosition ? 'down' : 'up';
  
  if (Math.abs(currentScrollPosition - lastScrollPosition) >= scrollThreshold) {
    const scrollData = {
      scrollPosition: currentScrollPosition,
      scrollDirection: scrollDirection,
      pageHeight: document.documentElement.scrollHeight,
      viewportHeight: window.innerHeight,
      scrollPercentage: (currentScrollPosition / (document.documentElement.scrollHeight - window.innerHeight)) * 100,
      timestamp: Date.now()
    };
    
    HeatmapAnalytics.track('scroll', scrollData);
    lastScrollPosition = currentScrollPosition;
  }
});

Mouse Movement Tracking

// Track mouse movement
let mouseTrackingEnabled = true;
let lastMousePosition = { x: 0, y: 0 };
const mouseThreshold = 50; // Track every 50px
document.addEventListener('mousemove', function(event) {
  if (!mouseTrackingEnabled) return;
  
  const currentPosition = { x: event.clientX, y: event.clientY };
  const distance = Math.sqrt(
    Math.pow(currentPosition.x - lastMousePosition.x, 2) +
    Math.pow(currentPosition.y - lastMousePosition.y, 2)
  );
  
  if (distance >= mouseThreshold) {
    const mouseData = {
      x: event.clientX,
      y: event.clientY,
      pageUrl: window.location.href,
      timestamp: Date.now(),
      viewportWidth: window.innerWidth,
      viewportHeight: window.innerHeight
    };
    
    HeatmapAnalytics.track('mouse', mouseData);
    lastMousePosition = currentPosition;
  }
});

Data Collection

Data Processing

Data Aggregation

# Backend data processing
class HeatmapProcessor:
    def __init__(self, project_id):
        self.project_id = project_id
        self.click_data = []
        self.scroll_data = []
        self.mouse_data = []
    
    def process_click_data(self, raw_data):
        """Process click data for heatmap visualization"""
        processed_data = []
        
        for click in raw_data:
            # Normalize coordinates
            normalized_x = self.normalize_x_coordinate(click['x'], click['viewportWidth'])
            normalized_y = self.normalize_y_coordinate(click['y'], click['viewportHeight'])
            
            processed_click = {
                'x': normalized_x,
                'y': normalized_y,
                'target': click['target'],
                'timestamp': click['timestamp'],
                'page_url': click['pageUrl']
            }
            
            processed_data.append(processed_click)
        
        return self.aggregate_click_points(processed_data)
    
    def aggregate_click_points(self, click_data):
        """Aggregate click points for heatmap rendering"""
        grid_size = 20  # 20x20 pixel grid
        click_grid = {}
        
        for click in click_data:
            grid_x = int(click['x'] / grid_size)
            grid_y = int(click['y'] / grid_size)
            grid_key = f"{grid_x},{grid_y}"
            
            if grid_key not in click_grid:
                click_grid[grid_key] = {
                    'x': grid_x * grid_size,
                    'y': grid_y * grid_size,
                    'count': 0,
                    'intensity': 0
                }
            
            click_grid[grid_key]['count'] += 1
            click_grid[grid_key]['intensity'] = min(click_grid[grid_key]['count'] / 10, 1.0)
        
        return list(click_grid.values())

Data Storage

Database Schema

# Heatmap data schema
CREATE TABLE heatmap_clicks (
    id SERIAL PRIMARY KEY,
    project_id VARCHAR(255) NOT NULL,
    page_url TEXT NOT NULL,
    x INTEGER NOT NULL,
    y INTEGER NOT NULL,
    viewport_width INTEGER NOT NULL,
    viewport_height INTEGER NOT NULL,
    target_tag VARCHAR(50),
    target_class TEXT,
    target_id VARCHAR(255),
    timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    session_id VARCHAR(255),
    user_id VARCHAR(255)
);
CREATE TABLE heatmap_scrolls (
    id SERIAL PRIMARY KEY,
    project_id VARCHAR(255) NOT NULL,
    page_url TEXT NOT NULL,
    scroll_position INTEGER NOT NULL,
    scroll_direction VARCHAR(10),
    scroll_percentage DECIMAL(5,2),
    page_height INTEGER NOT NULL,
    viewport_height INTEGER NOT NULL,
    timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    session_id VARCHAR(255),
    user_id VARCHAR(255)
);
CREATE TABLE heatmap_aggregated (
    id SERIAL PRIMARY KEY,
    project_id VARCHAR(255) NOT NULL,
    page_url TEXT NOT NULL,
    heatmap_type VARCHAR(20) NOT NULL, -- 'click', 'scroll', 'mouse'
    grid_data JSONB NOT NULL,
    date_created DATE DEFAULT CURRENT_DATE,
    total_events INTEGER DEFAULT 0
);

Visualization

Heatmap Rendering

Canvas-based Rendering

// Heatmap visualization component
class HeatmapVisualizer {
    constructor(canvas, data, options = {}) {
        this.canvas = canvas;
        this.ctx = canvas.getContext('2d');
        this.data = data;
        this.options = {
            radius: options.radius || 20,
            intensity: options.intensity || 0.8,
            colorScheme: options.colorScheme || 'default',
            showGrid: options.showGrid || false
        };
        
        this.colors = this.getColorScheme(this.options.colorScheme);
        this.render();
    }
    
    render() {
        // Clear canvas
        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
        
        // Draw background
        this.drawBackground();
        
        // Draw heatmap data
        this.drawHeatmapData();
        
        // Draw grid if enabled
        if (this.options.showGrid) {
            this.drawGrid();
        }
    }
    
    drawHeatmapData() {
        this.data.forEach(point => {
            const gradient = this.ctx.createRadialGradient(
                point.x, point.y, 0,
                point.x, point.y, this.options.radius
            );
            
            const intensity = point.intensity || 0.5;
            const color = this.getColorForIntensity(intensity);
            
            gradient.addColorStop(0, color);
            gradient.addColorStop(1, 'transparent');
            
            this.ctx.fillStyle = gradient;
            this.ctx.fillRect(
                point.x - this.options.radius,
                point.y - this.options.radius,
                this.options.radius * 2,
                this.options.radius * 2
            );
        });
    }
    
    getColorForIntensity(intensity) {
        const colors = this.colors;
        const index = Math.floor(intensity * (colors.length - 1));
        return colors[Math.min(index, colors.length - 1)];
    }
    
    getColorScheme(scheme) {
        const schemes = {
            default: [
                'rgba(0, 0, 255, 0.1)',   // Blue (low intensity)
                'rgba(0, 255, 0, 0.3)',   // Green (medium-low)
                'rgba(255, 255, 0, 0.5)',  // Yellow (medium)
                'rgba(255, 165, 0, 0.7)',  // Orange (medium-high)
                'rgba(255, 0, 0, 0.9)'     // Red (high intensity)
            ],
            blue: [
                'rgba(0, 0, 100, 0.1)',
                'rgba(0, 0, 200, 0.3)',
                'rgba(0, 100, 255, 0.5)',
                'rgba(0, 200, 255, 0.7)',
                'rgba(0, 255, 255, 0.9)'
            ],
            green: [
                'rgba(0, 100, 0, 0.1)',
                'rgba(0, 150, 0, 0.3)',
                'rgba(0, 200, 0, 0.5)',
                'rgba(0, 255, 0, 0.7)',
                'rgba(100, 255, 100, 0.9)'
            ]
        };
        
        return schemes[scheme] || schemes.default;
    }
}

Interactive Features

Zoom and Pan

// Interactive heatmap features
class InteractiveHeatmap extends HeatmapVisualizer {
    constructor(canvas, data, options = {}) {
        super(canvas, data, options);
        this.setupInteractions();
    }
    
    setupInteractions() {
        this.canvas.addEventListener('wheel', this.handleZoom.bind(this));
        this.canvas.addEventListener('mousedown', this.handlePanStart.bind(this));
        this.canvas.addEventListener('mousemove', this.handlePanMove.bind(this));
        this.canvas.addEventListener('mouseup', this.handlePanEnd.bind(this));
        this.canvas.addEventListener('click', this.handleClick.bind(this));
    }
    
    handleZoom(event) {
        event.preventDefault();
        const zoomFactor = event.deltaY > 0 ? 0.9 : 1.1;
        this.zoom *= zoomFactor;
        this.render();
    }
    
    handleClick(event) {
        const rect = this.canvas.getBoundingClientRect();
        const x = event.clientX - rect.left;
        const y = event.clientY - rect.top;
        
        // Find data point at click position
        const clickedPoint = this.findDataPointAt(x, y);
        
        if (clickedPoint) {
            this.showPointDetails(clickedPoint);
        }
    }
    
    showPointDetails(point) {
        const details = {
            position: `(${point.x}, ${point.y})`,
            clicks: point.count || 0,
            intensity: point.intensity || 0,
            target: point.target || 'Unknown'
        };
        
        // Display point details in tooltip
        this.showTooltip(details);
    }
}

Analytics Dashboard

Dashboard Components

Heatmap Overview

Metrics Panel

Comparative Analysis

A/B Testing

Trend Analysis

API Endpoints

Heatmap Data API

Get Heatmap Data

# Get click heatmap data
GET /api/v1/heatmaps/clicks/{project_id}
Parameters:
- page_url: URL of the page
- start_date: Start date for data
- end_date: End date for data
- grid_size: Grid size for aggregation
Response:
{
  "data": [
    {
      "x": 100,
      "y": 200,
      "count": 15,
      "intensity": 0.75
    }
  ],
  "metadata": {
    "total_clicks": 1250,
    "unique_visitors": 450,
    "date_range": "2024-01-01 to 2024-01-31"
  }
}

Get Scroll Data

# Get scroll heatmap data
GET /api/v1/heatmaps/scrolls/{project_id}
Parameters:
- page_url: URL of the page
- start_date: Start date for data
- end_date: End date for data
- bucket_size: Scroll position bucket size
Response:
{
  "data": [
    {
      "scroll_position": 500,
      "percentage": 25.5,
      "user_count": 125,
      "drop_off_rate": 0.15
    }
  ],
  "metadata": {
    "average_scroll_depth": 65.2,
    "total_sessions": 450,
    "completion_rate": 0.35
  }
}

Configuration API

Update Heatmap Settings

# Update heatmap configuration
PUT /api/v1/heatmaps/config/{project_id}
{
  "tracking": {
    "clicks": true,
    "scrolls": true,
    "mouse_movement": true,
    "hovers": false
  },
  "sampling": {
    "click_sampling": 1.0,
    "scroll_sampling": 0.5,
    "mouse_sampling": 0.1,
    "hover_sampling": 0.2
  },
  "privacy": {
    "anonymize_ip": true,
    "respect_do_not_track": true,
    "data_retention_days": 365
  }
}

Privacy Considerations

Data Protection

Privacy Features

  • IP Anonymization: Anonymize IP addresses
  • Do Not Track: Respect DNT headers
  • Data Minimization: Collect only necessary data
  • User Consent: Require user consent for tracking
  • Data Retention: Automatic data cleanup

Compliance

  • GDPR Compliance: Full GDPR compliance
  • CCPA Compliance: California privacy compliance
  • Data Processing: Transparent data processing
  • User Rights: Respect user data rights

Optimization

Performance Optimization

Best Practices

  • Regular Analysis: Review heatmaps regularly
  • A/B Testing: Use heatmaps for A/B testing
  • Mobile Optimization: Optimize for mobile devices
  • User Feedback: Combine with user feedback
  • Continuous Improvement: Continuously optimize based on insights