# Source: https://neon.com/llms/neon-auth-concepts-user-onboarding.txt

# User Onboarding

> The "User Onboarding" document outlines the process for new users to set up and access their Neon accounts, detailing steps for account creation, authentication, and initial configuration within the Neon platform.

## Source

- [User Onboarding HTML](https://neon.com/docs/neon-auth/concepts/user-onboarding): The original HTML version of this documentation

> 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](https://neon.com/docs/neon-auth/concepts/custom-user-data):

```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>
    </>
  );
}
```

   **Note**: 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:

Tab: Client Hook

```jsx
'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]);
}
```

Tab: Server Function

```jsx
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](https://neon.com/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:

Tab: Client Component

```jsx
import { useOnboarding } from '@/app/onboarding-hooks';
import { useUser } from '@stackframe/stack';

export default function HomePage() {
  useOnboarding();
  const user = useUser();

  return <div>Welcome to the app, {user.displayName}</div>;
}
```

Tab: Server Component

```jsx
import { ensureOnboarded } from '@/app/onboarding-functions';
import { stackServerApp } from '@/stack/server';

export default async function HomePage() {
  await ensureOnboarded();
  const user = await stackServerApp.getUser();

  return <div>Welcome to the app, {user.displayName}</div>;
}
```