> This page is for Applications Protection.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.humansecurity.com/llms.txt.

# Installation (Next.js 16)

In Next.js 16, [middleware was renamed to **proxy**](https://nextjs.org/docs/messages/middleware-to-proxy). The key differences are:

* **File:** `proxy.ts` (or `proxy.js`) replaces `middleware.ts`.
* **Export:** The handler function should be exported as `proxy` (named export) or as the default export.
* **Runtime:** Proxy runs on the **Node.js** runtime by default (middleware previously defaulted to Edge).

The `NextRequest` and `NextResponse` APIs remain the same. The HUMAN Enforcer works identically in both conventions—the only difference is the file name and the export name.

> **Note**
>
> `middleware.ts` is still supported in Next.js 16, but it is deprecated and will be removed in a future version. We recommend migrating to `proxy.ts`.

## Prerequisites

* Next.js 16 or newer
* Node.js 20.9+ (required by Next.js 16)
* An existing Next.js application. If you don't have one, [create a new application](https://nextjs.org/docs/getting-started).
* Your unique HUMAN information:
  * Application ID
  * Cookie encryption key
  * Authentication token

## Installing the NextJS Enforcer

Integrate the HUMAN Enforcer into your NextJS project by setting it as a [proxy](https://nextjs.org/docs/app/getting-started/proxy) in your project.

While only one `proxy.ts` file is supported per project, you can still organize your logic modularly. Placing the HUMAN Enforcer proxy first ensures that all incoming requests are evaluated for security threats before any other processing occurs. If you have additional logic, use the `onPass` and `onResponse` custom functions.

### Installation

1. Install the HUMAN NextJS Enforcer NPM package into your existing NextJS project.

```shell
npm install --save perimeterx-nextjs
```

2. In the root directory of your project, create a `proxy.ts` (or `proxy.js` if you're using JavaScript) file to configure and set up the HUMAN proxy.
3. Initiate a configuration object containing `px_app_id` (your Application ID), `px_cookie_secret` (your cookie encryption key), and `px_auth_token` (your authentication token). Import and use the `perimeterx` function.

> **Note**
>
> You can also use a default export: `export default perimeterx(pxConfig)`. Both forms are supported by Next.js 16.

```ts
import { perimeterx } from "perimeterx-nextjs";
import { PerimeterXConfigurations } from "perimeterx-nextjs";

// define HUMAN configuration
const pxConfig: PerimeterXConfigurations = {
    px_app_id: '<APP_ID>',
    px_cookie_secret: '<COOKIE_SECRET>',
    px_auth_token: '<AUTH_TOKEN>',
}
export const proxy = perimeterx(pxConfig)
```

### Optional: route matcher

To limit which routes the proxy (and thus the Enforcer) runs on, export a `config` object alongside the proxy:

```ts
import { perimeterx } from "perimeterx-nextjs";
import { PerimeterXConfigurations } from "perimeterx-nextjs";

const pxConfig: PerimeterXConfigurations = {
    px_app_id: '<APP_ID>',
    px_cookie_secret: '<COOKIE_SECRET>',
    px_auth_token: '<AUTH_TOKEN>',
}
export const proxy = perimeterx(pxConfig)

export const config = {
    matcher: [
        // Run on all paths except static assets and metadata files
        '/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)',
    ],
}
```

See the [Next.js proxy documentation](https://nextjs.org/docs/app/api-reference/file-conventions/proxy) for full matcher syntax.

### If you already use middleware/proxy in your project

Add implementation to the built-in `onResponse` and `onPass` custom functions in your configuration object, in order to execute your own logic after HUMAN verifies the request.

#### onPass

Define what to do when requests pass HUMAN enforcement.

* Parameters
  * request: [NextRequest](https://nextjs.org/docs/app/api-reference/functions/next-request)
* Returns a [NextResponse](https://nextjs.org/docs/app/api-reference/functions/next-response) object (or a Promise resolving to a NextResponse)

```typescript
const pxConfig: PerimeterXConfigurations = {
    px_app_id: '<APP_ID>',
    px_cookie_secret: '<COOKIE_SECRET>',
    px_auth_token: '<AUTH_TOKEN>',
    onPass: (request: NextRequest) => {
        const response = NextResponse.next();
        response.headers.set('test-header', 'test');

        // Return the customized response
        return response;
    },
    // ...
}

export const proxy = perimeterx(pxConfig)
```

#### onResponse

This function allows modification of the response when HUMAN decides to return a custom response—for example, in case of block, static resources, etc.

* Parameters
  * request: [NextRequest](https://nextjs.org/docs/app/api-reference/functions/next-request)
  * response: [NextResponse](https://nextjs.org/docs/app/api-reference/functions/next-response)
* Returns a [NextResponse](https://nextjs.org/docs/app/api-reference/functions/next-response) object (or a Promise resolving to a NextResponse)

```typescript
const pxConfig: PerimeterXConfigurations = {
    px_app_id: '<APP_ID>',
    px_cookie_secret: '<COOKIE_SECRET>',
    px_auth_token: '<AUTH_TOKEN>',
    onResponse: (request: NextRequest, response: NextResponse) => {
        const nextResponse = NextResponse.next();
        nextResponse.headers.set('X-PX-Status', response.headers.get('test'));

        // Return the customized response
        return nextResponse;
    },
    // ...
}

export const proxy = perimeterx(pxConfig)
```

## Client IP in the Node.js proxy runtime

In Next.js 16, the proxy runs on the Node.js runtime by default. In some deployment environments, `request.ip` may not be populated. The Enforcer automatically falls back to the `x-forwarded-for` header when `request.ip` is unavailable.

If you run behind a load balancer or reverse proxy and need accurate client IP resolution, configure `px_ip_headers` so the Enforcer knows which header(s) to use:

```typescript
const pxConfig: PerimeterXConfigurations = {
    px_app_id: '<APP_ID>',
    px_cookie_secret: '<COOKIE_SECRET>',
    px_auth_token: '<AUTH_TOKEN>',
    px_ip_headers: ['x-forwarded-for', 'x-real-ip'],
}

export const proxy = perimeterx(pxConfig)
```

The headers are traversed in the order listed. The first header with a non-empty value is used as the client IP.

## Migrating from middleware.ts (Next.js 14/15)

If you are upgrading an existing Next.js 14/15 application that already uses the HUMAN Enforcer via `middleware.ts`:

1. Rename `middleware.ts` to `proxy.ts`.
2. Change the export from `export const middleware = perimeterx(pxConfig)` (or `export default`) to `export const proxy = perimeterx(pxConfig)` (or keep `export default`).
3. No changes are needed to the configuration object or any `onPass`/`onResponse` handlers — they work exactly the same.

Next.js also provides an automated codemod for the rename:

```sh
npx @next/codemod@canary middleware-to-proxy .
```

All configuration options from the [Configuration](/applications/nextjs/configuration) page remain fully supported. No changes to Enforcer configuration are required when upgrading to Next.js 16.