π Join RudderStack Transformations Challenge (Last date - Apr 7, 2023)
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
cyrb53function 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("https://ip2.app/info.php?ip=" + event.request_ip);
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
UAParserfunction 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
walkfunction 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
tracktoidentifyif 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;
}