Journey Builder Custom Activities for Salesforce Marketing Cloud enable you to extend the platform capabilities by creating highly configurable interfaces which call externally-hosted endpoints when a Contact arrives at a custom activity in a published Journey.
There are several dependencies required by custom activities, which include Postmonger — a lightweight messaging Javascript utility for cross-domain messaging that is used to send data and event related information between Journey Builder and a custom activity interface, when a user configures a custom activity.
Use Cases
The available Postmonger methods and events are provided on developer.salesforce.com, however a common use case for custom activities is to retrieve Data Extension fields from the Journey Entry Source. For example, you might want to include a dropdown menu in your custom activity interface so a user can select a specific entry source field, then when the Journey is published, the field value for the Contact is included in the payload to the externally hosted ‘execute’ endpoint. Or, perhaps you want to retrieve the entire schema of the entry source, then include these field values (i.e. Journey Data) when the execute endpoint is called.
Custom Activities include the ability to define field values from the Data Source through support of Data Binding in the Event Context, which comprise of mustache formatted strings in the activity’s config.json file (a definition file that is loaded when the custom activity interface is opened). However, it’s generally not practical to define Entry Source fields in the config.json file, as these values will change between Journeys. Specifically, the format requires the assigned entry event key (a UUID value) along with the field name in the following format:
{{Event.entry-event-key.field-name}}
As a solution for these use cases, there are two undocumented Postmonger calls which enable the entry source schema to be retrieved, which can then be used by the custom activity interface, and/or programatically added as inArguments
to to include defined key/value pairs when the execute endpoint is called.
Retrieving the Entry Source Schema
The connection.trigger
Postmonger method can be used to retrieve the Entry Source schema as follows:
connection.trigger('requestSchema');
This returns the entire Data Extension schema of the Journey Entry Source, for example:
[ { "key":"Event.APIEvent-1a11c19c-7952-488a-99d7-069fa2bc543c.Id", "type":"Text", "length":18, "default":null, "isNullable":null, "isPrimaryKey":null }, { "key":"Event.APIEvent-1a11c19c-7952-488a-99d7-069fa2bc543c.FirstName", "type":"Text", "length":40, "default":null, "isNullable":null, "isPrimaryKey":null }, { "key":"Event.APIEvent-1a11c19c-7952-488a-99d7-069fa2bc543c.LastName", "type":"Text", "length":80, "default":null, "isNullable":null, "isPrimaryKey":null } ]
In turn, the schema can then be evaluated by listening for the requestedSchema
event using the connection.on
method:
connection.on('requestedSchema', function (data) { /* do something */ });
Entry Source fields for Execute Call
The following example demonstrates how Postmonger can be used to retrieve the Entry Source schema and push the fields as inArguments
, so the field values (i.e. Journey Data) are included in the payload sent to the execute endpoint when a Contact arrives at the custom activity in a published journey:
var connection = new Postmonger.Session(); var payload = {}; $(window).ready(onRender); connection.on('initActivity', initialize); connection.on('clickedNext', save); function onRender() { connection.trigger('ready'); } function initialize(data) { if (data) { payload = data; } connection.trigger('requestSchema'); connection.on('requestedSchema', function (data) { // add entry source attributes as inArgs const schema = data['schema']; for (var i = 0, l = schema.length; i < l; i++) { var inArg = {}; let attr = schema[i].key; let keyIndex = attr.lastIndexOf('.') + 1; inArg[attr.substring(keyIndex)] = '{{' + attr + '}}'; payload['arguments'].execute.inArguments.push(inArg); } }); let argArr = payload['arguments'].execute.inArguments; } function save() { /* the following code is optional, but provides an example of how to append additional key/value pair(s) as inArguments, for example, a form field value from the custom activity html var fieldVal = document.getElementById('your-field-id').value; var keyObj = { InsertKeyName: fieldVal }; payload['arguments'].execute.inArguments.push(keyObj); */ payload.metaData.isConfigured = true; connection.trigger('updateActivity', payload); }
The for
loop in this code programatically builds an array of entry source data as key/value pairs in the required data binding syntax, for example:
[ { "Id":"{{Event.APIEvent-1a11c19c-7952-488a-99d7-069fa2bc543c.Id}}" }, { "FirstName":"{{Event.APIEvent-1a11c19c-7952-488a-99d7-069fa2bc543c.FirstName}}" }, { "LastName":"{{Event.APIEvent-1a11c19c-7952-488a-99d7-069fa2bc543c.LastName}}" } ]
The connection.trigger
method (on the last line) updates the custom activity with these key/value pairs so they can be used as inArguments
for the execute endpoint (as an alternative to hardcoding the key/value pairs in config.json).
Including Entry Source fields in a form field
The following example indicates how to retrieve the entry source schema, then display field values in the custom activity interface:
var connection = new Postmonger.Session(); var payload = {}; $(window).ready(onRender); connection.on('initActivity', initialize); connection.on('clickedNext', onClickedNext); function onRender() { connection.trigger('ready'); $('#select1').change(function() { var name = $('#select1').find('option:selected').html(); console.log('PNR Field selected : ', name); }); } function initialize(data) { $('#step1').show(); if (data) { payload = data; } connection.trigger('requestSchema'); connection.on('requestedSchema', function(data) { const schema = data['schema']; for (var i = 0, l = schema.length; i < l; i++) { let attr = schema[i].key; // populate select dropdown let option = $('<option></option>') .attr('id', schema[i].key) .text(schema[i].name); $('#idField').append(option); } }); } function onClickedNext() { var idField = $('#idField').find('option:selected').html(); payload['arguments'].execute.inArguments.push({ idField: idField }) payload['metaData'].isConfigured = true; connection.trigger('updateActivity', payload); }
The for
loop creates option
tags which are appended to an empty select
tag in the html file. The following code can then be included in the index.html file (which is used to render the custom activity interface).
<select class="slds-select" id="idField"></select>
When the user has finished configuring the activity (by clicking the Next button). the connection.trigger
method (on the last line) updates the custom activity with the selected field as an inArgument
(using idField
as the key), so the corresponding field value will be sent to the execute endpoint when a Contact reaches the activity in a published journey.
Summary
Journey Builder Custom Activities extend the customer journey management and integration capabilities of the platform. The additional ability to retrieve Journey Entry Source fields and display them in a custom activity or include field values in a payload to an execute endpoint is an invaluable feature, as it unlocks many data integration use cases.
Want to do more with Journey Builder and learn how to improve the integration capabilities of your own Marketing Cloud platform? Get in touch! We’d love to discuss how you can customize your Salesforce Marketing Cloud to deliver the best possible experience for your clients and maximize the ROI for your organization.