--- title: User Onboarding subtitle: How to implement onboarding flows in Neon Auth enableTableOfContents: true tag: beta updatedOn: '2025-10-01T12:46:01.214Z' --- > Implementing a user onboarding page and collecting information on sign-up By default, Neon Auth collects information such as email addresses from OAuth providers. Sometimes, you may want to collect additional information from users during sign-up, for example a 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](/docs/neon-auth/concepts/custom-user-data): ```jsx shouldWrap title="app/onboarding/page.tsx" export default function OnboardingPage() { const user = useUser(); const router = useRouter(); const [address, setAddress] = useState(''); return ( <> setAddress(e.target.value)} /> ); } ``` 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. Next, we can create a hook/function to check if the user has completed onboarding and redirect them to the onboarding page: ```jsx shouldWrap title="app/onboarding-hooks.ts" 'use client'; import { useEffect } from 'react'; import { useUser } from '@stackframe/stack'; import { useRouter } from 'next/navigation'; export function useOnboarding() { const user = useUser(); const router = useRouter(); useEffect(() => { if (user && !user.clientMetadata?.onboarded) { router.push('/onboarding'); } }, [user]); } ``` ```jsx shouldWrap title="app/onboarding-functions.ts" import { stackServerApp } from '@/stack/server'; import { redirect } from 'next/navigation'; export async function ensureOnboarded() { const user = await stackServerApp.getUser(); if (user && !user.serverMetadata?.onboarded) { redirect('/onboarding'); } } ``` To add an Onboarding page and guarantee users hit it, create a dedicated `/onboarding` page and gate protected pages with the hook/server function above so users are always redirected there until completion. On that page, validate details on your backend and then set the `onboarded` metadata flag. Follow the guide on [Custom User Data](/docs/neon-auth/concepts/custom-user-data) for implementation details. Here are examples of how to use the hook and server function in your components: ```jsx shouldWrap title="app/page.tsx" import { useOnboarding } from '@/app/onboarding-hooks'; import { useUser } from '@stackframe/stack'; export default function HomePage() { useOnboarding(); const user = useUser(); return
Welcome to the app, {user.displayName}
; } ```
```jsx shouldWrap title="app/page.tsx" import { ensureOnboarded } from '@/app/onboarding-functions'; import { stackServerApp } from '@/stack/server'; export default async function HomePage() { await ensureOnboarded(); const user = await stackServerApp.getUser(); return
Welcome to the app, {user.displayName}
; } ```