Experience Platform
Overview

Experience Platform

The Experience Platform is ShellApps' unified developer and user experience toolkit. It provides everything an app builder needs to understand, improve, and manage the experience of their application β€” all under one platform, one identity, one dashboard.

What It Provides

FeatureFor BuildersFor Users
Event TrackingUnderstand how users interact with your appβ€”
Error MonitoringCatch and fix errors before users report themReport context when crashes happen
Feature FlagsGradually roll out features, run A/B testsGet the right experience for them
TranslationsManage multi-language support with LLM-powered suggestionsUse apps in their native language
FeedbackHear directly from users, respond, prioritiseSubmit bugs, request features, get responses
ThemingOffer customisable visual experiencesCreate and share custom themes
App AnalysisAutomated testing and competitive analysisβ€”

Core Principles

  1. Protobuf-first for high-throughput β€” Event tracking and error monitoring use Protocol Buffers for minimal payload size and maximum ingest throughput. JSON fallbacks exist for debugging.
  2. SDK-driven integration β€” Apps install @shellapps/experience (vanilla JS) or @shellapps/experience-react (React) and get auto-tracking, error capture, and feature flags with minimal code.
  3. Design system native β€” Tracking integrates directly with @shellapps/react-ui components via data-t attributes. Theming lives in the platform. The design system and experience platform are deeply connected.
  4. UI-first management β€” Translations, feature flags, themes, and feedback are all managed through the Experience dashboard. No config files, no CLI-only workflows.
  5. One identity β€” Everything is tied to ShellApps ID. Profiles, permissions, and groups carry through.

Architecture

High-Level System Diagram

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        Client Applications                          β”‚
β”‚                                                                     β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚ auth.shellapps    β”‚  β”‚ monet.live       β”‚  β”‚ thoughtstorm     β”‚  β”‚
β”‚  β”‚                   β”‚  β”‚                   β”‚  β”‚                   β”‚  β”‚
β”‚  β”‚ @shellapps/       β”‚  β”‚ @shellapps/       β”‚  β”‚ @shellapps/       β”‚  β”‚
β”‚  β”‚ experience-react  β”‚  β”‚ experience-react  β”‚  β”‚ experience-react  β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚           β”‚                      β”‚                      β”‚           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            β”‚     protobuf/JSON    β”‚                      β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                   β”‚
                                   β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Experience Service (port 3030)                    β”‚
β”‚                                                                     β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚ Event      β”‚ β”‚ Error      β”‚ β”‚ Feature    β”‚ β”‚ Translation    β”‚  β”‚
β”‚  β”‚ Ingest     β”‚ β”‚ Ingest     β”‚ β”‚ Flag       β”‚ β”‚ Engine         β”‚  β”‚
β”‚  β”‚            β”‚ β”‚            β”‚ β”‚ Engine     β”‚ β”‚                β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚        β”‚              β”‚              β”‚                β”‚           β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚ Feedback   β”‚ β”‚ Theme      β”‚ β”‚ App        β”‚ β”‚ Query /       β”‚  β”‚
β”‚  β”‚ System     β”‚ β”‚ Service    β”‚ β”‚ Analysis   β”‚ β”‚ Aggregation   β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚        β”‚              β”‚              β”‚                β”‚           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚              β”‚              β”‚                β”‚
         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                β”‚
                        β–Ό                               β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                      β”‚
              β”‚    MongoDB       β”‚β—„β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              β”‚                  β”‚
              β”‚  - events (TS)   β”‚
              β”‚  - errors        β”‚
              β”‚  - flags         β”‚
              β”‚  - translations  β”‚
              β”‚  - feedback      β”‚
              β”‚  - themes        β”‚
              β”‚  - analysis      β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Repos

RepoPurposeTech
experience-serviceCore backend serviceExpress/TS, port 3030, MongoDB
experience.shellapps.comDashboard UINext.js
shellapps-js/packages/experienceVanilla JS SDKTypeScript, protobuf
shellapps-js/packages/experience-reactReact SDKReact, hooks, providers
shellapps-js/packages/experience-protoShared protobuf definitions.proto files

Integration with Existing ShellApps

auth.shellapps.com ◄──── User login returns session with:
       β”‚                  - User data
       β”‚                  - Active profile
       β”‚                  - Resolved feature flags (from Experience)
       β”‚                  - Theme preference (from Experience)
       β”‚                  - Locale preference
       β”‚
       β–Ό
  Consumer App ────► Experience Service
                     - Sends events (protobuf)
                     - Sends errors (protobuf)
                     - Receives flag updates (SSE)
                     - Fetches translations (REST + cache)
                     - Submits feedback (REST)

Dashboard Navigation

