analytics.tube
Proxy Guide

Express.js Proxy Setup

Configure Express.js middleware to proxy analytics-tube tracking requests

Express.js makes it easy to proxy analytics-tube tracking using middleware. This guide shows how to set up a reverse proxy using http-proxy-middleware.

Overview

The http-proxy-middleware package provides a simple way to proxy requests in Express applications, making it perfect for routing analytics requests to analytics-tube servers.

What you'll achieve:

  • Proxy all analytics-tube endpoints through your Express app
  • Forward necessary headers for accurate tracking
  • Optional caching for better performance
  • Support all analytics-tube features

Prerequisites

  • Node.js and Express.js application
  • npm or yarn package manager
  • Your analytics-tube instance URL:
    • Cloud hosted: https://app.analytics.tube
    • Self-hosted: Your instance URL
  • Your analytics-tube site ID

Implementation

Install http-proxy-middleware

Install the proxy middleware package:

npm install http-proxy-middleware

Or with yarn:

yarn add http-proxy-middleware

Configure Environment Variables

Create or update your .env file:

# .env
analytics-tube_HOST=https://app.analytics.tube
# For self-hosted: analytics-tube_HOST=https://analytics.yourcompany.com

Install dotenv if not already: npm install dotenv

Add Proxy Middleware to Express

Minimal setup with basic tracking:

// server.js
require('dotenv').config();
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');

const app = express();
const analytics-tube_HOST = process.env.analytics-tube_HOST || 'https://app.analytics.tube';

// Proxy script and track endpoints only
app.use(['/analytics/script.js', '/analytics/track'], createProxyMiddleware({
  target: analytics-tube_HOST,
  changeOrigin: true,
  pathRewrite: {
    '^/analytics': '/api',
  },
  onProxyReq: (proxyReq, req, res) => {
    const clientIp = req.headers['x-forwarded-for'] || req.socket.remoteAddress;
    proxyReq.setHeader('X-Forwarded-For', clientIp);
    proxyReq.setHeader('X-Real-IP', clientIp);
  },
}));

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

For TypeScript projects:

// server.ts
import 'dotenv/config';
import express, { Request, Response } from 'express';
import { createProxyMiddleware, Options } from 'http-proxy-middleware';

const app = express();
const analytics-tube_HOST = process.env.analytics-tube_HOST || 'https://app.analytics.tube';

const proxyOptions: Options = {
  target: analytics-tube_HOST,
  changeOrigin: true,
  pathRewrite: {
    '^/analytics': '/api',
  },
  onProxyReq: (proxyReq, req, res) => {
    const clientIp = req.headers['x-forwarded-for'] || req.socket.remoteAddress;
    proxyReq.setHeader('X-Forwarded-For', clientIp as string);
    proxyReq.setHeader('X-Real-IP', clientIp as string);
  },
  logLevel: 'warn',
};

app.use('/analytics', createProxyMiddleware(proxyOptions));

app.use('/analytics/site/tracking-config', createProxyMiddleware({
  target: analytics-tube_HOST,
  changeOrigin: true,
  pathRewrite: {
    '^/analytics/site': '/api/site',
  },
  onProxyReq: proxyOptions.onProxyReq,
}));

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

Update Your Tracking Script

In your HTML or template files:

<script src="/analytics/script.js" async data-site-id="YOUR_SITE_ID"></script>

Start Your Server

node server.js

Or with nodemon for development:

npm install -D nodemon
npx nodemon server.js

