Identifying users & syncing data
Set up our SDK to automatically authenticate your users to your Featurebase and sync their data.
Written By Bruno from Featurebase
Last updated 2 days ago
This article assumes you've already booted the Featurebase SDK from Installation overview. Here we cover the identity layer: how to authenticate users securely, how custom attributes and companies flow into Featurebase, and when the local-testing fallback is acceptable.
Recommended path: use a server-signed featurebaseJwt. Secure installation is enabled by default, so plain browser-sent email / userId values are rejected unless you explicitly disable the requirement.
Recommended: identify users with a signed JWT
For production, put the user's identity and custom attributes into a JWT on your backend, then pass only featurebaseJwt to the universal SDK install. This prevents visitors from opening devtools and impersonating another customer.
1. Sign the JWT on your backend
Use your Featurebase JWT secret on the server. Never expose it in client-side code or public environment variables.
import jwt from 'jsonwebtoken';
const featurebaseJwt = jwt.sign(
{
userId: user.id,
email: user.email,
name: user.name,
// Optional custom attributes (configure in dashboard first)
plan: user.plan,
companies: [
{
companyId: user.company.id,
name: user.company.name,
monthlySpend: user.company.mrr,
},
],
},
process.env.FEATUREBASE_JWT_SECRET,
{ algorithm: 'HS256' }
);Need another language or the full payload reference? See Creating and signing a JWT.
2. Return the token with your user data
Send the generated token from your backend alongside the currently signed-in user (for example, from your /me endpoint). The frontend should receive a field such as user.featurebaseJwt.
3. Pass featurebaseJwt into the universal install
Example// app/layout.tsx — Next.js 13+, or any React root.
'use client';
import { FeaturebaseProvider } from 'featurebase-js/react';
export default function RootLayout({ children, user }) {
return (
<FeaturebaseProvider
appId="YOUR_APP_ID"
featurebaseJwt={user?.featurebaseJwt}
>
{children}
</FeaturebaseProvider>
);
}4. Validate before going live
Interact with whichever Featurebase surface you use — Messenger, Feedback, Changelog, Surveys, or the embedded portal — and confirm the resulting conversation, post, vote, or response is attributed to the correct user with the expected attributes.
Local testing fallback: plain user fields
Do not use this in production. Anyone who opens devtools can edit plain userId or email values, impersonate another customer, and pollute your support or feedback data. Use this only for local prototyping.
1. Disable secure installation
Until you disable secure installation, the SDK rejects identity calls that do not include a signed JWT. You can temporarily disable it in Settings → Security. Re-enable it before staging or production.
2. Pass user fields directly
Drop featurebaseJwt and pass userId, email, name, and any configured custom attributes directly on the boot call.
Example// Local testing only. Requires secure installation to be disabled.
'use client';
import { FeaturebaseProvider } from 'featurebase-js/react';
export default function RootLayout({ children, user }) {
return (
<FeaturebaseProvider
appId="YOUR_APP_ID"
userId={user?.id}
email={user?.email}
name={user?.name}
companies={user?.companies}
plan={user?.plan}
>
{children}
</FeaturebaseProvider>
);
}3. Switch back before production
Once everything looks right locally, re-enable secure installation, remove the plain identity fields, and pass featurebaseJwt instead.
Custom user & company attributes
Anything beyond standard fields (for example plan, title, signupSource, or company attributes) must be declared in the dashboard first, otherwise it can be ignored. Configure them in Settings → Users → Custom attributes.
With the recommended JWT path, include these attributes in the JWT payload. With the local-testing path, pass them directly on the boot call.
Companies
Pass an array of companies the user belongs to so support and feedback can be sliced by account. Each entry should include a stable companyId and name; everything else is optional.
companies: [
{
companyId: 'acme', // required — your stable company id
name: 'Acme Inc.', // required
monthlySpend: 500, // optional
createdAt: '2023-05-19T15:35:49.915Z', // optional
industry: 'Fintech', // custom — declare in dashboard first
location: 'Canada',
},
]Cross-domain SSO for the public portal
Once a user is identified in your app, Featurebase can sign them into your public portal automatically — no extra login — as long as your portal lives on the same top-level domain as the page where you boot the SDK.
Example: if your portal is feedback.yourdomain.com, boot the SDK from yourdomain.com or another *.yourdomain.com subdomain.
Fallback: data-featurebase-link
If your app and portal cannot share a top-level domain, add data-featurebase-link to links that point at your portal. The SDK rewrites the URL with a one-time sign-in token so the user lands authenticated.
Example<a data-featurebase-link
href="https://yourorg.featurebase.app"
target="_blank"
rel="noopener noreferrer">
Give feedback
</a>Auto-auth for in-app widgets
Once featurebaseJwt is on the universal boot, every widget you mount inherits that identity automatically. There is no per-widget identify step.
Run code after the SDK is ready
If you need to wait until Featurebase has finished bootstrapping, use whenReady.
Example'use client';
import { useEffect } from 'react';
import { whenReady } from 'featurebase-js';
export function FeaturebaseReadyEffect() {
useEffect(() => {
whenReady(() => {
// Safe to call into the SDK now.
});
}, []);
return null;
}You can also enrich feedback posts with session context (URL, app version, device, etc.) — see Metadata for posts.