SDK Plugins
Plugins extend Amplitude's behavior. This flexible pattern supports event enrichment, transformation, filtering, routing to third-party destinations, and more.
Plugin methods
A plugin is an object with two methods, setup() and execute():
Plugin.setup
This method prepares the plugin for use and takes config as a parameter. It returns undefined. A typical use copies configuration from config or instantiates plugin dependencies. Amplitude calls this method when you register the plugin with amplitude.add().
Plugin.execute
This method processes events and takes event as a parameter. For an enrichment-type plugin, it returns the modified or enriched event. For a destination-type plugin, it returns a map with keys: event (BaseEvent), code (number), and message (string). Amplitude calls this method for each event, including Identify, GroupIdentify, and Revenue events instrumented through the client interface.
Add a plugin to Ampli with amplitude.add(). You can add as many plugins as you want. Each plugin runs in order based on the plugin type.
amplitude.add(yourPlugin())
If execute() doesn't return an event, the event doesn't propagate through the remaining plugins.
Enrichment plugins
Enrichment plugins modify properties in Event objects or drop an event. For the available keys for the Event object, refer to the HTTP V2 API reference.
Drop an event
import * as amplitude from '@amplitude/analytics-browser';
import {PluginType} from '@amplitude/analytics-types';
class FilterEventsPlugin {
name = 'filter-events-plugin';
type = PluginType.ENRICHMENT;
async setup(config) {
return undefined;
}
async execute(event) {
// ignore events with a certain property
if (event.event_properties['ignore'] === true){
// returning null will prevent this event from being processed by subsequent plugins
return null;
}
// Allow other events to be processed and sent to destination plugins
return event;
}
}
amplitude.add(new FilterEventsPlugin());
amplitude.init('API_KEY');
Set universal user properties
import * as amplitude from '@amplitude/analytics-browser';
import {PluginType} from '@amplitude/analytics-types';
class PropertiesEnrichmentPlugin {
name = 'properties-plugin';
type = PluginType.ENRICHMENT;
async setup(_, amplitude) {
if (shouldSetUserProperties) {
const identifyEvent = new amplitude.Identify();
identifyEvent.set("testKey", "testValue");
amplitude.identify(identifyEvent);
}
return undefined;
}
async execute(event) {
return event
}
}
amplitude.add(new PropertiesEnrichmentPlugin());
amplitude.init('API_KEY');
Remove personally identifiable information (PII)
import * as amplitude from '@amplitude/analytics-browser';
import {PluginType} from '@amplitude/analytics-types';
class FilterEventsPlugin {
name = 'remove-PII-plugin';
type = PluginType.ENRICHMENT;
async setup(config) {
return undefined;
}
async execute(event) {
// remove PII on the event
if(event.user_properties['phone']) {
delete event.user_properties['phone'];
// set a new prop to mark this event as modified
event.event_properties['pii-removed'] = true;
}
// return modified event with PII removed
return event
}
}
amplitude.init('API_KEY');
amplitude.add(new FilterEventsPlugin());
Send event level groups with Ampli v2
This example shows how to send event-level groups in Ampli V2. Sending event-level groups in SDKs (not in Ampli) works differently. Check the specific SDK for usage details.
import * as amplitude from '@amplitude/analytics-browser';
import {PluginType} from '@amplitude/analytics-types';
class EventLevelGroupPlugin {
name = 'group-plugin';
type = PluginType.ENRICHMENT;
async setup(config) {
return undefined;
}
async execute(event) {
event.groups = event.extra['groups'];
return event;
}
// Allow other events to be processed and sent to destination plugins
return event;
}
ampli.client.add(new EventLevelGroupPlugin());
const extra = {extra: { groups: ["test_group_name": "test_group_value"]}};
ampli.eventWithGroups({requiredNumber: 1.23, requiredBoolean: false}, extra);
Destination plugins
Use a destination plugin to send events to third-party APIs.
Send to Segment
First, follow Segment's guide to install the Segment Analytics.js 2.0 Web SDK.
import { AnalyticsBrowser } from '@segment/analytics-next';
import { Types } from '@amplitude/analytics-browser';
export default class SegmentPlugin {
name = 'segment';
type = Types.PluginType.DESTINATION;
constructor(private readonly writeKey) {
// Create Segment tracker
this.segment = new AnalyticsBrowser();
}
async setup(config) {
this.segment.load({
writeKey: this.writeKey,
});
return;
}
execute(context) {
return new Promise(resolve => {
const {
event_type,
event_properties,
user_id,
user_properties,
groups,
group_properties,
} = context;
const callback = (ctx) => {
resolve({ event: context, code: 200, message: '' });
};
switch (event_type) {
case Types.SpecialEventType.IDENTIFY:
case Types.SpecialEventType.GROUP_IDENTIFY:
const groupValues = groups ? Object.values(groups) : [];
if (groupValues.length === 0) {
this.segment.identify(
user_id,
user_properties?.[Types.IdentifyOperation.SET],
{},
callback,
);
} else {
this.segment.group(
groupValues[0],
group_properties?.[Types.IdentifyOperation.SET],
{},
callback,
);
}
break;
case 'page':
// @ts-ignore
const { name, category, ...properties } = event_properties;
this.segment.page(category, name, properties, {}, callback);
break;
default:
this.segment.track(event_type, event_properties, {}, callback);
break;
}
});
}
}
Send to Hotjar
Before you begin, refer to Hotjar's tracking code.
import { PluginType } from "@amplitude/analytics-types"
import { default as hj } from "@hotjar/browser"
export class HotjarPlugin {
name = "hotjar"
type = PluginType.DESTINATION
constructor(siteId, hotjarVersion, debug = false) {
this.siteId = siteId
this.hotjarVersion = hotjarVersion
}
async setup() {
hj.init(this.siteId, this.hotjarVersion)
}
async execute(event) {
if (event.event_type === "$identify") {
const { user_id, device_id, user_properties } = event
const hotjarId = user_id || device_id || ""
hj.identify(hotjarId, user_properties || {})
} else {
hj.event(event.event_type)
}
return {
code: 0,
event: event,
message: "Event forwarded to Hotjar SDK"
}
}
}
Send to Google Analytics
Before you begin, refer to the documentation for Google's Data Layer.
import { PluginType } from "@amplitude/analytics-types"
export class GTMPlugin {
name = "google-tag-manager"
type = PluginType.DESTINATION
constructor(containerId) {
this.containerId = containerId
}
async setup() {
if (!window.dataLayer) {
window.dataLayer = window.dataLayer || []
window.dataLayer.push({
"gtm.start": new Date().getTime(),
event: "gtm.js"
})
const head = document.getElementsByTagName("head")[0],
script = document.createElement("script");
script.async = true
script.src =
`https://www.googletagmanager.com/gtm.js?id=${this.containerId}&l=datalayer`
head.insertBefore(script, head.firstChild)
}
}
async execute(event) {
window.dataLayer.push(event)
return {
code: 200,
event: event,
message: "Event pushed onto GTM Data Layer"
}
}
}
Send to FullStory
Before you begin, refer to the documentation for FullStory's browser SDK.
import { PluginType } from '@amplitude/analytics-types';
export class FullstoryPlugin {
constructor(fsOrg) {
this.name = 'fullstory';
this.type = PluginType.DESTINATION;
this.fsOrg = fsOrg;
this.FS = window.FS;
}
async setup() {
window._fs_host || (window._fs_host = "fullstory.com", window._fs_script = "edge.fullstory.com/s/fs.js", window._fs_org = this.fsOrg, window._fs_namespace = "FS", function (n, t, e, o, s, c, i, f) { e in n ? n.console && n.console.log && n.console.log('FullStory namespace conflict. Please set window["_fs_namespace"].') : ((i = n[e] = function (n, t, e) { i.q ? i.q.push([n, t, e]) : i._api(n, t, e); }).q = [], (c = t.createElement(o)).async = 1, c.crossOrigin = "anonymous", c.src = "https://" + _fs_script, (f = t.getElementsByTagName(o)[0]).parentNode.insertBefore(c, f), i.identify = function (n, t, e) { i(s, { uid: n }, e), t && i(s, t, e); }, i.setUserVars = function (n, t) { i(s, n, t); }, i.event = function (n, t, e) { i("event", { n: n, p: t }, e); }, i.anonymize = function () { i.identify(!1); }, i.shutdown = function () { i("rec", !1); }, i.restart = function () { i("rec", !0); }, i.log = function (n, t) { i("log", [n, t]); }, i.consent = function (n) { i("consent", !arguments.length || n); }, i.identifyAccount = function (n, t) { c = "account", (t = t || {}).acctId = n, i(c, t); }, i.clearUserCookie = function () { }, i.setVars = function (n, t) { i("setVars", [n, t]); }, i._w = {}, f = "XMLHTTPRequest", i._w[f] = n[f], f = "fetch", i._w[f] = n[f], n[f] && (n[f] = function () { return i._w[f].apply(this, arguments); }), i._v = "1.3.0"); }(window, document, window._fs_namespace, "script", "user"));
this.FS = window.FS;
}
async execute(event) {
if (event.event_type === '$identify') {
this.FS.identify(event.user_id);
}
else {
this.FS.event(event.event_type, event.event_properties);
}
return {
code: 200,
event: event,
message: 'Event forwarded to Fullstory',
};
}
}
Supported SDKs
Was this helpful?