Verify the Setup

  1. Test script endpoint:

    curl -I http://localhost:3000/analytics/script.js
  2. Open your app in a browser with Developer Tools

  3. Check Network tab: Requests should go to /analytics/*

  4. Verify in analytics-tube dashboard: Data should appear

How It Works

The http-proxy-middleware intercepts requests matching the specified paths and forwards them to analytics-tube:

  1. Request to /analytics/script.js is intercepted
  2. Path is rewritten to /api/script.js
  3. Request is forwarded to https://app.analytics.tube/api/script.js
  4. Client IP headers are added for accurate tracking
  5. Response is sent back to the browser

Advanced Configuration

Caching Responses

Add caching for better performance:

const NodeCache = require('node-cache');
const cache = new NodeCache({ stdTTL: 3600 }); // 1 hour default

// Install: npm install node-cache

// Caching middleware for scripts
const cacheMiddleware = (req, res, next) => {
  const key = req.originalUrl;
  const cachedResponse = cache.get(key);

  if (cachedResponse) {
    res.set('X-Cache-Status', 'HIT');
    return res.send(cachedResponse);
  }

  // Store original send
  const originalSend = res.send.bind(res);
  res.send = (body) => {
    cache.set(key, body);
    res.set('X-Cache-Status', 'MISS');
    return originalSend(body);
  };
  next();
};

// Apply caching only to script files
app.use('/analytics/script.js', cacheMiddleware);
app.use('/analytics/script.js', createProxyMiddleware({
  // ... proxy config
}));

Request Size Limits

For session replay uploads, increase body size limit:

const express = require('express');
const app = express();

// Increase limit for session replay endpoints
app.use('/analytics/session-replay', express.json({ limit: '10mb' }));
app.use('/analytics/session-replay', createProxyMiddleware({
  target: analytics-tube_HOST,
  changeOrigin: true,
  pathRewrite: {
    '^/analytics': '/api',
  },
}));

Rate Limiting

Protect your proxy with rate limiting:

const rateLimit = require('express-rate-limit');

// Install: npm install express-rate-limit

const analyticsLimiter = rateLimit({
  windowMs: 60 * 1000, // 1 minute
  max: 100, // Limit each IP to 100 requests per minute
  message: 'Too many requests from this IP',
  standardHeaders: true,
  legacyHeaders: false,
});

// Apply to tracking endpoints
app.use('/analytics/track', analyticsLimiter);
app.use('/analytics/track', createProxyMiddleware({
  // ... proxy config
}));

Error Handling

Add error handling for proxy failures:

app.use('/analytics', createProxyMiddleware({
  target: analytics-tube_HOST,
  changeOrigin: true,
  pathRewrite: {
    '^/analytics': '/api',
  },
  onError: (err, req, res) => {
    console.error('Proxy error:', err);
    res.status(500).json({ error: 'Analytics proxy error' });
  },
  onProxyReq: (proxyReq, req, res) => {
    const clientIp = req.headers['x-forwarded-for'] || req.socket.remoteAddress;
    proxyReq.setHeader('X-Forwarded-For', clientIp);
    proxyReq.setHeader('X-Real-IP', clientIp);
  },
}));

CORS Configuration

If serving API endpoints to other domains:

const cors = require('cors');

// Install: npm install cors

app.use('/analytics', cors({
  origin: ['https://yourdomain.com', 'https://www.yourdomain.com'],
  credentials: true,
}));

app.use('/analytics', createProxyMiddleware({
  // ... proxy config
}));

Troubleshooting

Requests timing out

Problem: Proxy requests hang or timeout.

Solution: Increase timeout limits:

app.use('/analytics', createProxyMiddleware({
  target: analytics-tube_HOST,
  changeOrigin: true,
  timeout: 30000, // 30 seconds
  proxyTimeout: 30000,
  pathRewrite: {
    '^/analytics': '/api',
  },
}));

Incorrect geolocation

Problem: All visitors show server's location.

Solution: Ensure IP forwarding is configured:

onProxyReq: (proxyReq, req, res) => {
  const clientIp = req.headers['x-forwarded-for'] || req.socket.remoteAddress;
  proxyReq.setHeader('X-Forwarded-For', clientIp);
  proxyReq.setHeader('X-Real-IP', clientIp);
}

Path rewriting issues

Problem: 404 errors on analytics-tube endpoints.

Solution: Check path rewriting is correct:

pathRewrite: {
  '^/analytics': '/api', // /analytics/script.js → /api/script.js
}

Debug by logging:

onProxyReq: (proxyReq, req, res) => {
  console.log('Proxying:', req.method, req.path, '→', proxyReq.path);
}