Skip to main content

Beacon Analytics Architecture

Overview

The Beacon Analytics system tracks user engagement across the Learnille marketplace. It captures impressions, clicks, and bounces for courses, consultations, instructors, and consultants to power analytics dashboards and recommendation algorithms.

Design Principles:

  • Privacy-conscious with obfuscated endpoints
  • Minimal payload size for performance
  • Resilient with fallback mechanisms
  • Deduplicated at client and server level

System Architecture

┌─────────────────────────────────────────────────────────────────┐
│ Frontend (Next.js) │
├─────────────────────────────────────────────────────────────────┤
│ BeaconWrapper │ useBounceTracker │ beacon.ts │
│ - IntersectionObserver │ - Time tracking │ - BeaconQueue │
│ - Impression on 50% │ - <10s = bounce │ - HMAC signing│
│ visibility │ - pagehide event │ - Batching │
└─────────────────────────┴──────────────────────┴────────────────┘

┌─────────▼─────────┐
│ Masked API │
│ /v1/a/s (init) │
│ /v1/a/c (batch) │
│ /v1/a/t.gif │
└─────────┬─────────┘

┌───────────────────────────────────▼─────────────────────────────┐
│ Backend (NestJS) │
├─────────────────────────────────────────────────────────────────┤
│ BeaconController │ BeaconService │ BeaconGuard │
│ - Session init │ - Token generation │ - HMAC verify │
│ - Batch processing │ - Signature verify │ - Rate limit │
│ - Pixel fallback │ - Event processing │ │
└─────────────────────────┴─────────┬───────────┴─────────────────┘

┌───────────────┼───────────────┐
▼ ▼ ▼
┌─────────┐ ┌───────────┐ ┌────────────┐
│ Redis │ │ PostgreSQL│ │ Impression │
│ - Rate │ │ - Storage │ │ Service │
│ - Dedup│ │ │ │ │
└─────────┘ └───────────┘ └────────────┘

Event Types

CodeTypeDescription
iImpressionItem visible in viewport (50%, 150ms)
kClickUser clicks on item
bBounceUser leaves detail page within 10 seconds

Entity Types

CodeEntity
cCourse
nConsultation
iInstructor
oConsultant

API Endpoints

All endpoints are intentionally obfuscated for security.

EndpointMethodPurpose
/v1/a/sGETInitialize session token
/v1/a/cPOSTCollect batch of events
/v1/a/t.gifGETPixel fallback (1x1 GIF)

Payload Structure

Session Init Response

{
"t": "session-token-jwt",
"k": "hmac-signing-key"
}

Batch Request

{
"t": "session-token",
"b": [
{
"d": "base64-encoded-payload",
"ts": 1705312345678,
"n": "random-nonce",
"sig": "hmac-sha256-signature"
}
]
}

Decoded Payload (d field)

{
"t": "c", // Entity type (course)
"e": "uuid", // Entity ID
"v": "i", // Event type (impression)
"r": "referrer", // Document referrer
"f": "fingerprint", // Browser fingerprint
"s": "session-id", // Client session ID
"ss": "search-sid", // Search session ID (optional)
"q": "query", // Search query (optional)
"rid": "result-id", // Search result ID (optional)
"val": 1, // Value (optional)
"u": "user-id" // User ID if logged in (optional)
}

Security Features

Authentication

  • Session tokens generated server-side (JWT, 24h expiry)
  • HMAC-SHA256 signing key issued per session
  • All batch requests validated by BeaconGuard

Replay Protection

  • Nonce included in each event
  • Timestamp validated (±30 second window)
  • Signature covers: payload + timestamp + nonce + token

Rate Limiting

  • 50 requests per 5 minutes per IP (Redis-backed)
  • Prevents abuse and spam events

Deduplication

  • Client-side: Cookie + sessionStorage tracking
  • Server-side: Redis with composite key (user/IP + entity + event type)
  • TTL: 30 days for cookies, session duration for storage

Data Flow

  1. Page Load

    • BeaconQueue restores session from sessionStorage
    • If no session, fetches new token from /v1/a/s
    • BeaconWrapper registers IntersectionObserver on cards
  2. Impression Tracking

    • Item becomes 50% visible for 150ms
    • trackImpression() called with entity type and ID
    • Client checks dedup (cookie/sessionStorage)
    • Event queued in BeaconQueue
  3. Batching

    • Events accumulate (max 10 or 2s timeout)
    • Each event signed with HMAC-SHA256
    • Batch sent to /v1/a/c
  4. Server Processing

    • BeaconGuard validates session token
    • BeaconService verifies each event signature
    • Checks Redis for duplicates
    • ImpressionService writes to PostgreSQL
  5. Page Unload

    • navigator.sendBeacon() flushes remaining events
    • Falls back to pixel if sendBeacon fails

Frontend Components

beacon.ts

Core tracking service with BeaconQueue class.

Key Functions:

  • trackImpression(entityType, entityId, metadata?) - Track view
  • trackClick(entityType, entityId, metadata?) - Track click
  • trackBounce(entityType, entityId) - Track early exit

BeaconQueue:

  • Manages session token lifecycle
  • Batches events with configurable thresholds
  • Signs payloads with HMAC-SHA256
  • Handles flush on page unload

BeaconWrapper.tsx

React component that wraps marketplace cards.

Props:

  • entityType - Course, consultation, etc.
  • entityId - UUID of the entity
  • metadata - Optional tracking metadata

Behavior:

  • Uses IntersectionObserver (50% threshold, 150ms delay)
  • Tracks impression when visible
  • Tracks click on interaction

useBounceTracker.ts

React hook for detail pages.

Usage:

useBounceTracker('course', course?.id);

Behavior:

  • Records page entry time
  • On pagehide/beforeunload, if < 10s elapsed, sends bounce event

Backend Components

BeaconController

NestJS controller at /v1/a.

Endpoints:

  • GET /s - Initialize session
  • POST /c - Process batch (guarded)
  • GET /t.gif - Pixel fallback

BeaconService

Core business logic.

Methods:

  • initializeSession() - Generate token + signing key
  • verifySessionToken(token) - Validate JWT
  • processBatch(dto, ip, userAgent) - Process events
  • processItem(item, ip, userAgent) - Verify and forward to ImpressionService

BeaconGuard

Request validation guard.

Checks:

  • Token presence
  • Token validity (JWT verification)
  • Rate limiting

Frontend

  • public/src/services/beacon.ts
  • public/src/components/BeaconWrapper.tsx
  • public/src/hooks/useBounceTracker.ts
  • public/src/hooks/useBeacon.ts

Pages with Tracking

  • public/src/pages/course/[slug].tsx - Course detail (impression + bounce)
  • public/src/pages/consultation/[slug]/index.tsx - Consultation detail (impression + bounce)
  • public/src/pages/instructor/[id].tsx - Instructor profile (impression + bounce)
  • public/src/pages/consultant/[id].tsx - Consultant profile (impression + bounce)

Tab Sections with Tracking

  • public/src/sections/course/Instructor.tsx - Instructor tab on course page
  • public/src/sections/consultation/Consultant.tsx - Consultant tab on consultation page

Card Collections with Tracking

  • public/src/components/instructor/SimilarInstructors.tsx - Instructor cards in swiper
  • public/src/components/consultant/SimilarConsultants.tsx - Consultant cards in swiper

Backend

  • server/src/impression/beacon.controller.ts
  • server/src/impression/beacon.service.ts
  • server/src/impression/guards/beacon.guard.ts
  • server/src/impression/dto/beacon.dto.ts
  • server/src/impression/impression.service.ts