Middleware lets you extend Amplitude by running a sequence of custom code on every event. This pattern is flexible — use it to support event enrichment, transformation, filtering, routing to third-party destinations, and more.


{% callout type="note" heading="" %}
Maintenance SDKs support middleware, except the maintenance Browser SDK and legacy Ampli. [Plugins](/docs/sdks/sdk-plugins) replace middleware in the latest SDK and Ampli versions.
{% /callout %}

## Middleware structure
 
### Function signature

Each middleware is a simple function with this signature:

```js
/**
 * A function to run on the Event stream (each logEvent call)
 *
 * @param payload The `payload` contains the `event` to send and an optional `extra` that lets you pass custom data to your own middleware implementations.
 * @param next Function to run the next middleware in the chain, not calling next will end the middleware chain
 */

function (payload: MiddlewarePayload: next: MiddlewareNext): void;
```

Types in middleware:

- **`MiddlewarePayload.event`**
  - **Type**: Event.
  - **Description**: The event data to send. The event can vary by platform.
- **`MiddlewarePayload.extra`**
  - **Type**: { [x: string]: any }.
  - **Description**: Unstructured object that lets users pass extra data to middleware.
- **`MiddlewareNext`**
  - **Type**: (payload: MiddlewarePayload) => void.
  - **Description**: Function that runs at the end of each middleware to invoke the next middleware in the chain.

To invoke the next middleware in the queue, use the `next` function. You must call `next(payload)` to continue the middleware chain. If a middleware doesn't call `next`, event processing stops after the current middleware completes.

### Payload customization

Middleware access to event fields can vary by platform. For comprehensive access, Amplitude recommends updating to the latest Ampli version and using the [Plugins](/docs/sdks/sdk-plugins) feature.

For Browser Ampli, the accessible keys under `payload` are as follows.

- **`event.event_type`**
  - **Type**: string.
  - **Description**: The event name.
- **`event.event_properties`**
  - **Type**: { [key: string]: any }.
  - **Description**: The event properties.
- **`event.user_id`**
  - **Type**: string.
  - **Description**: The event-level user ID.
- **`event.device_id`**
  - **Type**: string.
  - **Description**: The event-level device ID.
- **`event.user_properties`**
  - **Type**: { [key: string]: any }.
  - **Description**: The event-level user properties.
- **`extra`**
  - **Type**: { [x: string]: any }.
  - **Description**: Extra information that lets you pass custom data to your own middleware implementations.

For other platforms, middleware can access and modify the entire Event JSON object for comprehensive adjustments. Go to the [event array keys reference](/docs/apis/analytics/http-v2#event-array-keys) for the full schema.

### Use

Add middleware to Amplitude with `amplitude.addEventMiddleware()`. You can add as many middleware as you like. Each middleware runs in the order you add it.

```js
amplitude.addEventMiddleware(yourMiddleware());
```

## Middleware examples

Use middleware to modify event properties, transform data, filter events, route to third-party destinations, and more.


### Filtering middleware

```ts
    amplitude.addEventMiddleware((payload, next) => {
    const {eventType} =  payload.event;
    if (shouldSendEvent(eventType)) {
    next(payload)
    } else {
    // event doesn't continue to following middleware or get sent to Amplitude
    console.log(`Filtered event: ${eventType}`);
    }
});
```
        
### Remove PII (personally identifiable information)

```js
amplitude.addEventMiddleware((payload, next) => {
    const { event } = payload;
    if (hasPii(event.event_properties)) {
    payload.event.event_properties = obfuscate(payload.event.event_properties);
    }
    next(payload);
});
```
    
### Enrich event properties

```js
amplitude.addEventMiddleware((payload, next) => {
    const { event } = payload;
    if (needsDeviceId(event)) {
    payload.event.deviceId = getDeviceId();
    }
    next(payload)
});
```

### Send event-level groups using Ampli v1

This example shows how to send event-level groups in Ampli v1. Sending event-level groups in SDKs (not in Ampli) works differently. Check the specific SDKs for usage details.

```js
ampli.addEventMiddleware((payload, next) => {
    const {event, extra} =  payload;
    if (event && extra && event.extra.groups) {
    event.groups =  event.extra.groups;
    }

    next(payload);
});

// Pass the event-level groups info through middleware extra when calling the tracking plan.
const extra = {groups: {"test_group_name": "test_group_value"}};
ampli.eventWithGroups({requiredNumber: 1.23, requiredBoolean: false}, extra);
```


### Forward data to other services

```js
import amplitude from 'amplitude/sdk'
import adroll from 'adroll';
import segment from 'segment';
import snowplow from 'snowplow';

amplitude.addEventMiddleware((payload, next) => {
    const { event, extra } = payload;
    segment.track(event.event_type, event.event_properties, { extra.anonymousId })
    adroll.track();
    snowplow.track(event.event_type, event.event_properties, extra.snowplow.context);
    // next();
});
```


### Use client-side validation

```js
amplitude.addEventMiddleware((payload, next) => {
    if (isDevelopment && !SchemaValidator.isValid(payload.event)) {
    throw Error(`Invalid event ${event.event_type}`);
    }
    next(payload);
});
```

## Supported SDKs

| Platform                                                                       | SDK                                                                                                               | Github                                                                                        |
| ------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| [Android](/docs/sdks/analytics/android/android-sdk#middleware)                 | [`com.amplitude:android-sdk`](https://mvnrepository.com/artifact/com.amplitude/android-sdk) | [:material-github: Amplitude-Android](https://github.com/amplitude/Amplitude-Android)         |
| [Node.js](/docs/sdks/analytics/node/node-sdk#middleware)                       | [`@amplitude/node`](https://www.npmjs.com/package/@amplitude/node)                          | [:material-github: Amplitude-Node](https://github.com/amplitude/Amplitude-Node)               |
| [React Native](/docs/sdks/analytics/react-native/react-native-sdk-maintenance) | [`@amplitude/react-native`](https://www.npmjs.com/package/@amplitude/react-native)          | [:material-github: Amplitude-ReactNative](https://github.com/amplitude/Amplitude-ReactNative) |
| [iOS](/docs/sdks/analytics/ios/ios-sdk#middleware)                             | [`Amplitude`](https://cocoapods.org/pods/Amplitude-iOS)                                     | [:material-github: Amplitude-iOS](https://github.com/amplitude/Amplitude-iOS)                 |
| [Java](/docs/sdks/analytics/java/jre-java-sdk#middleware)                      | [`com.amplitude.:java-sdk`](https://mvnrepository.com/artifact/com.amplitude/java-sdk)      | [:material-github: Amplitude-Java](https://github.com/amplitude/Amplitude-Java)               |