Vite + React example for Split / Harness FME with OpenFeature: two named clients (anon-web, user-web) on one page.
Repository: github.com/Split-Community/react-openfeature-multiple-clients
Uses the Harness OpenFeature provider for React (@splitsoftware/openfeature-web-split-provider + @splitsoftware/splitio-browserjs).
src/main.tsx runs bootstrapOpenFeature() before createRoot(…).render so three problems do not show up on first paint:
-
Provider readiness — Until Split finishes initializing, OpenFeature can be
NOT_READYand flag hooks error.setProviderAndWaitwaits for each domain provider before the UI mounts. -
Domain context timing —
useContextMutator().setContextruns inuseEffect, which is after the first render. If you read flags immediately, OpenFeature may log “Unable to find context” foranon-web/user-weband evaluations can misbehave. Bootstrap callsOpenFeature.setContext(domain, …)up front so context exists before any hook runs. -
Efficient resource usage — The app creates one shared Split factory and registers two OpenFeature providers (one per domain) that share it. When context changes via
setContext({ targetingKey: newUserId }), the provider internally callsfactory.client(newUserId)to get the appropriate Split client. This avoids duplicating network connections, caches, and storage.
- One
SplitFactoryshared by multiple providers (efficient) - Two OpenFeature domains for simultaneous evaluation of different users
- Static context (anonymous) set once in bootstrap
- Dynamic context (user) updated via
setContext()when user ID changes
What to avoid:
- Creating multiple
SplitFactoryinstances (wastes resources: 2x network, memory, storage) - Using
setContext()in React for static values already set in bootstrap (unnecessary) - Forgetting that
factory.client(key)shares the factory infrastructure efficiently
| Scenario | Approach | Example |
|---|---|---|
| Static user key (won't change) | Set in bootstrap only | Anonymous users always with key ”anonymous” |
| Dynamic user key (changes at runtime) | Use setContext() in React useEffect |
User signs in, changes account, switches profile |
| Multiple simultaneous users | Multiple domains/providers, each with own context | Show flags for anonymous AND logged-in user on same page |
In this demo:
anon-webdomain → static context (”anonymous”), set in bootstrapuser-webdomain → dynamic context (changes via input field), updated withsetContext()
- Node.js (LTS) and npm
- A browser (client-side) SDK key from Harness FME / Split
git clone https://github.com/Split-Community/react-openfeature-multiple-clients.git
cd react-openfeature-multiple-clients
npm installPreferred: .env.local in the project root:
VITE_SPLIT_BROWSER_KEY=your-client-side-sdk-keyRestart npm run dev after editing env files.
Or set the fallback in src/openfeature-bootstrap.ts (authKey / <YOUR_AUTHORIZATION_KEY>).
Do not commit real keys to a public repo.
| Flag key | UI area | OpenFeature domain | Split customer key |
|---|---|---|---|
anon-flag |
Anonymous panel | anon-web |
anonymous (static) |
user-flag |
Signed-in panel | user-web |
Dynamic (e.g., user-1, user-2) |
Create both in the environment that matches your browser key.
Try targeting by key:
- Set
anon-flagto"on"for key ="anonymous" - Set
user-flagto"premium"for key ="user-1","basic"for"user-2" - Change the User ID input in the UI to see different treatments
npm run devIn dev, bootstrap also enables OpenFeature.setLogger(console), lightweight evaluation hooks, and Split debug on the factories. Use the browser console (show verbose logs if needed).
npm run build
npm run previewFrom open-feature/js-sdk root:
npm install
npm run dev --workspace=react-openfeature-multiple-clients