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
| Code | Type | Description |
|---|---|---|
i | Impression | Item visible in viewport (50%, 150ms) |
k | Click | User clicks on item |
b | Bounce | User leaves detail page within 10 seconds |
Entity Types
| Code | Entity |
|---|---|
c | Course |
n | Consultation |
i | Instructor |
o | Consultant |
API Endpoints
All endpoints are intentionally obfuscated for security.
| Endpoint | Method | Purpose |
|---|---|---|
/v1/a/s | GET | Initialize session token |
/v1/a/c | POST | Collect batch of events |
/v1/a/t.gif | GET | Pixel 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
-
Page Load
- BeaconQueue restores session from sessionStorage
- If no session, fetches new token from
/v1/a/s - BeaconWrapper registers IntersectionObserver on cards
-
Impression Tracking
- Item becomes 50% visible for 150ms
trackImpression()called with entity type and ID- Client checks dedup (cookie/sessionStorage)
- Event queued in BeaconQueue
-
Batching
- Events accumulate (max 10 or 2s timeout)
- Each event signed with HMAC-SHA256
- Batch sent to
/v1/a/c
-
Server Processing
- BeaconGuard validates session token
- BeaconService verifies each event signature
- Checks Redis for duplicates
- ImpressionService writes to PostgreSQL
-
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 viewtrackClick(entityType, entityId, metadata?)- Track clicktrackBounce(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 entitymetadata- 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 sessionPOST /c- Process batch (guarded)GET /t.gif- Pixel fallback
BeaconService
Core business logic.
Methods:
initializeSession()- Generate token + signing keyverifySessionToken(token)- Validate JWTprocessBatch(dto, ip, userAgent)- Process eventsprocessItem(item, ip, userAgent)- Verify and forward to ImpressionService
BeaconGuard
Request validation guard.
Checks:
- Token presence
- Token validity (JWT verification)
- Rate limiting
Related Files
Frontend
public/src/services/beacon.tspublic/src/components/BeaconWrapper.tsxpublic/src/hooks/useBounceTracker.tspublic/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 pagepublic/src/sections/consultation/Consultant.tsx- Consultant tab on consultation page
Card Collections with Tracking
public/src/components/instructor/SimilarInstructors.tsx- Instructor cards in swiperpublic/src/components/consultant/SimilarConsultants.tsx- Consultant cards in swiper
Backend
server/src/impression/beacon.controller.tsserver/src/impression/beacon.service.tsserver/src/impression/guards/beacon.guard.tsserver/src/impression/dto/beacon.dto.tsserver/src/impression/impression.service.ts