RudderStack's Transformations feature gives you the ability to code custom JavaScript functions to implement specific use-cases on your event data. This repository contains some useful transformation templates that you can use to create your own transformations.
For more information on RudderStack Transformations, refer to the documentation.
The sample transformations and libraries included in this repository can be added via the RudderStack dashboard. Follow these steps:
- In the RudderStack dashboard, go to Enhance > Transformations.
- Click New Transformations.
- Enter a name and description and add the code for the transformation or library.
- Click Save.
For detailed steps on adding a new transformation or library, refer to the documentation.
Filter out event if a property (event name in this example) is included in a denylist.
- Drop event if denylist includes event name
- Return event otherwise
export function transformEvent(event, metadata) {
const eventNames = ["game_load_time", "lobby_fps"];
const eventName = event.event;
if (eventName && eventNames.includes(eventName)) return;
return event;
}
Example Input and Output
Input | Output |
---|---|
{ "event": "game_load_time" } |
|
{ "event": "players" } |
{ "event": "players" } |
Filter out event if a property (email domain in this example) is not included in a allowlist.
- Return event if allowlist includes email domain
- Drop event otherwise
export function transformEvent(event, metadata) {
const domains = ["rudderstack.com", "rudderlabs.com"];
const email = event.context?.traits?.email;
if (email && domains.includes(email.split("@").pop())) return event;
return;
}
Example Input and Output
Input | Output |
---|---|
{ "context": { "traits": { "email": "john@gmail.com" } } } |
|
{ "context": { "traits": { "email": "john@rudderstack.com" } } } |
{ "context": { "traits": { "email": "john@rudderstack.com" } } } |
Drop a random sample of events based on a property (user ID in this example)
- Import
cyrb53
function from hash library - Drop event if remainder of hashed user ID less than 5
- Return event otherwise
import { cyrb53 } from "hash";
export function transformEvent(event, metadata) {
const userId = event.userId;
if (userId && cyrb53(userId) % 10 < 5) return;
return event;
}
Example Input and Output
Input | Output |
---|---|
{ "userId": "54321" } |
|
{ "userId": "12345" } |
{ "userId": "12345" } |
Enrich event with geolocation data using an external API and IP address
- Fetch geolocation data from external IP2Location API
- Add data to event
- Return event
export async function transformEvent(event, metadata) {
if (event.request_ip) {
const res = await fetch("<YOUR_API_ENDPOINT>" + event.request_ip); // Use your paid IP-to-geolocation API endpoint.
event.context.geolocation = res;
}
return event;
}
Example Input and Output
Input | Output |
---|---|
{ "context": { "ip": "64.233.160.0" } } |
{ "context": { "ip": "64.233.160.0", "geolocation": { "country_code": "US", "country_name": "United States", "region_name": "California", "city_name": "Mountain View", "latitude": "37.405992", "longitude": "-122.078515", "zip_code": "94043", "time_zone": "-07:00" } } } |
Enrich event with user data using an external API and email address
- Get user data from external Clearbit API
- Add data to event's traits
- Return event
export async function transformEvent(event) {
const email = event.context?.traits?.email;
if (email) {
const res = await fetch("https://person.clearbit.com/v2/combined/find?email=" + email, {
headers: {
"Authorization": "Bearer <your_clearbit_secure_key"
}
});
event.context.traits.enrichmentInfo = res;
}
return event;
}
Example Input and Output
Input | Output |
---|---|
{ "context": { "traits": { "email": "alex@alexmaccaw.com" } } } |
{ "context": { "traits": { "email": "john@gmail.com", "enrichmentInfo": { "id": "d54c54ad-40be-4305-8a34-0ab44710b90d", "name": { "fullName": "Alex MacCaw", "givenName": "Alex", "familyName": "MacCaw" }, "email": "alex@alexmaccaw.com", "location": "San Francisco, CA, US", "timeZone": "America/Los_Angeles", "utcOffset": -8, "geo": { "city": "San Francisco", "state": "California", "stateCode": "CA", "country": "United States", "countryCode": "US", "lat": 37.7749295, "lng": -122.4194155 }, "bio": "O'Reilly author, software engineer & traveller. Founder of https://clearbit.com", "site": "http://alexmaccaw.com", "avatar": "https://d1ts43dypk8bqh.cloudfront.net/v1/avatars/d54c54ad-40be-4305-8a34-0ab44710b90d", "employment": { "domain": "clearbit.com", "name": "Clearbit", "title": "Co-founder, CEO", "role": "leadership", "subRole": "ceo", "seniority": "executive" }, "facebook": { "handle": "amaccaw" }, "github": { "handle": "maccman", "avatar": "https://avatars.githubusercontent.com/u/2142?v=2", "company": "Clearbit", "blog": "http://alexmaccaw.com", "followers": 2932, "following": 94 }, "twitter": { "handle": "maccaw", "id": "2006261", "bio": "O'Reilly author, software engineer & traveller. Founder of https://clearbit.com", "followers": 15248, "following": 1711, "location": "San Francisco", "site": "http://alexmaccaw.com", "avatar": "https://pbs.twimg.com/profile_images/1826201101/297606_10150904890650705_570400704_21211347_1883468370_n.jpeg" }, "linkedin": { "handle": "pub/alex-maccaw/78/929/ab5" }, "googleplus": { "handle": null }, "gravatar": { "handle": "maccman", "urls": [ { "value": "http://alexmaccaw.com", "title": "Personal Website" } ], "avatar": "http://2.gravatar.com/avatar/994909da96d3afaf4daaf54973914b64", "avatars": [ { "url": "http://2.gravatar.com/avatar/994909da96d3afaf4daaf54973914b64", "type": "thumbnail" } ] }, "fuzzy": false, "emailProvider": false, "indexedAt": "2016-11-07T00:00:00.000Z" } } } } |
Enrich event with parsed user agent data
- Import
UAParser
function from user agent parser library - Add parsed user agent data
- Return event
import { UAParser } from "userAgentParser";
export function transformEvent(event, metadata) {
const userAgent = event.context?.userAgent;
if (userAgent) {
const parser = new UAParser();
const parsedUserAgent = parser.setUA(userAgent).getResult();
event.context.parsedUserAgent = parsedUserAgent;
}
return event;
}
Example Input and Output
Input | Output |
---|---|
{ "context": { "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:98.0) Gecko/20100101 Firefox/98.0" } } |
{ "context": { "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:98.0) Gecko/20100101 Firefox/98.0", "parsedUserAgent": { "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:98.0) Gecko/20100101 Firefox/98.0", "browser": { "name": "Firefox", "version": "98.0", "major": "98" }, "engine": { "name": "Gecko", "version": "98.0" }, "os": { "name": "Mac OS", "version": "10.15" }, "device": {}, "cpu": {} } } } |
Add a dynamic header to event payload
- Add dynamnic header to event
- Return event
export function transformEvent(event, metadata) {
event.header = {
dynamic_header_1: "dynamic_header_1_value",
dynamic_header_2: "dynamic_header_2_value"
};
return event;
}
Example Input and Output
Input | Output |
---|---|
{ "event": "Button Clicked" } |
{ "event": "Button Clicked", "header": { "dynamic_header_1": "dynamic_header_1_value", "dynamic_header_2": "dynamic_header_2_value" } } |
Dynamically append the event endpoint
- Add dynamic path to event's endpoint base URL
- Return event
export function transformEvent(event, metadata) {
const email = event.context?.traits?.email;
if (email) event.appendPath = `/search?email=${email}`;
return event;
}
Example Input and Output
Input | Output |
---|---|
{ "context": { "traits": { "email": "john@gmail.com" } } } |
{ "context": { "traits": { "email": "john@gmail.com" } }, "appendPath": "/search?email=john@gmail.com" } |
Fuzzy find and replace PII properties (social security number in this example)
- Import
walk
function from fuzzy find replace library - Replace values where keys approximately match target keys
- Return event
import { walk } from "fuzzyFindReplace";
export function transformEvent(event, metadata) {
const targetKeys = [
"SSN",
"Social Security Number",
"social security no.",
"social sec num",
"ssnum"
];
walk(event, targetKeys, "XXX-XX-XXXX");
return event;
}
Example Input and Output
Input | Output |
---|---|
{ "context": { "traits": { "socialSecurityNumber": "123-45-6789" } } } |
{ "context": { "traits": { "socialSecurityNumber": "XXX-XX-XXXX" } } } |
Remove all properties with null values
- Remove properties with null values
- Return event
export function transformEvent(event) {
if (event.properties) {
const keys = Object.keys(event.properties);
if (keys) {
keys.forEach(key => {
if (event.properties[key] === null) delete event.properties[key];
})
}
}
return event;
}
Example Input and Output
Input | Output |
---|---|
{ "properties": { "revenue": null, "quantity": 4 } } |
{ "properties": { "quantity": 4 } } |
Perform action if event is from a specific source
- Do something if event from specified source
- Return event
export function transformEvent(event, metadata) {
if (metadata(event).sourceId === "12345") {
// Do something
}
return event;
}
Change the type of an event (track to identify in this example)
- Change event from
track
toidentify
if conditions are met - Return event
export function transformEvent(event) {
let updatedEvent = event;
if (
event.type === "track" &&
event.event === "ide-authentication" &&
event.properties?.email &&
event.properties.email !== ""
) {
updatedEvent.type = "identify";
let updatedContext = event.context || {};
updatedContext.traits = updatedContext.traits || {};
updatedContext.traits.email = event.properties.email;
updatedEvent.context = updatedContext;
}
return updatedEvent;
}
Example Input and Output
Input | Output |
---|---|
{ "type": "track", "event": "ide-authentication", "properties": { "email": "john@gmail.com" } } |
{ "type": "identify", "event": "ide-authentication", "properties": { "email": "john@gmail.com" }, "context": { "traits": { "email": "john@gmail.com" } } |
Perform action for each event in a batch
- Do something for each event
- Return events
export function transformBatch(events, metadata) {
events.forEach(event => {
// Do something
});
return events;
}