# withCroct

Learn how to use Croct proxy in a Next.js API route.

This higher-order function wraps a Next.js API route handler with the Croct proxy.

If your project already has a Next.js API route handler, you can use this function to configure the [Croct proxy](/reference/sdk/nextjs/api/functions/proxy) while preserving the current handler logic.

It also provides a way to identify and anonymize users for request-based authentication via headers or cookie.

## Signature

You can use this function without arguments, which is equivalent to using the [proxy](/reference/sdk/nextjs/api/functions/proxy) function:

```ts
function withCroct(): NextApiHandler;
```

Alternatively, you can pass a handler function as the first argument and optionally a user ID resolver function as the second argument:

```ts
export function withCroct(
  next: NextProxy,
  userIdResolver?: UserIdResolver,
): NextProxy;
```

And lastly, you can pass an options object as a single argument:

```ts
export function withCroct(props: CroctProxyOptions): NextProxy;
```

## Example \[#withcroct-example]

Here is an example of how to use this function:

**Next ≤ 15 — JavaScript**

**Basic**

```js
import {NextResponse} from 'next/server';
import {withCroct} from '@croct/plug-next/middleware';

function log(request) {
  console.log(request.headers.get('user-agent'));

  return NextResponse.next({headers: request.headers});
}

export const middleware = withCroct(log);`
```

**Authentication**

```js
import {withCroct} from '@croct/plug-next/middleware';
import authorizer from '@/services/authorizer';

async function resolveUserId(request) {
  const userToken = request.cookies.get('my-session-token');

  if (userToken === null) {
    return null;
  }

  try {
    const userId = await authorizer(userToken);

    return userId;
  } catch {
    return null;
  }
}

export const config = {
  matcher: "/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)"
};

export const middleware = withCroct({userIdResolver: resolveUserId});
```

**Next ≤ 15 — TypeScript**

**Basic**

```tsx
import {NextResponse, NextRequest} from 'next/server';
import {withCroct} from '@croct/plug-next/middleware';

function log(request: NextRequest): NextResponse {
  console.log(request.headers.get('user-agent'));

  return NextResponse.next({headers: request.headers});
}

export const middleware = withCroct(log);
```

**Authentication**

```tsx
import type {NextRequest} from 'next/server';
import {withCroct} from '@croct/plug-next/middleware';
import authorizer from '@/services/authorizer';

async function resolveUserId(request: NextRequest): string|null {
  const userToken = request.cookies.get('my-session-token');

  if (userToken === null) {
    return null;
  }

  try {
    const userId = await authorizer(userToken);

    return userId;
  } catch {
    return null;
  }
}

export const config = {
  matcher: "/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)"
};

export const middleware = withCroct({userIdResolver: resolveUserId});
```

**Next ≥ 16 — JavaScript**

**Basic**

```js
import {NextResponse} from 'next/server';
import {withCroct} from '@croct/plug-next/proxy';

function log(request) {
  console.log(request.headers.get('user-agent'));

  return NextResponse.next({headers: request.headers});
}

export const proxy = withCroct(log);`
```

**Authentication**

```js
import {withCroct} from '@croct/plug-next/proxy';
import authorizer from '@/services/authorizer';

async function resolveUserId(request) {
  const userToken = request.cookies.get('my-session-token');

  if (userToken === null) {
    return null;
  }

  try {
    const userId = await authorizer(userToken);

    return userId;
  } catch {
    return null;
  }
}

export const config = {
  matcher: "/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)"
};

export const proxy = withCroct({userIdResolver: resolveUserId});
```

**Next ≥ 16 — TypeScript**

**Basic**

```tsx
import {NextResponse, NextRequest} from 'next/server';
import {withCroct} from '@croct/plug-next/proxy';

function log(request: NextRequest): NextResponse {
  console.log(request.headers.get('user-agent'));

  return NextResponse.next({headers: request.headers});
}

export const proxy = withCroct(log);
```

**Authentication**

```tsx
import type {NextRequest} from 'next/server';
import {withCroct} from '@croct/plug-next/proxy';
import authorizer from '@/services/authorizer';

async function resolveUserId(request: NextRequest): string|null {
  const userToken = request.cookies.get('my-session-token');

  if (userToken === null) {
    return null;
  }

  try {
    const userId = await authorizer(userToken);

    return userId;
  } catch {
    return null;
  }
}

export const config = {
  matcher: "/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)"
};

export const proxy = withCroct({userIdResolver: resolveUserId});
```

## Parameters

The following list describes the supported parameters:

- `options`: `object` (optional)

  The middleware options.

  - `next`: `NextMiddleware` (optional)

    The handler function to execute after the Croct middleware.

    The function receives the request object and returns a response object.

  - `matcher`: `MiddlewareMatcher` (optional)

    The middleware matcher, as defined in the [Next.js documentation](https://nextjs.org/docs/app/api-reference/file-conventions/middleware#matcher).

    Passing a matcher allows the middleware to match only the necessary routes in addition to those already specified.

    This is useful when integrating the SDK into a project that already uses a custom matcher. Instead of manually merging matchers, you can simply pass your existing matcher to extend it automatically.

  - `userIdResolver`: `(request: NextRequest) => Promise<string|null>` (optional)

    A function that resolves the user ID for the current request.

    The function receives the request object and returns the user ID as a string or `null` if the user is anonymous.

    While [`identify`](identify) and [`anonymize`](anonymize) update the Croct token immediately when called, the token lifecycle is independent of your authentication system. If a session expires or a token needs renewal, the SDK has no way to know the user is still logged in. The `userIdResolver` bridges this gap by reading the user ID from your auth session on every request, keeping the Croct token in sync automatically, such as renewing an expiring token or anonymizing a stale session.

  - `localeResolver`: `(request: NextRequest) => Promise<string|null>` (optional)

    A function that determines the locale for the current request.

    The function receives the request object and returns the locale as a string or `null` to use the default locale configured in the workspace.

    This is useful for websites that localize content based on the URL, subdomain, headers, or cookies.
