Skip to content

Commit dc4fcb8

Browse files
committed
Adding retrack destination function exammple
1 parent 72c80c8 commit dc4fcb8

File tree

3 files changed

+94
-1
lines changed

3 files changed

+94
-1
lines changed

Readme.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ this repo as the set of examples.
3535
- [Slack](./destinations/slack) - Adds a Gravatar icon to events with an email and sends messages to Slack
3636
- [Zendesk](./destinations/zendesk) - Create new Zendesk tickets triggered by events that you send
3737
- [Datadog](./destinations/datadog) - Sends a metric to datadog with high level message/event type as tags
38-
- [Optimizely](./destinations/optimizely) - Sends conversion metrix to optimizely.
38+
- [Optimizely](./destinations/optimizely) - Sends conversion metrix to optimizely
39+
- [Retrack](./destinations/retrack) - Intercepts track event, updates user identity and enriches said event
3940

4041
## Development
4142

destinations/retrack/Readme.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Re-track Custom Destination Function
2+
3+
Example of destination function which:
4+
* Intercepts track event from Segment source attached to it,
5+
* modifies userId and posts [alias](https://segment.com/docs/connections/spec/alias/) request, so Segment will know anticipated identity,
6+
* enriches event properties and posts [track](https://segment.com/docs/connections/spec/track/) request, so Segment will know enriched event,
7+
* all requests are being forwarded to another [Segment HTTP Tracking API Source](https://segment.com/docs/connections/sources/catalog/libraries/server/http-api/), given `apiKey` from function settings.
8+
9+
## Settings
10+
11+
- `apiKey` {String} ([write key of Segment HTTP Tracking API Source](https://segment.com/docs/connections/sources/catalog/libraries/server/http-api/))

destinations/retrack/handler.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/**
2+
* @typedef {Object} SegmentTrackEvent
3+
* @see {@link https://segment.com/docs/connections/spec/track/} for full track event spec
4+
* @see {@link https://segment.com/docs/connections/spec/common/} for full common fields spec
5+
* @property {String} event Track event name
6+
* @property {String} messageId Original API message identifier
7+
* @property {String} userId Tracked user id that we want to modify and re-track
8+
* @property {String} timestamp Timestamp of event in ISO 8601 format
9+
* @property {Object} properties Track event arbitrary properties, we want to add 3 own
10+
*/
11+
12+
/**
13+
* @typedef {Object} FunctionSettings
14+
* @property {String} apiKey Write key of source to forward alias and track events to
15+
*/
16+
17+
/**
18+
* Call Segment V1 API, using HTTP API Segment Source by write key
19+
* @see {@link https://segment.com/docs/connections/sources/catalog/libraries/server/http-api/} for source doc
20+
* @internal
21+
* @param {String} apiKey
22+
* @param {String<'alias'|'track'>} route
23+
* @param {Object} body
24+
* @return {Promise<void>}
25+
*/
26+
async function callSegmentAPI(apiKey, route, body) {
27+
let response;
28+
29+
try {
30+
response = await fetch(`https://api.segment.io/v1/${route}`, {
31+
method: 'POST',
32+
headers: {
33+
Authorization: `Basic ${btoa(`${apiKey}:`)}`,
34+
'Content-Type': 'application/json',
35+
},
36+
body: JSON.stringify(body),
37+
});
38+
} catch (error) {
39+
throw new RetryError(error.message);
40+
}
41+
42+
if (response.status >= 500 || response.status === 429) {
43+
throw new RetryError(`Failed with ${response.status}`);
44+
}
45+
}
46+
47+
/**
48+
* Handle track event
49+
* @param {SegmentTrackEvent} event
50+
* @param {FunctionSettings} settings
51+
* @return {Promise<void>}
52+
*/
53+
async function onTrack(event, settings) {
54+
const { apiKey } = settings;
55+
56+
if (!apiKey) {
57+
throw new ValidationError('Forward source write key is required');
58+
}
59+
60+
const anticipatedId = crypto.createHash('md5').update(event.userId).digest('hex');
61+
62+
const [slug1, slug2, slug3] = event.userId.split('-');
63+
64+
await Promise.all([
65+
callSegmentAPI(apiKey, 'alias', {
66+
previousId: event.userId,
67+
userId: anticipatedId,
68+
timestamp: event.timestamp,
69+
}),
70+
callSegmentAPI(apiKey, 'track', {
71+
event: event.event,
72+
userId: anticipatedId,
73+
properties: {
74+
...event.properties,
75+
slug1,
76+
slug2,
77+
slug3,
78+
},
79+
}),
80+
]);
81+
}

0 commit comments

Comments
 (0)