Example of destination created with the J0 sandbox in the Destination Builder
The Destination builder allows you to create custom server-side destinations using server-side javascript (aka Node.js), but with an easy and simplified subset of Node.js : the Javascript Sandbox.
This tutorial will teach you the basics of writing your own server-side destination template and publish it in your own destination catalog(s).
A server-side destination receive incoming event data from your sources, transform it, and send the data wherever you want. As long as the destination tool accepts HTTP requests, it can accept data from a server-side destination.
In this tutorial, you will create a destination that sends event data to Slack using a single webhook_url
parameter. Slack is a messaging and collaboration tool that supports webhook integration. The Use cas can be : "I want to receive on a Slack channel a message each time an event "sign_up" is received"
To begin, create the destination template by navigating to the Destination section in the menu and clicking New in the Destination Builder section. Then, give your destination a name, a logo, a category and a description.
Then, go to the Fields section of the editor to add settings options for your destination. You have three options for building your destination:
Total Configuration: Create a configuration field for every parameter, allowing the user to set everything explicitly.
No Configuration: Do not include any options for configuring the destination. Instead, all data is taken directly from the event.
Some Configuration: Include fields for some parameters but not others.
While having a field for every parameter is flexible, it can result in a lot of duplicated work for the user. Therefore, it is best to have the code handle the configuration of unambiguous and universal data. For example, if you are building an analytics destination, you don't want to ask to the user to enter the URL of the analytics API every time he will setup this destination. You will prefer to hardcode the URL inside your code without to ask user to enter it. On the other hand, if you build your destination to get the data only from the event, without adding any field in the settings for the user, the user will not be able to personnalize the destination. For example, if the destination required a token, this token may vary according to the context (prod, dev, country...), so if you hardcode one token in the code... Or, perhaps the assumptions made by the destination regarding the structure of the incoming event data do not align with the actual reality for custom events/properties. In both scenarios, the user is unable to proceed.
In conclusion, some data should always be extracted from the event while other data needs to be configured by the user. It is up to you to decide so that the end result is user-friendly.
In the case of our Slack destination, we will want to add one field so that the user can copy/paste its Slack's webhook url. We choose a text input like this:
Now, we can go to the Code tab, starting to write the code of our destination template.
You may want to get 2 types of data :
user-entered data (fields filled in the settings tab)
event data (some properties of your event that you want to send to the partner)
All data filled in the differents fields by the user are accessible in the data
object in your code.
In your example, we have only one field named "url", and the value that the end-user will enter will be accessible via data.url
You will want to get some properties of your events to send them to the partner server. You can use one of this 2 functions to get your event data :
getAllEventData() => will return an object will all the event properties
getEventData(myProperty) =>will return the value of a specific property in your event
After setting up the destination configuration, you can proceed to implement its behavior in the JavaScript Sandbox.
The Slack example requires the following four steps:
Obtain the webhook URL from the destination's settings.
Create the message that will be sent to the Slack API.
Send a request to the Slack collection server to transmit the data.
Test your code, to make sure that the destination will behave appropriately in production.
It's important to note that the code should not perform certain actions, as they are the responsibility of the filter tab. Specifically, the code should not:
Manage the consent to determine wether the event should be send or not. It is the responsability of the consent category dropdown in the Filter tab. It is important not to override this feature, to not break the Data Governance reports
Analyze the event properties to determine whether it should be executed. Don't forget that the user will be able to choose in the Filter tab wich event will be sent to the destination. You may want to restrict your code to some event's type, but you should not remove the user's ability to filter his events on certain properties (ex : the user may want to send only events with property "country" equals to "UK")
Return an global error (data.onFailure()
) when some event's type does not fit the destination. Prefer to use silent error with data.onFailure({ status: 'filtered'})
If you create a destination template that performs any of these actions, it can cause confusion for users of your destination. For instance, a destination that sends errors to Event Delivery whenever unsupported events are detected can lead to unnecessary warnings in Health reports. This would violate users' expectations regarding the expected behavior of the destination.
With this in mind, here is an annotated example of the tag implementation in JavaScript sandbox:
Note that the data.onSuccess()
is mandatory in your code.
The data.onSuccess()
and data.onFailure()
values tell the platform when the destination has completed or failed its task, and are then used as a signal for Event Delivery dashboard and Destination Live Invent Inspector
This article describes the server-side destination APIs.
decodeURI
Decodes any encoded characters in the provided URI. Returns a string that represents the decoded URI. Returns undefined
when provided with invalid input.
Syntax
Example
encoded_uri
string
decodeUriComponent
Decodes any encoded characters in the provided URI component. Returns a string that represents the decoded URI component. Returns undefined
when given invalid input.
Syntax
Example
encoded_uri_component
string
encodeUri
Returns an encoded Uniform Resource Identifier (URI) by escaping special characters. Returns a string that represents the provided string encoded as a URI.
Syntax
Example
uri
string
A complete URI.
encodeUriComponent
Returns an encoded Uniform Resource Identifier (URI) by escaping special characters. Returns a string that represents the provided string encoded as a URI.
Syntax
Example
str
string
A component of a URI.
fromBase64
Decodes a base64-encoded string. Returns undefined
if the input is invalid.
Syntax
Example
base64EncodedString
string
Base64 encoded string.
generateRandom
Returns a random number (integer) within the given range.
Syntax
Example
min
number
Minimum potential value of the returned integer (inclusive).
max
number
Maximum potential value of the returned integer (inclusive).
getAllEventData
Returns a copy of the event data.
Syntax
Usage Example
Notice that the event data may contains more properties that what you sent initially because of system properties that are added automatically on web events and app sdk events.
Data example:
If you send this web event:
Then the getAllEventData() function will return this object:
getCookieValues
Returns an array containing the values of all cookies with the given name.
Syntax
Example
Parameters
name
string
Name of the cookie.
noDecode
boolean
If true
, the cookie values will not be decoded before being returned. Defaults to false
.
getEventData
Returns a copy of the value at the given path in the event data. Returns undefined
if there is no event data or if there is no value at the given path.
Syntax
Example
Parameters
keyPath
any
The path of the key, where path components are separated by dots. The path components can be keys in an object or indices in an array. If keyPath
is not a string, it is coerced into a string.
getRemoteAddress
Returns a string representation of the IP address where the request originated, e.g. 62.123.65.780
for IPv4 or 2001:0db8:85a3:0:0:8a2e:0370:1234
for IPv6
Syntax
getTimestamp
Deprecated. Prefer getTimestampMillis.
Returns a number that represents the current time in milliseconds since Unix epoch, as returned by Date.now()
.
Syntax
getTimestampMillis
Returns a number that represents the current time in milliseconds since Unix epoch, as returned by Date.now()
.
Syntax
getType
Returns a string describing the given value's type.
string
'string'
number
'number'
boolean
'boolean'
null
'null'
undefined
'undefined'
Array
'array'
Object
'object'
Function
'function'
Syntax
Example
Parameters
value
any
Input value.
logToConsole
Logs its argument(s) to the console.
These logs are visible within Destination Builder's console.
Example
Syntax
Parameters
The function takes one or more arguments, each of which is converted to a string, if necessary, and logged to the console.
makeInteger
Converts the given value to a number (integer).
Syntax
Parameters
value
any type
The value to convert.
makeNumber
Converts the given value to a number.
Syntax
Parameters
value
any type
The value to convert.
makeString
Returns the given value as a string.
Syntax
Parameters
value
any type
The value to convert.
parseUrl
Returns an object that contains all of a given URL's component parts, similar to the URL
object.
This API will return undefined
for any malformed URL. For properly formatted URLs, fields not present in the URL string will have a value of an empty string, or in the case of searchParams
, an empty object.
The returned object will have the following fields:
Syntax
Example
Parameters
url
string
The full url that will be parsed.
sha256
Calculates the SHA-256 digest of the input and invokes a callback with the digest encoded in base64, unless the options
object specifies a different output encoding.
This API signature and behavior matches the sha256
API for web containers; however, Custom Templates in server containers should use the sha256Sync
API for simpler code.
Syntax
Example
Parameters
input
string
The string to hash.
onSuccess
function
Called with the resulting digest, encoded in base64, unless the options
object specifies a different output encoding.
options
object
Optional options object to specify the output encoding. If specified, the object should contain the key outputEncoding
with value as one of base64
or hex
.
sha256Sync
Calculates and returns the SHA-256 digest of the input, encoded in base64, unless the options
object specifies a different output encoding.
Syntax
Example
Parameters
input
string
The string to hash.
options
object
Optional options object to specify the output encoding. If specified, the object should contain the key outputEncoding
with value as one of base64
or hex
.
toBase64
Encodes a string as base64.
Syntax
Example
Parameters
input
string
String to encode.
JSON
Returns an object that provides JSON functions.
The parse()
function parses a JSON string to construct the value or object described by the string. If the value cannot be parsed (malformed JSON), the function will return undefined
. If the input value is not a string, the input will be coerced to a string.
The stringify()
function converts the input into a JSON string. If the value cannot be parsed (ex. the object has a cycle), the method will return undefined
.
Syntax
Example
Math
An object providing Math
functions.
Syntax
Parameters
Math function parameters are converted to numbers.
sendHttpGet
Makes an HTTP GET request to the specified URL, and invokes a callback with the response once the request completes or times out.
Syntax
Example
Parameters
url
string
The request URL.
callback
function
An optional callback to invoke upon request completion, error, or timeout.
It is invoked with the response status code, the response headers, and the response body (or undefined if there was no response body).
If the request failed (e.g. invalid URL, no route to host, SSL negotiation failure, etc.), the callback will be invoked with a response status code of zero, no headers, and an undefined body.
If the 'timeout'
option was set and the request timed out, the callback will be invoked with a response status code of -1, no headers, and an undefined body.
options
object
Optional request options. The supported options are headers, timeout. Advanced options can be added in extraOptions
headers: Additional request headers represented as an object.
timeout: The timeout, in milliseconds, before the request is aborted.
extraOptions: Advanced options (ex: {strictSSL:true})
sendHttpRequest
Makes an HTTP request to the specified URL, and invokes a callback with the response once the request completes or times out.
Syntax
Example
Parameters
url
string
The request URL.
callback
function
An optional callback to invoke upon request completion, error, or timeout. It is invoked with the response status code, the response headers, and the response body (or undefined if there was no response body). If the request failed (e.g. invalid URL, no route to host, SSL negotiation failure, etc.), the callback will be invoked with a response status code of zero, no headers, and an undefined body. If the 'timeout' option was set and the request timed out, the callback will be invoked with a response status code of -1, no headers, and an undefined body.
options
object
Optional request options. The supported options are: headers, method, and timeout. Unknown option keys are ignored. Advanced options can be added in extraOptions.
body
string
Optional request body.
Options
headers: Additional request headers.
method: The request method, defaults to 'GET'.
timeout: The timeout, in milliseconds, before the request is aborted.
extraOptions: Advanced options (ex: {strictSSL:true})
md5Sync
Calculates and returns the md5
digest of the input.
Syntax
Example
For more advanced users, we propose to create custom destinations using server-side javascript (aka Node.js), but with an easy and simplified subset of Node.js : the Javascript Sandbox.
Sandboxed JavaScript is a simplified Javascript that allows you to execute arbitrary JavaScript logic from your custom destination securely and easily (no need to learn Node.js or to understand the async/await syntax for example. If you know the basics of Javascript ES5, it is enough)
This simplified Javascript is based on helpers, set of methods that allow you to easily and quickly process and send your data.
The technology for destination's template javascript sandbox in the platform is, to a large extent, compatible with Google Tag manager templates. In most cases, templates written for GTM run in Commanders'act with no (or few) changes
You can also import templates created on GTM inside your catalog in a few clics with a 100% no-code experience.
You can choose to create an Event destination (to forward events like purchase, page view...) or Audience destination (send users who entered or were removed from a specific segment).
For Event destination, all standard and custom events can be used as input.
For Audience destination, only 2 system events are managed:
user_enters_segment
user_leaves_segment
These 2 events are automatically trigger by the system when a user enter or leave a segment. Format of audience events:
The Template Editor enables you to create, preview, and test custom templates. It has four primary areas for input to help you define your destination template:
Informations: Define basic information of the template, such as the logo, category, name.
Fields: This is a visual drag&drop editor to add input fields to your destination template.
Code: Enter sandboxed JavaScript to define how your destination will map/transform/send the data.
Publish: View/change on wich catalogs (workspaces) your destination is visible.
A URI that has been encoded by or by other means.
A URI component that has been encoded by or by other means.