Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 10 additions & 112 deletions guides/self-opt-in.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,125 +7,23 @@ icon: browser

Use Reflag's React SDK to let users opt themselves—or their company—into beta and experimental features.

For an overview of how opt-in affects access and how memberships are managed in Reflag, see [End-user opt-in](../product-handbook/end-user-opt-in.md).

## Before you begin

1. [Configure one or more non-secret flags for end-user opt-in](../product-handbook/end-user-opt-in.md#configure-end-user-opt-in).
2. Set **Access** to **Some** in every environment where opting in should be available.
3. Include a `user.id` in the Reflag context for user opt-in. To support company opt-in, also include a `company.id`.

## Quick start

Render the available opt-in flags and let the current user set their opt-in status.

If you're using `<ReflagBootstrappedProvider>` without a `<Suspense>` boundary, see the loading section below.

```tsx
import { useState } from "react";
import {
type OptInFlag,
useOptInFlags,
useSetOptIn,
} from "@reflag/react-sdk";
import { Spinner } from "your-component-library";

function OptInPage() {
const { flags: optInFlags } = useOptInFlags();

if (optInFlags.length === 0) {
return <p>No opt-in flags are available.</p>;
}

return optInFlags.map((flag) => (
<OptInFlagCard key={flag.key} flag={flag} />
));
}

function OptInFlagCard({ flag }: { flag: OptInFlag }) {
const setOptIn = useSetOptIn();
const [isUpdating, setIsUpdating] = useState(false);
const [updateError, setUpdateError] = useState<string | null>(null);
const label = flag.userOptedIn ? "Cancel opt-in" : `Try ${flag.name}`;

async function updateOptIn() {
setUpdateError(null);
setIsUpdating(true);

try {
const response = await setOptIn(flag.key, {
optedIn: !flag.userOptedIn,
});

if (response?.ok === false) {
throw new Error("Opt-in request failed");
}
} catch {
setUpdateError(`Could not update ${flag.name}. Please try again.`);
} finally {
setIsUpdating(false);
}
}

return (
<section>
<h2>{flag.name}</h2>
{flag.description && <p>{flag.description}</p>}
<button
aria-busy={isUpdating}
disabled={isUpdating}
onClick={updateOptIn}
>
{isUpdating ? (
<Spinner aria-label={`Updating ${flag.name}`} />
) : (
label
)}
</button>
{updateError && <p role="alert">{updateError}</p>}
</section>
);
}
```

`setOptIn()` returns a promise that resolves after the SDK applies the latest flag state, confirms the membership change, and notifies components using `useOptInFlags()`. React may not have committed the resulting render yet.

`useOptInFlags()` keeps the list synchronized with Reflag. `useSetOptIn()` changes the current user's opt-in by default and requires the current Reflag context to include a `user.id`.

## Company opt-in

To change the current company's opt-in, pass `scope: "company"`. The current Reflag context must include a `company.id`.

```tsx
setOptIn(flag.key, {
optedIn: !flag.companyOptedIn,
scope: "company",
});
```

User and company opt-ins are independent. Setting `optedIn` to `false` removes only the selected scope, so `isOptedIn` remains `true` while either scope is opted in.

Cancelling every opt-in does not necessarily disable the flag: an access rule may independently enable it for the current context.

## Managing loading state with `<ReflagBootstrappedProvider>` and without `<Suspense>`

Only apps using `ReflagBootstrappedProvider` without Suspense need to handle this loading state. Bootstrapped flag data does not include opt-in metadata, so the SDK fetches it when `useOptInFlags()` is first used.
1. Set up the [React SDK](../sdk/@reflag/react-sdk/README.md) and place your opt-in page inside a Reflag provider.
2. [Configure one or more non-secret flags for end-user opt-in](../product-handbook/end-user-opt-in.md#configure-end-user-opt-in). Add a public description to explain each feature in your UI.
3. Set **Access** to **Some** in every environment where opting in should be available. For an opt-in-only feature, leave the other access rules empty.
4. Include a `user.id` in the Reflag context for user opt-in. To support company opt-in, also include a `company.id`.

Check the hook's `isLoading` value before rendering an empty state:
## Build the opt-in page

```tsx
const { flags: optInFlags, isLoading } = useOptInFlags({ suspense: false });
Follow the [React SDK opt-in example](../sdk/@reflag/react-sdk/README.md#useoptinflags-and-usesetoptin) to list available flags and let users change their membership. The SDK documentation also covers loading, Suspense, error handling, and retrying failed metadata requests.

if (isLoading) {
return <Spinner aria-label="Loading opt-in flags" />;
}
## Choose the opt-in scope

if (optInFlags.length === 0) {
return <p>No opt-in flags are available.</p>;
}
```
* **User opt-in** applies to the current user and is the SDK default. Use it for personal beta preferences.
* **Company opt-in** applies to users evaluated in the current company. Use `scope: "company"` for an organization-wide opt-in experience.

With a regular `ReflagProvider`, opt-in metadata arrives as part of the normal flags request, so `useOptInFlags().isLoading` remains `false`. Use `useIsLoading()`, suspense or the provider's `loadingComponent` for the normal initial loading state.
User and company memberships are independent. Cancelling one does not remove the other. Even after cancelling both, an access rule may still enable the flag.

## Next steps

Expand Down
2 changes: 1 addition & 1 deletion product-handbook/end-user-opt-in.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,4 @@ If you enable opt-in again, retained memberships become active again as long as

Reflag does not impose a particular end-user experience. You can build a Labs page, beta settings page, organization-level experiments page, or any other interface that fits your product.

See [Beta feature opt-in](../guides/self-opt-in.md) for a step-by-step React implementation using Reflag's SDK hooks.
See [Build a beta feature opt-in page](../guides/self-opt-in.md) for setup guidance and a link to the React SDK example.
Loading