Skip to main content
Glama

Bucket Feature Flags MCP Server

Official
by reflagcom
README.md27.5 kB
# Reflag React SDK React client side library for [Reflag.com](https://reflag.com) Reflag supports flag toggling, tracking flag usage, [requesting feedback](#userequestfeedback) on features, and [remotely configuring flags](#remote-config). The Reflag React SDK comes with a [built-in toolbar](https://docs.reflag.com/supported-languages/browser-sdk#toolbar) which appears on `localhost` by default. ## Install Install via npm: ```shell npm i @reflag/react-sdk ``` ## Get started ### 1. Add the `ReflagProvider` context provider Add the `ReflagProvider` context provider to your application: **Example:** ```tsx import { ReflagProvider } from "@reflag/react-sdk"; <ReflagProvider publishableKey="{YOUR_PUBLISHABLE_KEY}" context={{ company: { id: "acme_inc", plan: "pro" }, user: { id: "john doe" }, }} loadingComponent={<Loading />} > {/* children here are shown when loading finishes or immediately if no `loadingComponent` is given */} </ReflagProvider>; ``` ### 2. Create a new flag and set up type safety Install the Reflag CLI: ```shell npm i --save-dev @reflag/cli ``` Run `npx reflag new` to create your first flag! On the first run, it will sign into Reflag and set up type generation for your project: ```shell ❯ npx reflag new Opened web browser to facilitate login: https://app.reflag.com/api/oauth/cli/authorize Welcome to ◪ Reflag! ? Where should we generate the types? gen/flags.d.ts ? What is the output format? react ✔ Configuration created at reflag.config.json. Creating flag for app Slick app. ? New flag name: Huddle ? New flag key: huddle ✔ Created flag Huddle with key huddle (https://app.reflag.com/features/huddles) ✔ Generated react types in gen/flags.d.ts. ``` > [!Note] > By default, types will be generated in `gen/flags.d.ts`. > The default `tsconfig.json` file `include`s this file by default, but if your `tsconfig.json` is different, make sure the file is covered in the `include` property. ### 3. Use `useFlag(<flagKey>)` to get flag status Using the `useFlag` hook from your components lets you toggle flags on/off and track flag usage: **Example:** ```tsx function StartHuddleButton() { const { isEnabled, // boolean indicating if the flag is enabled track, // track usage of the flag } = useFlag("huddle"); if (!isEnabled) { return null; } return <button onClick={track}>Start huddle!</button>; } ``` `useFlag` can help you do much more. See a full example for `useFlag` [see below](#useflag). ## Setting context Reflag determines which flags are active for a given `user`, `company`, or `other` context. You can pass these to the `ReflagProvider` using the `context` prop. ### Using the `context` prop ```tsx <ReflagProvider publishableKey={YOUR_PUBLISHABLE_KEY} context={{ user: { id: "user_123", name: "John Doe", email: "john@acme.com" }, company: { id: "company_123", name: "Acme, Inc" }, other: { source: "web" }, }} > <LoadingReflag> {/* children here are shown when loading finishes */} </LoadingReflag> </ReflagProvider> ``` ### Legacy individual props (deprecated) For backward compatibility, you can still use individual props, but these are deprecated and will be removed in the next major version: ```tsx <ReflagProvider publishableKey={YOUR_PUBLISHABLE_KEY} user={{ id: "user_123", name: "John Doe", email: "john@acme.com" }} company={{ id: "company_123", name: "Acme, Inc" }} otherContext={{ source: "web" }} > <LoadingReflag> {/* children here are shown when loading finishes */} </LoadingReflag> </ReflagProvider> ``` > [!Important] > The `user`, `company`, and `otherContext` props are deprecated. Use the `context` prop instead, which provides the same functionality in a more structured way. ### Context requirements If you supply `user` or `company` objects, they must include at least the `id` property otherwise they will be ignored in their entirety. In addition to the `id`, you must also supply anything additional that you want to be able to evaluate flag targeting rules against. Attributes which are not properties of the `user` or `company` can be supplied using the `other` property. Attributes cannot be nested (multiple levels) and must be either strings, numbers or booleans. A number of special attributes exist: - `name` -- display name for `user`/`company`, - `email` -- the email of the user, - `avatar` -- the URL for `user`/`company` avatar image. To retrieve flags along with their targeting information, use `useFlag(key: string)` hook (described in a section below). Note that accessing `isEnabled` on the object returned by `useFlag()` automatically generates a `check` event. ## Remote config Remote config is a dynamic and flexible approach to configuring flag behavior outside of your app – without needing to re-deploy it. Similar to `isEnabled`, each flag accessed using the `useFlag()` hook, has a `config` property. This configuration is managed from within Reflag. It is managed similar to the way access to flags is managed, but instead of the binary `isEnabled` you can have multiple configuration values which are given to different user/companies. ### Get started with Remote config 1. Update your flag definitions: ```typescript import "@reflag/react-sdk"; // Define your flags by extending the `Flags` interface in @reflag/react-sdk declare module "@reflag/react-sdk" { interface Flags { huddle: { // change from `boolean` to an object which sets // a type for the remote config for `questionnaire` maxTokens: number; model: string; }; } } ``` ```ts const { isEnabled, config: { key, payload }, } = useFlag("huddles"); // isEnabled: true, // key: "gpt-3.5", // payload: { maxTokens: 10000, model: "gpt-3.5-beta1" } ``` `key` is mandatory for a config, but if a flag has no config or no config value was matched against the context, the `key` will be `undefined`. Make sure to check against this case when trying to use the configuration in your application. `payload` is an optional JSON value for arbitrary configuration needs. Note that, similar to `isEnabled`, accessing `config` on the object returned by `useFlag()` automatically generates a `check` event. ## Toolbar The Reflag Toolbar is great for toggling flags on/off for yourself to ensure that everything works both when a flag is on and when it's off. <img width="310" height="265" alt="Toolbar" src="https://github.com/user-attachments/assets/61492915-0d30-446d-a163-3eb16d9024b2" /> The toolbar will automatically appear on `localhost`. However, it can also be incredibly useful in production. You have full control over when it appears through the `toolbar` configuration option passed to the ReflagProvider. You can pass a simple boolean to force the toolbar to appear/disappear: ```ts <ReflagProvider ... // show the toolbar even in production if the user is an internal/admin user toolbar={user?.isInternal} ... }); ``` ## Server-side rendering and bootstrapping For server-side rendered applications, you can eliminate the initial network request by bootstrapping the client with pre-fetched flag data using the `ReflagBootstrappedProvider`. ### Using `ReflagBootstrappedProvider` The `<ReflagBootstrappedProvider>` component is a specialized version of `ReflagProvider` designed for server-side rendering and preloaded flag scenarios. Instead of fetching flags on initialization, it uses pre-fetched flags, resulting in faster initial page loads and better SSR compatibility. ```tsx import { useState, useEffect } from "react"; import { BootstrappedFlags } from "@reflag/react-sdk"; interface BootstrapData { user: User; flags: BootstrappedFlags; } function useBootstrap() { const [data, setData] = useState<BootstrapData | null>(null); useEffect(() => { fetch("/bootstrap") .then((res) => res.json()) .then(setData); }, []); return data; } // Usage in your app function App() { const { user, flags } = useBootstrap(); return ( <AuthProvider user={user}> <ReflagBootstrappedProvider publishableKey="your-publishable-key" flags={flags} > <Router /> </ReflagBootstrappedProvider> </AuthProvider> ); } ``` ### Server-side endpoint setup Create an endpoint that provides bootstrap data to your client application: ```typescript // server.js or your Express app import { ReflagClient as ReflagNodeClient } from "@reflag/node-sdk"; const reflagClient = new ReflagNodeClient({ secretKey: process.env.REFLAG_SECRET_KEY, }); await reflagClient.initialize(); app.get("/bootstrap", (req, res) => { const user = getUser(req); // Get user from your auth system const company = getCompany(req); // Get company from your auth system const flags = reflagClient.getFlagsForBootstrap({ user: { id: "user123", name: "John Doe", email: "john@acme.com" }, company: { id: "company456", name: "Acme Inc", plan: "enterprise" }, other: { source: "web" }, }); res.status(200).json({ user, flags, }); }); ``` ### Next.js Page Router SSR example For Next.js applications using server-side rendering, you can pre-fetch flags in `getServerSideProps`: ```typescript // pages/index.tsx import { GetServerSideProps } from "next"; import { ReflagClient as ReflagNodeClient } from "@reflag/node-sdk"; import { ReflagBootstrappedProvider, BootstrappedFlags, useFlag } from "@reflag/react-sdk"; interface PageProps { bootstrapData: BootstrappedFlags; } export const getServerSideProps: GetServerSideProps = async (context) => { const serverClient = new ReflagNodeClient({ secretKey: process.env.REFLAG_SECRET_KEY }); await serverClient.initialize(); const user = await getUserFromSession(context.req); const company = await getCompanyFromUser(user); const bootstrapData = serverClient.getFlagsForBootstrap({ user: { id: "user123", name: "John Doe", email: "john@acme.com" }, company: { id: "company456", name: "Acme Inc", plan: "enterprise" }, other: { page: "homepage" } }); return { props: { bootstrapData } }; }; export default function HomePage({ bootstrapData }: PageProps) { return ( <ReflagBootstrappedProvider publishableKey={process.env.NEXT_PUBLIC_REFLAG_PUBLISHABLE_KEY} flags={bootstrapData} > <HuddleFeature /> </ReflagBootstrappedProvider> ); } function HuddleFeature() { const { isEnabled, track, config } = useFlag("huddle"); if (!isEnabled) return null; return ( <div> <h2>Start a Huddle</h2> <p>Max participants: {config.payload?.maxParticipants ?? 10}</p> <p>Video quality: {config.payload?.videoQuality ?? "standard"}</p> <button onClick={track}>Start Huddle</button> </div> ); } ``` This approach eliminates loading states and improves performance by avoiding the initial flags API call. ### Next.js App Router example For Next.js applications using the App Router (Next.js 13+), you can pre-fetch flags in Server Components and pass them to client components: ```typescript // app/layout.tsx (Server Component) import { ReflagClient as ReflagNodeClient } from "@reflag/node-sdk"; import { ClientProviders } from "./providers"; async function getBootstrapData() { const serverClient = new ReflagNodeClient({ secretKey: process.env.REFLAG_SECRET_KEY! }); await serverClient.initialize(); // In a real app, you'd get user/company from your auth system const bootstrapData = serverClient.getFlagsForBootstrap({ user: { id: "user123", name: "John Doe", email: "john@acme.com" }, company: { id: "company456", name: "Acme Inc", plan: "enterprise" }, other: { source: "web" } }); return bootstrapData; } export default async function RootLayout({ children, }: { children: React.ReactNode; }) { const bootstrapData = await getBootstrapData(); return ( <html lang="en"> <body> <ClientProviders bootstrapData={bootstrapData}> {children} </ClientProviders> </body> </html> ); } ``` ```typescript // app/providers.tsx (Client Component) "use client"; import { ReflagBootstrappedProvider, BootstrappedFlags } from "@reflag/react-sdk"; interface ClientProvidersProps { children: React.ReactNode; bootstrapData: BootstrappedFlags; } export function ClientProviders({ children, bootstrapData }: ClientProvidersProps) { return ( <ReflagBootstrappedProvider publishableKey={process.env.NEXT_PUBLIC_REFLAG_PUBLISHABLE_KEY!} flags={bootstrapData} > {children} </ReflagBootstrappedProvider> ); } ``` ```typescript // app/page.tsx (Server Component) import { HuddleFeature } from "./huddle-feature"; export default function HomePage() { return ( <main> <h1>My App</h1> <HuddleFeature /> </main> ); } ``` ```typescript // app/huddle-feature.tsx (Client Component) "use client"; import { useFlag } from "@reflag/react-sdk"; export function HuddleFeature() { const { isEnabled, track, config } = useFlag("huddle"); if (!isEnabled) return null; return ( <div> <h2>Start a Huddle</h2> <p>Max participants: {config.payload?.maxParticipants ?? 10}</p> <p>Video quality: {config.payload?.videoQuality ?? "standard"}</p> <button onClick={track}>Start Huddle</button> </div> ); } ``` This App Router approach leverages Server Components for server-side flag fetching while using Client Components only where React state and hooks are needed. ## `<ReflagClientProvider>` component The `<ReflagClientProvider>` is a lower-level component that accepts a pre-initialized `ReflagClient` instance. This is useful for advanced use cases where you need full control over client initialization or want to share a client instance across multiple parts of your application. ### Usage ```tsx import { ReflagClient } from "@reflag/browser-sdk"; import { ReflagClientProvider } from "@reflag/react-sdk"; // Initialize the client yourself const client = new ReflagClient({ publishableKey: "your-publishable-key", user: { id: "user123", name: "John Doe" }, company: { id: "company456", name: "Acme Inc" }, // ... other configuration options }); // Initialize the client await client.initialize(); function App() { return ( <ReflagClientProvider client={client} loadingComponent={<Loading />}> <Router /> </ReflagClientProvider> ); } ``` ### Props The `ReflagClientProvider` accepts the following props: - `client`: A pre-initialized `ReflagClient` instance - `loadingComponent`: Optional React component to show while the client is initializing (same as `ReflagProvider`) > [!Note] > Most applications should use `ReflagProvider` or `ReflagBootstrappedProvider` instead of `ReflagClientProvider`. Only use this component when you need the advanced control it provides. ## `<ReflagProvider>` component The `<ReflagProvider>` initializes the Reflag SDK, fetches flags and starts listening for automated feedback survey events. The component can be configured using a number of props: - `publishableKey` is used to connect the provider to an _environment_ on Reflag. Find your `publishableKey` under [environment settings](https://app.reflag.com/env-current/settings/app-environments) in Reflag, - `context` (recommended): An object containing `user`, `company`, and `other` properties that make up the evaluation context used to determine if a flag is enabled or not. `company` and `user` contexts are automatically transmitted to Reflag servers so the Reflag app can show you which companies have access to which flags etc. - `company`, `user` and `other` (deprecated): Individual props for context. These are deprecated in favor of the `context` prop and will be removed in the next major version. > [!Note] > If you specify `company` and/or `user` they must have at least the `id` property, otherwise they will be ignored in their entirety. You should also supply anything additional you want to be able to evaluate flag targeting against, - `fallbackFlags`: A list of strings which specify which flags to consider enabled if the SDK is unable to fetch flags. Can be provided in two formats: ```ts // Simple array of flag keys fallbackFlags={["flag1", "flag2"]} // Or with configuration overrides fallbackFlags: { "flag1": true, // just enable the flag "flag2": { // enable with configuration key: "variant-a", payload: { limit: 100, mode: "test" } } } ``` - `timeoutMs`: Timeout in milliseconds when fetching flags from the server. - `staleWhileRevalidate`: If set to `true`, stale flags will be returned while refetching flags in the background. - `expireTimeMs`: If set, flags will be cached between page loads for this duration (in milliseconds). - `staleTimeMs`: Maximum time (in milliseconds) that stale flags will be returned if `staleWhileRevalidate` is true and new flags cannot be fetched. - `offline`: Provide this option when testing or in local development environments to avoid contacting Reflag servers. - `loadingComponent` lets you specify an React component to be rendered instead of the children while the Reflag provider is initializing. If you want more control over loading screens, `useFlag()` and `useIsLoading` returns `isLoading` which you can use to customize the loading experience. - `enableTracking`: Set to `false` to stop sending tracking events and user/company updates to Reflag. Useful when you're impersonating a user (defaults to `true`), - `apiBaseUrl`: Optional base URL for the Reflag API. Use this to override the default API endpoint, - `appBaseUrl`: Optional base URL for the Reflag application. Use this to override the default app URL, - `sseBaseUrl`: Optional base URL for Server-Sent Events. Use this to override the default SSE endpoint, - `debug`: Set to `true` to enable debug logging to the console, - `toolbar`: Optional [configuration](https://docs.reflag.com/supported-languages/browser-sdk/globals#toolbaroptions) for the Reflag toolbar, - `feedback`: Optional configuration for feedback collection ## `<ReflagBootstrappedProvider>` component The `<ReflagBootstrappedProvider>` is a specialized version of the `ReflagProvider` that uses pre-fetched flag data instead of making network requests during initialization. This is ideal for server-side rendering scenarios. The component accepts the following props: - `flags`: Pre-fetched flags data of type `BootstrappedFlags` obtained from the Node SDK's `getFlagsForBootstrap()` method. This contains both the context (user, company, other) and the flags data. - All other props available in [`ReflagProvider`](#reflagprovider-component) are supported except `context`, `user`, `company`, and `other` (which are extracted from `flags.context`). **Example:** ```tsx import { ReflagBootstrappedProvider, BootstrappedFlags, } from "@reflag/react-sdk"; interface AppProps { bootstrapData: BootstrappedFlags; } function App({ bootstrapData }: AppProps) { return ( <ReflagBootstrappedProvider publishableKey="your-publishable-key" flags={bootstrapData} loadingComponent={<Loading />} debug={process.env.NODE_ENV === "development"} > <Router /> </ReflagBootstrappedProvider> ); } ``` > [!Note] > When using `ReflagBootstrappedProvider`, the context (user, company, and other) is extracted from the `flags.context` property and doesn't need to be passed separately. ## Hooks ### `useFlag()` Returns the state of a given flag for the current context. The hook provides type-safe access to flags and their configurations. ```tsx import { useFlag } from "@reflag/react-sdk"; import { Loading } from "./Loading"; function StartHuddleButton() { const { isLoading, // true while flags are being loaded isEnabled, // boolean indicating if the flag is enabled config: { // flag configuration key, // string identifier for the config variant payload, // type-safe configuration object }, track, // function to track flag usage requestFeedback, // function to request feedback for this flag } = useFlag("huddle"); if (isLoading) { return <Loading />; } if (!isEnabled) { return null; } return ( <> <button onClick={track}>Start huddle!</button> <button onClick={(e) => requestFeedback({ title: payload?.question ?? "How do you like the Huddles feature?", position: { type: "POPOVER", anchor: e.currentTarget as HTMLElement, }, }) } > Give feedback! </button> </> ); } ``` ### `useTrack()` `useTrack()` lets you send custom events to Reflag. Use this whenever a user _uses_ a feature. These events can be used to analyze feature usage in Reflag. ```tsx import { useTrack } from "@reflag/react-sdk"; function StartHuddle() { const { track } = useTrack(); <div> <button onClick={() => track("Huddle Started", { huddleType: "voice" })}> Start voice huddle! </button> </div>; } ``` ### `useRequestFeedback()` `useRequestFeedback()` returns a function that lets you open up a dialog to ask for feedback on a specific feature. This is useful for collecting targeted feedback about specific features as part of roll out. See [Automated Feedback Surveys](https://docs.reflag.com/product-handbook/live-satisfaction) for how to do this automatically, without code. When using the `useRequestFeedback` you must pass the flag key to `requestFeedback`. The example below shows how to use `position` to ensure the popover appears next to the "Give feedback!" button. ```tsx import { useRequestFeedback } from "@reflag/react-sdk"; function FeedbackButton() { const requestFeedback = useRequestFeedback(); return ( <button onClick={(e) => requestFeedback({ flagKey: "huddle-flag", title: "How satisfied are you with file uploads?", position: { type: "POPOVER", anchor: e.currentTarget as HTMLElement, }, // Optional custom styling style: { theme: "light", primaryColor: "#007AFF", }, }) } > Give feedback! </button> ); } ``` See the [Feedback Documentation](https://github.com/reflagcom/javascript/blob/main/packages/browser-sdk/FEEDBACK.md#manual-feedback-collection) for more information on `requestFeedback` options. ### `useSendFeedback()` Returns a function that lets you send feedback to Reflag. This is useful if you've manually collected feedback through your own UI and want to send it to Reflag. ```tsx import { useSendFeedback } from "@reflag/react-sdk"; function CustomFeedbackForm() { const sendFeedback = useSendFeedback(); const handleSubmit = async (data: FormData) => { await sendFeedback({ flagKey: "reflag-flag-key", score: parseInt(data.get("score") as string), comment: data.get("comment") as string, }); }; return <form onSubmit={handleSubmit}>...</form>; } ``` ### `useUpdateUser()`, `useUpdateCompany()` and `useUpdateOtherContext()` These hooks return functions that let you update the attributes for the currently set user, company, or other context. Updates to user/company are stored remotely and affect flag targeting, while "other" context updates only affect the current session. ```tsx import { useUpdateUser, useUpdateCompany, useUpdateOtherContext, } from "@reflag/react-sdk"; function FlagOptIn() { const updateUser = useUpdateUser(); const updateCompany = useUpdateCompany(); const updateOtherContext = useUpdateOtherContext(); const handleUserUpdate = async () => { await updateUser({ role: "admin", betaFlags: "enabled", }); }; const handleCompanyUpdate = async () => { await updateCompany({ plan: "enterprise", employees: 500, }); }; const handleContextUpdate = async () => { await updateOtherContext({ currentWorkspace: "workspace-123", theme: "dark", }); }; return ( <div> <button onClick={handleUserUpdate}>Update User</button> <button onClick={handleCompanyUpdate}>Update Company</button> <button onClick={handleContextUpdate}>Update Context</button> </div> ); } ``` ### `useClient()` Returns the `ReflagClient` used by the `ReflagProvider`. The client offers more functionality that is not directly accessible thorough the other hooks. ```tsx import { useClient } from "@reflag/react-sdk"; function LoggingWrapper({ children }: { children: ReactNode }) { const client = useClient(); console.log(client.getContext()); return children; } ``` ### `useIsLoading()` Returns the loading state of the flags in the `ReflagClient`. Initially, the value will be `true` if no bootstrap flags have been provided and the client has not be initialized. ```tsx import { useIsLoading } from "@reflag/react-sdk"; import { Spinner } from "./Spinner"; function LoadingWrapper({ children }: { children: ReactNode }) { const isLoading = useIsLoading(); if (isLoading) { return <Spinner />; } return children; } ``` ### `useOnEvent()` Attach a callback handler to client events to act on changes. It automatically disposes itself on unmount. ```tsx import { useOnEvent } from "@reflag/react-sdk"; function LoggingWrapper({ children }: { children: ReactNode }) { useOnEvent("flagsUpdated", (newFlags) => { console.log(newFlags); }); return children; } ``` ## Migrating from Bucket SDK If you have been using the Bucket SDKs, the following list will help you migrate to Reflag SDK: - `Bucket*` classes, and types have been renamed to `Reflag*` (e.g. `BucketClient` is now `ReflagClient`) - `Feature*` classes, and types have been renamed to `Flag*` (e.g. `Feature` is now `Flag`, `RawFeatures` is now `RawFlags`) - When using strongly-typed flags, the new `Flags` interface replaced `Features` interface - All methods that contained `feature` in the name have been renamed to use the `flag` terminology (e.g. `getFeature` is `getFlag`) - The `fallbackFeatures` property in client constructor and configuration files has been renamed to `fallbackFlags` - `featureKey` has been renamed to `flagKey` in all methods that accepts that argument - The SDKs will not emit `evaluate` and `evaluate-config` events anymore - The new cookies that are stored in the client's browser are now `reflag-*` prefixed instead of `bucket-*` - The `featuresUpdated` hook has been renamed to `flagsUpdated` - The `checkIsEnabled` and `checkConfig` hooks have been removed, use `check` from now on To ease in transition to Reflag SDK, some of the old methods have been preserved as aliases to the new methods: - `getFeature` method is an alias for `getFlag` - `getFeatures` method is an alias for `getFlags` - `useFeature` method is an alias for `useFlag` - `featuresUpdated` hook is an alias for `flagsUpdated` If you are running with strict Content Security Policies active on your website, you will need change them as follows: - `connect-src https://front.bucket.co` to `connect-src https://front.reflag.com` ## Content Security Policy (CSP) See [CSP](https://github.com/reflagcom/javascript/blob/main/packages/browser-sdk/README.md#content-security-policy-csp) for info on using Reflag React SDK with CSP ## License MIT License Copyright (c) 2025 Bucket ApS

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/reflagcom/bucket-javascript-sdk'

If you have feedback or need assistance with the MCP directory API, please join our Discord server