Feature Flags (OFREP)
Logfire’s managed variables can serve as feature flags for client-side applications like web frontends, mobile apps, and edge services. The OFREP (OpenFeature Remote Evaluation Protocol) endpoints let any OpenFeature-compatible client evaluate variables without the Python SDK.
This guide shows how to set up a JavaScript/TypeScript web application using the official OpenFeature Web SDK and OFREP provider. The same approach works for any language with an OpenFeature SDK and OFREP provider.
- Create your variables in the Logfire UI (Settings > Variables) and mark them as external — see External Variables and OFREP
- Create an API key with the
project:read_external_variablesscope — this restricted scope is safe to use in client-side code since it only exposes variables you’ve explicitly marked as external
Install the OpenFeature Web SDK and OFREP provider:
npm install @openfeature/web-sdk @openfeature/ofrep-web-provider
pnpm add @openfeature/web-sdk @openfeature/ofrep-web-provider
yarn add @openfeature/web-sdk @openfeature/ofrep-web-provider
Initialize the OpenFeature provider once at application startup. The OFREP provider connects to your Logfire project’s OFREP endpoint and handles authentication via your API key.
import { OFREPWebProvider } from '@openfeature/ofrep-web-provider'
import { OpenFeature } from '@openfeature/web-sdk'
const LOGFIRE_API_KEY = 'your-api-key' // project:read_external_variables scope
const LOGFIRE_API_HOST = 'logfire-api.pydantic.dev' // or your self-hosted API host
const provider = new OFREPWebProvider({
baseUrl: `https://${LOGFIRE_API_HOST}/v1/ofrep/v1`,
fetchImplementation: (input, init) =>
fetch(input, {
...init,
headers: {
...Object.fromEntries(new Headers(init?.headers).entries()),
Authorization: `Bearer ${LOGFIRE_API_KEY}`,
},
}),
})
OpenFeature.setProvider(provider)
Set the evaluation context to enable targeting and deterministic rollouts. The targetingKey ensures that the same user always gets the same variant:
await OpenFeature.setContext({
targetingKey: userId,
// Additional attributes for targeting rules
plan: 'enterprise',
region: 'us-east',
})
Any attributes you include in the context can be used by conditional rules configured in the Logfire UI. For example, you could route all enterprise plan users to a specific label.
Use the OpenFeature client to evaluate flags. The client provides typed methods for different value types:
const client = OpenFeature.getClient()
// Boolean flag
const showNewFeature = client.getBooleanValue('show_new_feature', false)
// String value (e.g., a theme or prompt)
const theme = client.getStringValue('ui_theme', 'light')
// Number value
const maxRetries = client.getNumberValue('max_retries', 3)
// Get detailed evaluation info
const details = client.getStringDetails('ui_theme', 'light')
console.log(details.value) // resolved value
console.log(details.variant) // label name (e.g., "production", "canary")
console.log(details.reason) // evaluation reason (e.g., "TARGETING_MATCH", "SPLIT")
The second argument to each method is the default value, returned when the flag can’t be evaluated (e.g., network error, flag not found).
For React applications, OpenFeature provides a React SDK with hooks for flag evaluation:
npm install @openfeature/react-sdk
pnpm add @openfeature/react-sdk
yarn add @openfeature/react-sdk
Wrap your application with the OpenFeatureProvider and use hooks in your components:
import { OpenFeatureProvider, useBooleanFlagValue, useStringFlagDetails } from '@openfeature/react-sdk'
// In your app root
function App() {
return (
<OpenFeatureProvider>
<MyComponent />
</OpenFeatureProvider>
)
}
// In any component
function MyComponent() {
const showBanner = useBooleanFlagValue('show_banner', false)
const theme = useStringFlagDetails('ui_theme', 'light')
return (
<div data-theme={theme.value}>
{showBanner && <PromoBanner />}
<p>Theme variant: {theme.variant}</p>
</div>
)
}
Here’s a complete setup combining initialization, context, and evaluation:
import { OFREPWebProvider } from '@openfeature/ofrep-web-provider'
import { OpenFeature } from '@openfeature/web-sdk'
// Initialize once at app startup
function initFeatureFlags(apiKey: string, apiHost: string) {
const provider = new OFREPWebProvider({
baseUrl: `https://${apiHost}/v1/ofrep/v1`,
fetchImplementation: (input, init) =>
fetch(input, {
...init,
headers: {
...Object.fromEntries(new Headers(init?.headers).entries()),
Authorization: `Bearer ${apiKey}`,
},
}),
})
OpenFeature.setProvider(provider)
}
// Set context when user authenticates
async function setUserContext(userId: string, attributes: Record<string, string> = {}) {
await OpenFeature.setContext({
targetingKey: userId,
...attributes,
})
}
// Evaluate flags anywhere in your app
function getFeatureFlags() {
const client = OpenFeature.getClient()
return {
showNewDashboard: client.getBooleanValue('show_new_dashboard', false),
pricingTier: client.getStringValue('pricing_tier_config', 'standard'),
maxUploadSize: client.getNumberValue('max_upload_size_mb', 10),
}
}
OpenFeature provides SDKs and OFREP providers for many languages. You can use the same Logfire OFREP endpoint with any of them:
| Platform | SDK | OFREP Provider |
|---|---|---|
| JavaScript (Web) | @openfeature/web-sdk | @openfeature/ofrep-web-provider |
| JavaScript (Server) | @openfeature/server-sdk | @openfeature/ofrep-provider |
| Kotlin / Android | OpenFeature Kotlin SDK | OFREP Provider |
| Swift / iOS | OpenFeature Swift SDK | OFREP Provider |
See the OpenFeature ecosystem page for a full list.
The OFREP endpoint format is the same regardless of client:
POST https://<your-api-host>/v1/ofrep/v1/evaluate/flags/{flag_key}
POST https://<your-api-host>/v1/ofrep/v1/evaluate/flags
Both endpoints accept a JSON body with a context object containing targetingKey and any additional targeting attributes:
{
"context": {
"targetingKey": "user-123",
"plan": "enterprise",
"region": "us-east"
}
}
Authenticate with an Authorization: Bearer <api-key> header using a key with project:read_external_variables scope.