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
| Feature | For Builders | For Users |
|---|---|---|
| Event Tracking | Understand how users interact with your app | β |
| Error Monitoring | Catch and fix errors before users report them | Report context when crashes happen |
| Feature Flags | Gradually roll out features, run A/B tests | Get the right experience for them |
| Translations | Manage multi-language support with LLM-powered suggestions | Use apps in their native language |
| Feedback | Hear directly from users, respond, prioritise | Submit bugs, request features, get responses |
| Theming | Offer customisable visual experiences | Create and share custom themes |
| App Analysis | Automated testing and competitive analysis | β |
Core Principles
- 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.
- 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. - Design system native β Tracking integrates directly with
@shellapps/react-uicomponents viadata-tattributes. Theming lives in the platform. The design system and experience platform are deeply connected. - UI-first management β Translations, feature flags, themes, and feedback are all managed through the Experience dashboard. No config files, no CLI-only workflows.
- 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
| Repo | Purpose | Tech |
|---|---|---|
experience-service | Core backend service | Express/TS, port 3030, MongoDB |
experience.shellapps.com | Dashboard UI | Next.js |
shellapps-js/packages/experience | Vanilla JS SDK | TypeScript, protobuf |
shellapps-js/packages/experience-react | React SDK | React, hooks, providers |
shellapps-js/packages/experience-proto | Shared 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 profilesQuick 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-react3. 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-telements - β 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 Type | Size Per Event | 90-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
| Phase | Scope | Milestone |
|---|---|---|
| 1: Core | Service, protobuf, event + error ingest, SDKs | Track events and capture errors |
| 2: Intelligence | Feature flags, translations, feedback | Full feature set via API |
| 3: Dashboard | Experience dashboard UI | UI management |
| 4: Advanced | Theming + theme store, app analysis | Full platform |
| 5: Integration | Replace Sentry, integrate all apps | All ShellApps on Experience |
| 6: Documentation | Comprehensive docs | Ready for external developers |