On this page

SDK Middleware

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.

Maintenance SDKs support middleware, except the maintenance Browser SDK and legacy Ampli. Plugins replace middleware in the latest SDK and Ampli versions.

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 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 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

Was this helpful?