experience.shellapps.com
β”œβ”€β”€ / ........................ Overview dashboard
β”œβ”€β”€ /analytics ............... Event analytics
β”‚   β”œβ”€β”€ /analytics/pages ..... Page view stats
β”‚   β”œβ”€β”€ /analytics/events .... Custom events
β”‚   β”œβ”€β”€ /analytics/heatmaps .. Heatmap viewer
β”‚   β”œβ”€β”€ /analytics/flows ..... User flow diagrams
β”‚   └── /analytics/sessions .. Session replay
β”œβ”€β”€ /errors .................. Error explorer
β”‚   β”œβ”€β”€ /errors/:id .......... Error group detail
β”‚   └── /errors/trends ....... Error rate trends
β”œβ”€β”€ /flags ................... Feature flags
β”‚   β”œβ”€β”€ /flags/new ........... Create flag
β”‚   β”œβ”€β”€ /flags/:id ........... Flag detail + rules
β”‚   └── /flags/experiments ... Experiment results
β”œβ”€β”€ /translations ............ Translation management
β”‚   β”œβ”€β”€ /translations/:locale  Per-locale editor
β”‚   └── /translations/config . Language configuration
β”œβ”€β”€ /feedback ................ Feedback inbox
β”‚   └── /feedback/:id ........ Thread view
β”œβ”€β”€ /themes .................. Theme management
β”‚   β”œβ”€β”€ /themes/builder ...... Theme builder/editor
β”‚   └── /themes/store ........ Theme store
└── /analysis ................ App analysis
    β”œβ”€β”€ /analysis/scans ...... Scan results
    └── /analysis/profiles ... App profiles

Quick Start

Add Experience to a Next.js ShellApp in 5 minutes:

1. Register your app

curl -X POST https://experience.shellapps.com/api/v1/apps/register \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "My App"}'
 
# Response: { "appId": "abc123", "apiKey": "exp_xxxxxxxxxxxx" }

2. Install SDKs

npm install @shellapps/experience @shellapps/experience-react

3. Add Provider

import { ExperienceProvider, ErrorBoundary, FeedbackButton } from '@shellapps/experience-react';
 
export default function Providers({ children, profileId }) {
  return (
    <ExperienceProvider
      appId="abc123"
      apiKey="exp_xxxxxxxxxxxx"
      profileId={profileId}
    >
      <ErrorBoundary showCommentForm>
        {children}
      </ErrorBoundary>
      <FeedbackButton position="bottom-right" />
    </ExperienceProvider>
  );
}

4. Add tracking to key elements

<Button trackingId="signup-cta" variant="primary">
  Sign Up Free
</Button>
 
<a data-t="nav-pricing" href="/pricing">Pricing</a>

5. Use feature flags

const showBanner = useFlag('welcome-banner', true);
 
{showBanner && <WelcomeBanner />}

6. Add translations

const { t } = useTranslation();
 
<h1>{t('home.title')}</h1>

That's it. You now have:

  • βœ… Automatic page view tracking
  • βœ… Automatic error capture with breadcrumbs
  • βœ… Click/hover tracking on data-t elements
  • βœ… Crash UI with user comment
  • βœ… Feature flags
  • βœ… Translations
  • βœ… Feedback widget

Design Decisions

Why Protobuf for Event/Error Ingest?

Event tracking and error monitoring generate high volumes of data. JSON payloads are verbose and expensive to parse at scale. Protocol Buffers provide ~60-80% smaller payloads, faster serialization, and schema-enforced validation. JSON fallback endpoints exist for development/debugging.

Why Pre-Computed Flag Sets?

Evaluating flag rules on every request is expensive (N flags Γ— M rules Γ— K conditions). Instead, resolved flags are pre-computed per profile when a flag changes. Flag reads become a single DB lookup. Trade-off: propagation delay on flag changes, mitigated by SSE stream for real-time updates.

Why LLM Translations?

Traditional machine translation lacks context about the app, its terminology, and voice. The Norman engine (LLM) provides context-aware translations, handles interpolation variables naturally, and maintains consistent voice. Translation memory reduces costs.

Why data-t Instead of Auto-Tracking Everything?

Auto-tracking every click generates overwhelming noise. data-t attributes provide intentional, developer-controlled tracking with signal over noise. Integrates with design system components via trackingId prop.


Security Model

API Keys

  • App API keys (exp_xxxxxxxxxxxx) for SDK-to-service communication
  • Keys hashed in database (bcrypt) β€” only prefix stored plaintext
  • Rotatable without downtime (old key valid for 24h after rotation)
  • Rate limited per key: default 10,000 events/minute

Data Isolation

  • All data scoped to appId β€” no cross-app data access
  • Dashboard access requires Bearer token + app ownership/membership
  • SDK ingest only accepts events matching the API key's app

User Privacy

  • Heatmap data aggregated, not stored per-user
  • Error user comments are opt-in
  • Respects browser Do Not Track header
  • Configurable data retention (default 90 days events, 30 days heatmaps)

Scaling

Target: 100,000 events/second across all apps.

Data TypeSize Per Event90-Day Retention (1M events/day)
Track event~200 bytes~18 GB
Heatmap event~50 bytes~4.5 GB (30-day)
Error event~2 KB~180 GB

Strategy: Protobuf encoding, batch processing, async writes, MongoDB time-series collections, TTL indexes, horizontal scaling. Future migration path to ClickHouse for very high-volume deployments.

Migration Plan

PhaseScopeMilestone
1: CoreService, protobuf, event + error ingest, SDKsTrack events and capture errors
2: IntelligenceFeature flags, translations, feedbackFull feature set via API
3: DashboardExperience dashboard UIUI management
4: AdvancedTheming + theme store, app analysisFull platform
5: IntegrationReplace Sentry, integrate all appsAll ShellApps on Experience
6: DocumentationComprehensive docsReady for external developers

Β© 2026 Shell Technology. All rights reserved.