mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-16 21:08:38 +08:00
Step 5: rename lowercase local vars stackApp/stackServerApp/stackClientApp/ stackAdminApp -> hexclave* across SDK source, apps, examples, and docs-mintlify (docs/ excluded). Public StackServerApp/StackClientApp classes and the useStackApp hook are unchanged. typecheck + lint green.
124 lines
3.8 KiB
Plaintext
124 lines
3.8 KiB
Plaintext
---
|
|
title: "User Onboarding"
|
|
description: "Implementing a user onboarding page and collecting information on sign-up"
|
|
sidebarTitle: Onboarding
|
|
---
|
|
|
|
Sometimes, you may want to collect additional information from users during sign-up, for example a real name or address.
|
|
|
|
The most straightforward approach is to redirect users to an onboarding page right after they sign up. However, this is not recommended for the following reasons:
|
|
|
|
1. Users can accidentally (or purposefully) close or navigate away from the page before completing the onboarding.
|
|
2. Redirect URLs may vary depending on the context. For instance, if a user is redirected to a sign-in page after trying to access a protected page, they'll expect to return to the original protected page post-authentication.
|
|
|
|
Instead, a more reliable strategy is to store an `onboarded` flag in the user's metadata and redirect users to the onboarding page if they haven't completed it yet.
|
|
|
|
## Example implementation
|
|
|
|
Let's say you have an onboarding page that asks for an address and stores it in the user's [metadata](/guides/going-further/user-metadata):
|
|
|
|
```jsx
|
|
export default function OnboardingPage() {
|
|
const user = useUser();
|
|
const router = useRouter();
|
|
const [address, setAddress] = useState('');
|
|
|
|
return <>
|
|
<input
|
|
type="text"
|
|
value={address}
|
|
onChange={(e) => setAddress(e.target.value)}
|
|
/>
|
|
|
|
<button onClick={async () => {
|
|
await user.update({
|
|
clientMetadata: {
|
|
onboarded: true,
|
|
address,
|
|
},
|
|
});
|
|
router.push('/');
|
|
}}>
|
|
Submit
|
|
</button>
|
|
</>
|
|
);
|
|
}
|
|
```
|
|
|
|
<Info>
|
|
While the above implementation offers a basic onboarding process, users can still skip onboarding by directly sending an API request to update the `clientMetadata.onboarded` flag. If you want to ensure that onboarding cannot be bypassed on the API level, you should create a server endpoint to validate and store the data, then save the `onboarded` flag in the `clientReadOnlyMetadata` on the server side after validation.
|
|
</Info>
|
|
|
|
Next, we can create a hook/function to check if the user has completed onboarding and redirect them to the onboarding page:
|
|
|
|
<Tabs>
|
|
<Tab title="Client Component">
|
|
```jsx
|
|
'use client';
|
|
import { useEffect } from 'react';
|
|
import { useUser } from '@hexclave/next';
|
|
import { useRouter } from 'next/navigation';
|
|
|
|
export function useOnboarding() {
|
|
const user = useUser();
|
|
const router = useRouter();
|
|
|
|
useEffect(() => {
|
|
if (!user.clientReadOnlyMetadata.onboarded) {
|
|
router.push('/onboarding');
|
|
}
|
|
}, [user]);
|
|
}
|
|
```
|
|
</Tab>
|
|
<Tab title="Server Component">
|
|
```jsx
|
|
import { hexclaveServerApp } from '@/stack/server';
|
|
import { redirect } from 'next/navigation';
|
|
|
|
export async function ensureOnboarded() {
|
|
const user = await hexclaveServerApp.getUser();
|
|
if (!user.clientReadOnlyMetadata.onboarded) {
|
|
redirect('/onboarding');
|
|
}
|
|
}
|
|
```
|
|
</Tab>
|
|
</Tabs>
|
|
|
|
You can then use these functions wherever onboarding is required:
|
|
|
|
<Tabs>
|
|
<Tab title="Client Component">
|
|
```jsx
|
|
import { useOnboarding } from '@/app/onboarding-hooks';
|
|
import { useUser } from '@hexclave/next';
|
|
|
|
export default function HomePage() {
|
|
useOnboarding();
|
|
const user = useUser();
|
|
|
|
return (
|
|
<div>Welcome to the app, {user.displayName}</div>
|
|
);
|
|
}
|
|
```
|
|
</Tab>
|
|
<Tab title="Server Component">
|
|
```jsx
|
|
import { ensureOnboarding } from '@/app/onboarding-functions';
|
|
import { hexclaveServerApp } from '@/stack/server';
|
|
|
|
export default async function HomePage() {
|
|
await ensureOnboarding();
|
|
const user = await hexclaveServerApp.getUser();
|
|
|
|
return (
|
|
<div>Welcome to the app, {user.displayName}</div>
|
|
);
|
|
}
|
|
```
|
|
</Tab>
|
|
</Tabs>
|