Skip to content

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:

  1. Entry: User comes from the monolith registration (/register/account-completion)
  2. Steps 1-4: User navigates through personalization questions
    • /registration/personalization/account-purpose
    • /registration/personalization/industries
    • /registration/personalization/topics
    • /registration/personalization/data-preferences
  3. Child steps
    • /registration/personalization/account-purpose/ai is shown when the option q_001_i_006 from account-purpose step is selected
  4. 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:

  1. Single Route Component: A unified personalization.$step/($childStep)/route.tsx that handles all four steps including child steps
  2. In-Memory State Management: React state that persists during navigation between steps
  3. Static Data Structure: Server-side configuration defining step content and flow
  4. Event-Driven Analytics: Mercury integration for tracking user interactions
  5. 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 renderType property 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 UI
  • renderType: "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:

  • useState hook 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:

  1. Data Collection: Captures user interaction events during the personalization flow
  2. Analytics Foundation: Provides structured data for user behavior analysis and personalization algorithms
  3. 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:

  1. Backwards step event: triggered when user clicks the "Back" button
  2. 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 sendEvent method
  • 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 events
  • send-complete-step-event.server.ts: Handles step completion events
  • Each function formats event-specific data and calls the Mercury service
  • Both use the common createPersonalizationEvent helper for standardization