@jillen/analytics
Version:
Advanced analytics package for Next.js applications with bot detection and comprehensive tracking
1 lines • 34.6 kB
Source Map (JSON)
{"version":3,"sources":["../analytics-constants.ts","../visitor-tracker.tsx","../server/header-parser.ts","../analytics-bot-utils.ts","../server/middleware-utils.ts","../client/index.ts","../server/index.ts"],"names":["ip","userAgent","isbot"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Analytics configuration using environment variables\n * Both server and client components use NEXT_PUBLIC_* variables for consistency\n */\nexport const ANALYTICS_CONFIG = {\n SERVER_URL: process.env.NEXT_PUBLIC_ANALYTICS_SERVER_URL || \"\",\n SITE_ID: process.env.NEXT_PUBLIC_ANALYTICS_SITE_ID || \"\",\n} as const;\n\n/**\n * Validate that required environment variables are set\n */\nexport function validateAnalyticsConfig() {\n const { SERVER_URL, SITE_ID } = ANALYTICS_CONFIG;\n \n if (!SERVER_URL || !SITE_ID) {\n console.warn(\"[Analytics] Missing environment variables:\", {\n SERVER_URL: SERVER_URL ? \"✓\" : \"✗ NEXT_PUBLIC_ANALYTICS_SERVER_URL\",\n SITE_ID: SITE_ID ? \"✓\" : \"✗ NEXT_PUBLIC_ANALYTICS_SITE_ID\"\n });\n return false;\n }\n \n return true;\n} ","\"use client\";\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport React, { useEffect, useRef, useCallback } from \"react\";\nimport { usePathname } from \"next/navigation\";\nimport { isbot } from \"isbot\";\nimport {\n ANALYTICS_CONFIG,\n validateAnalyticsConfig,\n} from \"./analytics-constants\";\n\nexport interface VisitorTrackerProps {\n ip: string;\n country: string | null;\n city: string | null;\n region: string | null;\n continent?: string | null;\n latitude?: string | null;\n longitude?: string | null;\n timezone?: string | null;\n postalCode?: string | null;\n host?: string | null;\n protocol?: \"http\" | \"https\" | null;\n deploymentUrl?: string | null;\n route: string;\n userAgent: string;\n // Optional server-side header data\n edgeRegion?: string | null;\n cacheStatus?: \"HIT\" | \"MISS\" | \"BYPASS\" | \"STALE\" | null;\n}\n\nexport function VisitorTracker({\n ip,\n country,\n city,\n region,\n continent,\n latitude,\n longitude,\n timezone,\n postalCode,\n host,\n protocol,\n deploymentUrl,\n route,\n userAgent,\n edgeRegion,\n cacheStatus,\n}: VisitorTrackerProps) {\n const pathname = usePathname();\n const isInitialized = useRef<boolean>(false);\n const lastTrackedPath = useRef<string>(route);\n\n // Check if this is a bot environment\n const checkIfBot = useCallback(() => {\n // Check server-provided user agent first\n if (isbot(userAgent)) {\n return true;\n }\n\n // Check client-side navigator user agent\n if (typeof navigator !== \"undefined\" && isbot(navigator.userAgent)) {\n return true;\n }\n\n // Additional client-side bot checks\n if (typeof window !== \"undefined\") {\n // Check for headless browser indicators\n const win = window as Window & {\n navigator?: Navigator & { webdriver?: boolean };\n phantom?: unknown;\n callPhantom?: unknown;\n __nightmare?: unknown;\n };\n if (\n win.navigator?.webdriver ||\n win.phantom ||\n win.callPhantom ||\n win.__nightmare\n ) {\n return true;\n }\n\n // Check for missing typical browser features that bots might lack\n if (!window.localStorage || !window.sessionStorage) {\n return true;\n }\n }\n\n return false;\n }, [userAgent]);\n\n // Generate consistent visitor and session IDs\n const generateVisitorId = (ip: string, userAgent: string): string => {\n const normalizedUA = userAgent.toLowerCase().replace(/\\s+/g, \"\");\n const combined = `${ip}:${normalizedUA}`;\n return btoa(combined)\n .replace(/[^a-zA-Z0-9]/g, \"\")\n .substring(0, 16);\n };\n\n const generateSessionId = (): string => {\n // Check for existing session ID in sessionStorage\n if (typeof window !== \"undefined\") {\n const existingSessionId = sessionStorage.getItem(\"analytics_session_id\");\n if (existingSessionId) {\n return existingSessionId;\n }\n }\n\n // Generate new lightweight session ID\n const generateLightweightId = (): string => {\n try {\n // Use crypto.getRandomValues() for secure randomness\n const array = new Uint8Array(4);\n crypto.getRandomValues(array);\n\n // Convert to base36 and combine with timestamp\n const timestamp = Date.now().toString(36).slice(-4); // Last 4 chars of timestamp in base36\n const randomPart = Array.from(array)\n .map((byte) => byte.toString(36))\n .join(\"\")\n .slice(0, 4); // Take first 4 chars\n\n return `${timestamp}${randomPart}`.substring(0, 8);\n } catch {\n // Fallback to Math.random() if crypto is unavailable\n const timestamp = Date.now().toString(36).slice(-4);\n const randomPart = Math.random().toString(36).substring(2, 6);\n return `${timestamp}${randomPart}`.substring(0, 8);\n }\n };\n\n const newSessionId = generateLightweightId();\n\n // Store in sessionStorage (persists across page loads, expires with browser session)\n if (typeof window !== \"undefined\") {\n try {\n sessionStorage.setItem(\"analytics_session_id\", newSessionId);\n } catch {\n // Continue without storage if sessionStorage is disabled\n }\n }\n\n return newSessionId;\n };\n\n // Get enhanced client-side data\n const getClientData = useCallback(() => {\n // SSR Guard: Return safe defaults if running on server\n if (typeof window === \"undefined\") {\n return {\n isNewVisitor: true,\n screenResolution: null,\n viewportSize: null,\n connectionType: null,\n clientTimeZone: null,\n sessionStartTime: new Date().toISOString(),\n };\n }\n\n // Check if this is a new visitor using session-level caching\n const visitorId = generateVisitorId(ip, userAgent);\n const sessionId = generateSessionId();\n const sessionCacheKey = `isNewVisitor_${sessionId}`;\n\n // Check if we already determined isNewVisitor for this session\n const cachedIsNewVisitor = sessionStorage.getItem(sessionCacheKey);\n let isNewVisitor: boolean;\n\n if (cachedIsNewVisitor === null) {\n // First event in this session - make the determination\n const visitorExists = localStorage.getItem(\n `analytics_visitor_${visitorId}`\n );\n isNewVisitor = !visitorExists;\n\n // Cache the decision for this entire session\n sessionStorage.setItem(sessionCacheKey, isNewVisitor.toString());\n\n // Mark visitor as seen for future sessions (only if they're new)\n if (isNewVisitor) {\n localStorage.setItem(\n `analytics_visitor_${visitorId}`,\n Date.now().toString()\n );\n }\n } else {\n // Use the cached decision from earlier in this session\n isNewVisitor = cachedIsNewVisitor === \"true\";\n }\n\n // Get session start time (persistent for this session)\n // Note: reusing sessionId from above\n let sessionStartTime = localStorage.getItem(\n `analytics_session_start_${sessionId}`\n );\n if (!sessionStartTime) {\n sessionStartTime = new Date().toISOString();\n localStorage.setItem(\n `analytics_session_start_${sessionId}`,\n sessionStartTime\n );\n }\n\n // Get screen and viewport data (safe now that we're client-side)\n const screenResolution = `${screen.width}x${screen.height}`;\n const viewportSize = `${window.innerWidth}x${window.innerHeight}`;\n\n // Get connection type (if available)\n const connectionType = (() => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const nav = navigator as any;\n return (\n nav.connection?.effectiveType || nav.connection?.type || \"unknown\"\n );\n } catch {\n return \"unknown\";\n }\n })();\n\n // Get client timezone\n const clientTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;\n\n return {\n isNewVisitor,\n screenResolution,\n viewportSize,\n connectionType,\n clientTimeZone,\n sessionStartTime,\n };\n }, [ip, userAgent]);\n\n // Send event to analytics system\n const sendAnalyticsEvent = useCallback(\n async (\n eventType: \"pageview\" | \"session_start\",\n referrer?: string,\n customPath?: string\n ) => {\n // Only run in production (temporarily disabled for debugging)\n if (process.env.NODE_ENV !== \"production\" && false) {\n return;\n }\n\n // Validate configuration\n if (!validateAnalyticsConfig()) {\n return;\n }\n\n const serverUrl = ANALYTICS_CONFIG.SERVER_URL;\n const siteId = ANALYTICS_CONFIG.SITE_ID;\n\n const endpoint = `${serverUrl}/api/log/ingest`;\n\n // Extract standard client-side data with SSR guards\n const language =\n typeof navigator !== \"undefined\"\n ? navigator.language || navigator.languages?.[0] || undefined\n : undefined;\n const doNotTrack =\n typeof navigator !== \"undefined\" ? navigator.doNotTrack === \"1\" : false;\n const isMobile =\n typeof navigator !== \"undefined\"\n ? /Mobi|Android/i.test(navigator.userAgent)\n : /Mobi|Android/i.test(userAgent); // Fallback to server userAgent\n\n // Get enhanced client data\n const clientData = getClientData();\n\n // Simulate development data when running locally\n const isDev = process.env.NODE_ENV === \"development\";\n const devCountry = isDev && !country ? \"US\" : country;\n const devCity = isDev && !city ? \"San Francisco\" : city;\n const devRegion = isDev && !region ? \"CA\" : region;\n const devEdgeRegion = isDev && !edgeRegion ? \"sfo1\" : edgeRegion;\n\n try {\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n mode: \"cors\",\n body: JSON.stringify({\n siteId,\n path: customPath || route,\n visitorId: generateVisitorId(ip, userAgent),\n sessionId: generateSessionId(),\n eventType,\n // Enhanced client-side fields\n isNewVisitor: clientData.isNewVisitor,\n screenResolution: clientData.screenResolution,\n viewportSize: clientData.viewportSize,\n connectionType: clientData.connectionType,\n clientTimeZone: clientData.clientTimeZone,\n sessionStartTime: clientData.sessionStartTime,\n // Server-side fields\n ipAddress: ip,\n userAgent,\n referrer,\n country: devCountry || undefined,\n city: devCity || undefined,\n region: devRegion || undefined,\n continent: continent || undefined,\n latitude: latitude ? parseFloat(latitude) : undefined,\n longitude: longitude ? parseFloat(longitude) : undefined,\n timezone: timezone || undefined,\n postalCode: postalCode || undefined,\n host: host || undefined,\n protocol: protocol || undefined,\n deploymentUrl: deploymentUrl || undefined,\n edgeRegion: devEdgeRegion || undefined,\n language,\n doNotTrack,\n isMobile,\n cacheStatus: cacheStatus || \"UNKNOWN\",\n }),\n });\n\n if (!response.ok) {\n const error = await response.json();\n console.error(\"[Analytics] Failed to track event:\", error);\n }\n } catch (error) {\n // Silent error handling - don't block the page\n console.error(\"[Analytics] Tracking failed:\", error);\n }\n },\n [\n ip,\n country,\n city,\n region,\n continent,\n latitude,\n longitude,\n timezone,\n postalCode,\n host,\n protocol,\n deploymentUrl,\n route,\n userAgent,\n edgeRegion,\n cacheStatus,\n getClientData,\n ]\n );\n\n // Track session start, pageview and setup session end\n useEffect(() => {\n // SSR Guard: Only run on client\n if (typeof window === \"undefined\") return;\n\n // Only track in production environment\n const isProduction =\n process.env.NEXT_PUBLIC_VERCEL_ENV === \"production\" ||\n (process.env.NODE_ENV === \"production\" &&\n !process.env.NEXT_PUBLIC_VERCEL_ENV);\n\n if (!isProduction) {\n return;\n }\n\n // Check if this is a bot - if so, skip all client-side tracking\n if (checkIfBot()) {\n return;\n }\n\n const currentPath = pathname || route;\n\n // Initial setup on first load\n if (!isInitialized.current) {\n isInitialized.current = true;\n\n const sessionId = generateSessionId();\n const sessionKey = `analytics_session_active_${sessionId}`;\n const isSessionActive = localStorage.getItem(sessionKey);\n\n // Send session_start if this is a new session\n if (!isSessionActive) {\n sendAnalyticsEvent(\"session_start\", undefined, currentPath);\n localStorage.setItem(sessionKey, \"true\");\n }\n\n // Track initial pageview\n const referrer =\n document.referrer && document.referrer.length > 0\n ? document.referrer\n : undefined;\n sendAnalyticsEvent(\"pageview\", referrer, currentPath);\n lastTrackedPath.current = currentPath;\n\n // No cleanup needed - sessions end naturally through timeout logic\n }\n // Handle route changes (client-side navigation)\n else if (currentPath !== lastTrackedPath.current) {\n // Track pageview for route change\n sendAnalyticsEvent(\"pageview\", undefined, currentPath);\n lastTrackedPath.current = currentPath;\n }\n\n // Return undefined for useEffect when no cleanup is needed\n return;\n }, [\n pathname,\n route,\n ip,\n country,\n city,\n region,\n continent,\n latitude,\n longitude,\n timezone,\n postalCode,\n host,\n protocol,\n deploymentUrl,\n userAgent,\n edgeRegion,\n cacheStatus,\n sendAnalyticsEvent,\n getClientData,\n checkIfBot,\n ]); // Re-run if pathname or route changes\n\n return null; // This component renders nothing\n}\n","/**\n * Server-side utility to parse analytics data from Next.js headers\n */\n\nexport interface ParsedAnalyticsHeaders {\n ip: string;\n country: string | null;\n city: string | null;\n region: string | null;\n continent: string | null;\n latitude: string | null;\n longitude: string | null;\n timezone: string | null;\n postalCode: string | null;\n host: string | null;\n protocol: \"http\" | \"https\" | null;\n deploymentUrl: string | null;\n userAgent: string;\n edgeRegion: string | null;\n cacheStatus: \"HIT\" | \"MISS\" | \"BYPASS\" | \"STALE\" | null;\n}\n\nexport function parseAnalyticsHeaders(headers: Headers): ParsedAnalyticsHeaders {\n const ip = headers.get(\"x-forwarded-for\") || headers.get(\"x-real-ip\") || \"unknown\";\n const country = headers.get(\"x-vercel-ip-country\") || null;\n const userAgent = headers.get(\"user-agent\") || \"\";\n const city = headers.get(\"x-vercel-ip-city\") || null;\n const region = headers.get(\"x-vercel-ip-country-region\") || null;\n const continent = headers.get(\"x-vercel-ip-continent\") || null;\n const latitude = headers.get(\"x-vercel-ip-latitude\") || null;\n const longitude = headers.get(\"x-vercel-ip-longitude\") || null;\n const timezone = headers.get(\"x-vercel-ip-timezone\") || null;\n const postalCode = headers.get(\"x-vercel-ip-postal-code\") || null;\n const host = headers.get(\"host\") || null;\n const protocol = headers.get(\"x-forwarded-proto\") as \"http\" | \"https\" | null;\n const deploymentUrl = headers.get(\"x-vercel-deployment-url\") || null;\n const vercelId = headers.get(\"x-vercel-id\") || null;\n\n // Extract edge region from x-vercel-id\n const edgeRegion = vercelId ? vercelId.split(\"::\")[0] : null;\n const cacheStatus = null; // This would need to be determined differently\n\n return {\n ip,\n country,\n city,\n region,\n continent,\n latitude,\n longitude,\n timezone,\n postalCode,\n host,\n protocol,\n deploymentUrl,\n userAgent,\n edgeRegion,\n cacheStatus,\n };\n} ","import type { NextRequest } from 'next/server';\nimport { ANALYTICS_CONFIG, validateAnalyticsConfig } from './analytics-constants';\n\n/**\n * Simplified Bot Tracking Utility\n * \n * Fire-and-forget bot tracking with minimal data collection.\n * Designed for performance and reliability - no complex calculations.\n */\n\n// Simple hash generation for bot IDs (no complex session windows)\nfunction generateSimpleBotVisitorId(ip: string, userAgent: string): string {\n const normalizedUA = userAgent.toLowerCase().replace(/\\s+/g, \"\");\n const combined = `bot:${ip}:${normalizedUA}`;\n return Buffer.from(combined)\n .toString(\"base64\")\n .replace(/[^a-zA-Z0-9]/g, \"\")\n .substring(0, 16);\n}\n\nfunction generateSimpleBotSessionId(ip: string): string {\n const today = new Date().toISOString().split('T')[0]; // YYYY-MM-DD\n const combined = `bot-session:${ip}:${today}`;\n return Buffer.from(combined)\n .toString(\"base64\")\n .replace(/[^a-zA-Z0-9]/g, \"\")\n .substring(0, 16);\n}\n\n/**\n * Track bot visit with minimal data collection\n * Fire-and-forget: does not throw errors or block execution\n */\nexport function trackBotVisit(request: NextRequest, pathname: string): void {\n // Fire-and-forget: run async without awaiting\n void (async () => {\n try {\n // Validate configuration\n if (!validateAnalyticsConfig()) {\n return;\n }\n\n const serverUrl = ANALYTICS_CONFIG.SERVER_URL;\n const siteId = ANALYTICS_CONFIG.SITE_ID;\n\n // Extract essential bot data\n const userAgent = request.headers.get('user-agent') || '';\n const ip = request.headers.get('x-forwarded-for')?.split(',')[0] || \n request.headers.get('x-real-ip') || \n 'unknown';\n\n // Generate minimal required IDs\n const visitorId = generateSimpleBotVisitorId(ip, userAgent);\n const sessionId = generateSimpleBotSessionId(ip);\n\n // Prepare minimal bot payload\n const botPayload = {\n // Required fields (minimal values)\n siteId,\n path: pathname,\n visitorId,\n sessionId,\n eventType: \"pageview\" as const,\n \n // Essential bot data\n userAgent,\n ipAddress: ip,\n \n // Client-side fields (bots don't have these)\n isNewVisitor: true,\n screenResolution: null,\n viewportSize: null,\n connectionType: null,\n clientTimeZone: null,\n sessionStartTime: new Date().toISOString(),\n \n // Optional server fields (skip expensive lookups)\n referrer: request.headers.get('referer') || null,\n country: null,\n city: null,\n region: null,\n continent: null,\n latitude: null,\n longitude: null,\n timezone: null,\n postalCode: null,\n host: request.headers.get('host') || null,\n protocol: request.headers.get('x-forwarded-proto') as \"http\" | \"https\" || null,\n deploymentUrl: null,\n edgeRegion: null,\n language: null,\n doNotTrack: false,\n isMobile: /Mobi|Android/i.test(userAgent),\n cacheStatus: \"UNKNOWN\" as const,\n };\n\n // Send to analytics server (fire-and-forget)\n const endpoint = `${serverUrl}/api/log/ingest`;\n \n await fetch(endpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n mode: 'cors',\n body: JSON.stringify(botPayload),\n });\n\n } catch {\n // Silent fail - do not log errors or throw exceptions\n // Bot tracking should never break the application\n return;\n }\n })();\n} ","import type { NextRequest } from 'next/server';\nimport { isbot } from 'isbot';\nimport { trackBotVisit } from '../analytics-bot-utils';\n\n/**\n * Combined middleware utility for analytics\n * Handles both pathname header injection and bot tracking\n */\nexport function setupAnalyticsMiddleware(request: NextRequest) {\n // Extract pathname from URL\n const pathname = request.nextUrl.pathname;\n \n // Clone headers and add pathname\n const headers = new Headers(request.headers);\n headers.set('x-pathname', pathname);\n \n // Track bot visits if this is a bot\n const userAgent = request.headers.get('user-agent') || '';\n if (isbot(userAgent)) {\n trackBotVisit(request, pathname);\n }\n \n return {\n headers,\n pathname\n };\n} ","// Client-side analytics components\nexport { VisitorTracker, type VisitorTrackerProps } from '../visitor-tracker'; ","// Server-side analytics utilities\nexport { setupAnalyticsMiddleware } from './middleware-utils';\nexport { parseAnalyticsHeaders } from './header-parser';\nexport { trackBotVisit } from '../analytics-bot-utils'; "]}