Skip to main content
Build a preference center that lives inside your app instead of redirecting users to an external page. The Courier React SDK gives you two approaches: the prebuilt <CourierPreferences> component for quick setup, or the headless useCourier().preferences hooks for a fully custom UI. By the end of this tutorial, your users will be able to toggle notification topics on and off, choose delivery channels (Enterprise), and subscribe to digests directly in your app.

Prerequisites

If you haven’t created subscription topics and mapped templates yet, complete Steps 1-2 of the hosted preference center tutorial first. The topics and template mappings are the same regardless of how you surface preferences.

Step 1: Install the SDK

The SDK ships as a single package. Install @trycourier/courier-react for React 18+, or @trycourier/courier-react-17 for React 17. They expose the same API.

Step 2: Authenticate with a JWT

Preferences authenticate with a JWT generated by your backend, then signed in on the client with courier.shared.signIn. There is no provider to wrap your app in, and authentication is shared across every Courier component, so if you already signed in for Inbox or Toast you can skip this step. Generate the token server-side with the issue-token API and include the preferences scopes:
Fetch that token in your app and call signIn:
See How to Send a JWT from Your Backend for language-specific backend examples. To scope preferences to a tenant, pass tenantId to signIn: courier.shared.signIn({ userId, jwt, tenantId }).
Critical: The userId you sign in with must match the to.user_id you use when sending, or preference enforcement will not line up.

Option A: Prebuilt Component (Quick Setup)

<CourierPreferences> renders a complete preference interface out of the box: topic toggles, channel selection (Enterprise), and digest scheduling, with the SDK’s modern UI, native theming, and dark mode.

Props

Tenant scope is set on signIn, not per component, so there is no tenantId prop.

Option B: Headless Hooks (Full Control)

For a fully custom UI, read and write preferences through useCourier().preferences.

Fetching Preferences

Updating Preferences

Use putUserPreferenceTopic to toggle a topic or set custom routing:

Preference Methods

For the putUserPreferenceTopic payload, status is "OPTED_IN" or "OPTED_OUT", customRouting is an array of channel types (for example ["email", "push"]) applied when hasCustomRouting is true, and digestSchedule sets a digest cadence when the topic supports it.

Step 3: Test Your Implementation

1

Verify Topic Display

Confirm that all subscription topics from the Preferences Editor appear in your component.
If topics are missing or stale, make sure you’ve clicked Publish in the Preferences Editor. Changes are saved as a draft until you publish.
2

Test Opt-In/Out

Toggle a topic off, then send a test notification for a template linked to that topic. The notification should be suppressed for the opted-out user.
3

Verify Channel Selection (Enterprise)

If channel selection is enabled, confirm a user’s channel choices appear when you query the topic from your backend:

Theming

Style the prebuilt component with the lightTheme and darkTheme props rather than global CSS. See the Preferences component reference for the theme fields, and use mode to force light, dark, or system. For total control over markup and styles, use the headless hooks in Option B and render your own UI.

What’s Next

Set Up Hosted Preferences

Deploy a hosted preference page as an alternative or complement

Embedding Reference

Full reference for the component and preference hooks

JWT Authentication

Secure your embedded components with JWT tokens

User Preferences API

API reference for server-side preference management