Skip to main content

Writing a script

Custom transformation scripts may be defined in Javascript and provided to Snowbridge.

The scripting interfaceโ€‹

The script must define a main function with a single argument. Snowbridge will pass the engineProtocol data structure as the argument:

type engineProtocol struct {
FilterOut bool
PartitionKey string
Data interface{}
HTTPHeaders map[string]string
}

This structure is represented as an object in the script engine, and serves as both the input and output of the script.

Scripts must define a main function with a single input argument (JSDoc for type information is optional):

/**
* @typedef {object} EngineProtocol
* @property {boolean} FilterOut
* @property {string} PartitionKey
* @property {(string | Object.<string, ?>)} Data
* @property {Object.<string, string>} HTTPHeaders
*/

/**
* @param {EngineProtocol} input
* @return {Partial<EngineProtocol>}
*/
function main(input) {
return input
}

Accessing dataโ€‹

Scripts can access the message Data at input.Data, and can return modified data by returning it in the Data field of the output. Likewise for the partition key to be used for the destination - input.PartitionKey and the PartitionKey field of the output.

By default, the input's Data field will be a string in enriched TSV format. This can be changed with the SpEnrichedToJson transform, or the Javascript transformation itself has a snowplow_mode option, which transforms the data to an object first.

The output of the script must be an object which maps to engineProtocol.

snowplow_modeโ€‹

snowplow_mode uses the Go Analytics SDK to parse the TSV fields into an object suitable for working with in Go. The result of the ParsedEvent.ToMap() method is the input to your transform function.

The keys of the resulting map are defined by the Analytics SDK. Values are primitives (string, number, boolean) or, for timestamps (e.g. derived_tstamp, collector_tstamp), time.Time objects.

tip

To work with native Javascript Date objects for timestamps, construct one via new Date(ts.UnixMilli()) where ts is a time.Time instance.

When returned as part of Data, time.Time instances will serialize in JSON as RFC3339 strings.

Structured data (Self Describing Event payloads and Entities) will have keys with a prefix of unstruct_event_ or contexts_, the vendor name converted to snake case, the event/entity name in snake case, and the schema model version. For example:

Schema URITypeKey
iglu:com.snowplowanalytics.snowplow/web_page/jsonschema/1-0-0Entitycontexts_com_snowplowanalytics_snowplow_web_page_1
iglu:org.w3/PerformanceNavigationTiming/jsonschema/1-0-0Entitycontexts_org_w3_performance_navigation_timing_1
iglu:com.urbanairship.connect/OPEN/jsonschema/1-0-0Eventunstruct_event_com_urbanairship_connect_open_1

Timestamps in structured data values will always have their primitive representation (string/number) and not be time.Time instances.

Transforming Dataโ€‹

For all the below examples, the input is a string representation of the below JSON object. For Snowplow data, using snowplow_mode will produce a JSON object input - see the snowplow example.

{
"name": "Bruce",
"id": "b47m4n",
"batmobileCount": 1
}

To modify the message data, return an object which conforms to EngineProtocol, with the Data field set to the modified data. The Data field may be returned as either a string, or an object.

assets/docs/configuration/transformations/custom-scripts/create-a-script-modify-example.js
loading...

Filteringโ€‹

If the FilterOut field of the output is returned as true, the message will be acknowledged immediately and won't be sent to the target. This will be the behavior regardless of what is returned to the other fields in the protocol.

assets/docs/configuration/transformations/custom-scripts/create-a-script-filter-example.js
loading...

Setting the Partition Keyโ€‹

To set the Partition Key in the message, you can simply set the input's PartitionKey field, and return it:

assets/docs/configuration/transformations/custom-scripts/create-a-script-setpk-example.js
loading...

Or, if modifying the data as well, return the modified data and PartitionKey field:

assets/docs/configuration/transformations/custom-scripts/create-a-script-setpk-modify-example.js
loading...

Setting an HTTP headerโ€‹

For the http target only, you can specify a set of HTTP headers, which will be appended to the configured headers for the http target. Do so by providing an object in the HTTPHeaders field:

assets/docs/configuration/transformations/custom-scripts/create-a-script-header-example.js
loading...

The headers will only be included if the target has the dynamic_headers = true setting configured.

Configurationโ€‹

Once your script is ready, you can configure it in the app by following the Javascript configuration page.

You can also find some complete example use cases in the examples section.