SDK Middleware

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

Note

Middleware is only supported in Maintenance SDKs except the maintenance Browser SDK and legacy Ampli. Middleware has been replaced by Plugins in the latest SDK and Ampli versions.

Middleware Structure

Function Signature

Each middleware is a simple function with this signature:

1/**
2 * A function to run on the Event stream (each logEvent call)
3 *
4 * @param payload The `payload` contains the `event` to send and an optional `extra` that lets you pass custom data to your own middleware implementations.
5 * @param next Function to run the next middleware in the chain, not calling next will end the middleware chain
6 */
7 
8function (payload: MiddlewarePayload: next: MiddlewareNext): void;

Types in middleware:

Name
Type Description
MiddlewarePayload.event Event The event data being sent. The event may vary by platform.
MiddlewarePayload.extra { [x: string]: any } Unstructured object to let users pass extra data to middleware.
MiddlewareNext (payload: MiddlewarePayload) => void Function called at the end of each Middleware to run 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, then the event processing stops executing after the current middleware completes.

Payload Customization

Middleware access to event fields may vary by platform. To ensure comprehensive access, Amplitude recommends updating to the latest Ampli version and utilizing the Plugins feature.

For Browser Ampli, the following are the accessible keys under payload.

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

For other platforms, middleware can access and modify the entire Event JSON object, allowing for comprehensive adjustments as needed. Learn more at here.

Use

Add middleware to Amplitude via amplitude.addEventMiddleware(). You can add as many middleware as you like. Each middleware runs in the order in which it's added.

1amplitude.addEventMiddleware(yourMiddleware());

Middleware examples

Use an Middleware to modify event properties, transformation, filtering, routing to third-party destinations, and more:

Filtering middleware

1 amplitude.addEventMiddleware((payload, next) => {
2 const {eventType} = payload.event;
3 if (shouldSendEvent(eventType)) {
4 next(payload)
5 } else {
6 // event will not continue to following middleware or be sent to Amplitude
7 console.log(`Filtered event: ${eventType}`);
8 }
9});

Remove PII (Personally Identifiable Information)

1amplitude.addEventMiddleware((payload, next) => {
2 const { event } = payload;
3 if (hasPii(event.event_properties)) {
4 payload.event.event_properties = obfuscate(payload.event.event_properties);
5 }
6 next(payload);
7});

Enrich Event Properties

1amplitude.addEventMiddleware((payload, next) => {
2 const { event } = payload;
3 if (needsDeviceId(event)) {
4 payload.event.deviceId = getDeviceId();
5 }
6 next(payload)
7});

Send event level groups using Ampli v1

This is an example of how to send event level groups in Ampli V1. How to send event level groups in SDKs(not in Ampli) is different. Please check the specific SDKs for the usage.

1ampli.addEventMiddleware((payload, next) => {
2 const {event, extra} = payload;
3 if (event && extra && event.extra.groups) {
4 event.groups = event.extra.groups;
5 }
6 
7 next(payload);
8});
9 
10// Pass the event level groups info though middleware extra when calling the tracking plan.
11const extra = {groups: {"test_group_name": "test_group_value"}};
12ampli.eventWithGroups({requiredNumber: 1.23, requiredBoolean: false}, extra);

Forward data to other services

1import amplitude from 'amplitude/sdk'
2import adroll from 'adroll';
3import segment from 'segment';
4import snowplow from 'snowplow';
5 
6amplitude.addEventMiddleware((payload, next) => {
7 const { event, extra } = payload;
8 segment.track(event.event_type, event.event_properties, { extra.anonymousId })
9 adroll.track();
10 snowplow.track(event.event_type, event.event_properties, extra.snowplow.context);
11 // next();
12});

Use client-side validation (click to expand)

1amplitude.addEventMiddleware((payload, next) => {
2 if (isDevelopment && !SchemaValidator.isValid(payload.event)) {
3 throw Error(`Invalid event ${event.event_type}`);
4 }
5 next(payload);
6});

Supported SDKs

Platform SDK Github
Android com.amplitude:android-sdk :material-github: Amplitude-Android
Node.js @amplitude/node :material-github: Amplitude-Node
React Native @amplitude/react-native :material-github: Amplitude-ReactNative
iOS Amplitude :material-github: Amplitude-iOS
Java com.amplitude.:java-sdk :material-github: Amplitude-Java
Was this page helpful?

Thanks for your feedback!

June 16th, 2024

Need help? Contact Support

Visit Amplitude.com

Have a look at the Amplitude Blog

Learn more at Amplitude Academy

© 2024 Amplitude, Inc. All rights reserved. Amplitude is a registered trademark of Amplitude, Inc.