Personalization Flow
Overview
The personalization feature captures user preferences during registration and sends analytics events to the Mercury API, enhancing the user experience and facilitating data collection.
For reference to the old personalization flow in the monolith implementation, see: Personalization Feature Monolith
Personalization Flow Steps
The personalization flow is integrated into the existing registration process:
- Entry: User comes from the monolith registration
(
/register/account-completion) - Steps 1-4: User navigates through personalization questions
- /registration/personalization/account-purpose
- /registration/personalization/industries
- /registration/personalization/topics
- /registration/personalization/data-preferences
- Child steps
- /registration/personalization/account-purpose/ai is shown when the option q_001_i_006 from account-purpose step is selected
- Exit: Redirect to the monolith completion (
/register/account-completed)
Each personalization flow step is a question with a possibility for a user to select multiple options. If none of the options were selected we show an error message, making it mandatory for a user to select something. After the user selects an option its possible to submit selected state and move to a next step.
Technical implementation
The implementation consists of several key architectural components:
- Single Route Component: A unified
personalization.$step/($childStep)/route.tsxthat handles all four steps including child steps - In-Memory State Management: React state that persists during navigation between steps
- Static Data Structure: Server-side configuration defining step content and flow
- Event-Driven Analytics: Mercury integration for tracking user interactions
- Remix-based Server Actions: Server-side validation and navigation logic
Dynamic routing
The personalization flow uses Remix's dynamic routing with a single parameterized route:
- Route pattern:
/registration/personalization/:step/($childStep) - Step slugs:
account-purpose,industries,topics,data-preferences - Child step slugs:
account-purpose/ai - A single component handles all steps via URL parameter changes
The step is resolved from the URL parameter rendered based on the step configuration properties.
The personalization steps are defined as static data in
personalization.$step/data.server.ts. Each step is imported from
individual data files (e.g., data/account-purpose.ts,
data/industries.ts) and exported as a function which returns an array of
steps with conditional child steps based on different unleash feature toggles.
Each step includes:
- A unique
slug(e.g.,account-purpose,industries,topics,data-preferences,account-purpose/ai) that corresponds to the URL parameter - Step metadata (id, type, title, description, error messages)
- A
renderTypeproperty that determines the UI rendering approach
The slug serves as the URL parameter in the route pattern
/registration/personalization/:step/($childStep) and is used to match the current
step from the getPersonalizationSteps function.
UI Element Rendering Decision Mechanism
UI elements are conditionally rendered based on:
Render Type:
renderType: "cards"→ Renders card-based selection UIrenderType: "tags"→ Renders tag-based selection UI
State Management Mechanism
The personalization flow implements a session-scoped state management system that maintains user selections across all four steps without persisting data beyond the active browser session.
The state management approach was carefully evaluated and documented in State Management for Personalization Flow, where multiple approaches were considered before selecting the Parameterized Route State pattern.
Core Implementation Strategy:
useStatehook is used within the route component (personalization.$step/route.tsx)- State remains intact during navigation between personalization steps because the same component instance handles all steps
- State is automatically cleared when the user closes the tab, refreshes the page, or navigates away from the personalization flow
Form Submission and Server Integration
- Selected options are serialized as JSON in hidden form fields
- Server actions receive and parse selected options data
- Data are sent to Mercury through the mercury service
Mercury integration
What is Mercury
Mercury is Statista's centralized event streaming platform built on Apache Kafka that serves as the backbone for real-time data collection and analytics across the organization. It functions as an event-bus system that enables applications to publish structured events for data pipelines, analytics systems, and other services.
In the context of the personalization flow, Mercury serves several critical functions:
- Data Collection: Captures user interaction events during the personalization flow
- Analytics Foundation: Provides structured data for user behavior analysis and personalization algorithms
- Backend Replacement: As for now, it replaces saving the data to a database, and this part would be added in future iterations
What is Mercury event
All events sent through the mercury event pipeline must conform to a standardized envelope structure. The envelope consists of three main sections:
event_header: Required metadata for identification, context, and correlation.
metadata: Additional technical details about the schema and source.
payload: The dynamic and flexible core of the event, containing business-specific
data.
If you want to find out more about the event structure, see here: https://statista.atlassian.net/wiki/spaces/DA/pages/4596171049/Schema+of+mercury+events
Mercury events in personalization flow
Each step in the Personalization flow can send following events:
- Backwards step event: triggered when user clicks the "Back" button
- Complete step event: triggered when user clicks the "Submit button"
Backwards step event payload
The backwards step event is triggered when a user clicks the "Back" button during the personalization flow.
For the complete payload structure and property descriptions, see
BackwardStepPayload type in:
app/services/personalization-events/send-backward-step-event.server.ts
Complete step event payload
The complete step event is triggered when a user clicks the "Submit" button to complete a step in the personalization flow.
For the complete payload structure and property descriptions, see
CompleteStepPayload type in:
app/services/personalization-events/send-complete-step-event.server.ts
Topic name
Events are sent to Mercury using environment-specific topic names following
the pattern:
{env}.{domain}.{entity}.{entity_class}.{schema_version}
Example:
Production: prod.user-profile.onboarding.user-interests.v1
Staging: stage.user-profile.onboarding.user-interests.v1
Development: dev.user-profile.onboarding.user-interests.v1
Mercury Technical Implementation
The personalization flow utilizes the Mercury service to send events to Mercury.
Core Components
1. Mercury Service (app/services/mercury/mercury.server.ts)
- Singleton service providing a generic
sendEventmethod - Handles event structure validation and topic name construction
- Manages HTTP communication with Mercury's Kafka REST API
- Implements error handling and logging
- Formats events according to Kafka record structure
2. Mercury Service Factory (app/services/create-mercury.server.ts)
- Factory function for creating Mercury service instances
3. Event Helper Functions (app/services/personalization-events/)
send-backward-step-event.server.ts: Handles backward navigation eventssend-complete-step-event.server.ts: Handles step completion events- Each function formats event-specific data and calls the Mercury service
- Both use the common
createPersonalizationEventhelper for standardization