Skip to main content

SFMC Tips and Tricks Challenge

Rafal Wolsztyniak


Sharing the wisdom

Michał Rzepka started something amazing with his #SFMCTipsAndTricksChallenge on LinkedIn in which the members of the SFMC community were asked to share 3 tips about the system. Lots of people responded already sharing great tips for beginner and advanced developers alike.

So, it's my turn to share:

  • How I'm a big fan of the console.table() function in client-side JavaScript for debugging
  • What the dreaded Error 500 message on a page without SSJS or Ampscript teaches us about proper testing and the CloudPagesURL() function
  • How data binding can be used to create a basic logging mechanism writing personalized values with the Update Contact Block in Journey Builder

console.table() is great for debugging

While developing my Ampscript Wordle clone I had to tackle multiple problems concerning the changing game state. Seeing what information came in from the forms and how they were finally processed was crucial in the debugging process.

Normally I would just output such values on the page, but the results are messy: even if you make everything monospace, you would still have to take care of the alignment of every debugged variable to have a readable output.

While building an HTML table with Ampscript for this purpose, I realized I could simply pass all values to debug as a single JSON object and have client-side JavaScript take care of build the table using the console.table() function.

Example output

It really be like that sometimes


Empty values like '' will not be displayed by this function, but you can click the ▶ Object button right below the table to see all valuas listed.

All you need to do is build a JavaScript object with Ampscript (or with SSJS for which this would be natural):

How to get it done

set @debug = Concat('{',
'"@now": "', @now, '",',
'"@number": ', @number, ',',
'"@empty": "', @empty, '",',
'"@alphabet": "', @alphabet, '",',
'"@evaluation": "', @evaluation, '",',

and output this to the page:


Sometimes Ampscript is really email-specific

Sometimes we can ignore the little things like the official documentation mentioning that some functions were designed with the email context in mind, because they have proven to work in our tests. Sometimes it will work like

If there's a chance that you will send an SMS with a link to a CloudPage before the first email is sent to this customer, don't use the CloudPagesURL() function - if the contact you are sending to does not exist in the All Subscribers list, opening the link can make the Error 500 page appear (even if there's no Ampscript or SSJS code that could cause this error).

In such cases build the personalized URL with the Concat function to build the final URL with encrypted parameters containing user data.


There's also a different lesson to be learned here:

When testing new scenarios, use new contacts that closely resemble the state in which the recipients would be in that moment:

  • They might not be in All Subscribers? Make sure your contacts are not in that list
  • They might not be in the synchronized data extension yet? Don't rely on it at the time of sending

Creating a journey log with the The Update Contact activity

Let's assume you want to introduce some basic logging in your journeys and would want to write who entered a particular path. There's no communication on that path and you don't want to rely on code running while the message is prepared (some people may be opted-out after all), so you turn your gaze to the Update Contact activity and start wondering how to use it for this case.

The way the Update Contact activity in Journey Builder presents itself is pretty humble - it seems like it can't assign any dynamic values and can only write hard-coded values to the DE you select. Why would anyone want to write only the same values for everyone is beyond me. Nevertheless it's possible to make this activity write personalized values from both the Contact and Journey, but it's tricky.

To make this happen we need to utilize what is decribed as data binding which will allow you go grab data from:

  • the journey entry data (but be aware this data does not change as is frozen in time and reperesents the state in which the data was when the customer entered the journey)
  • real-time user data from attribute groups from the contact model in Contact Builder

Contact Data

To grab the contact data you need to follow this pattern: {{Contact.Attribute."ATTRIBUTE SET NAME"."ATTRIBUTE FIELD"}} )

For example if you want to get the Subscriber / Contact Key, you would need to use: {{Contact.Attribute."Contact"."Contact Key"}}, but only in this instance you could simply use {{Contact.Key}}

Consider this custom attribute group:

Custom attribute group

You can get the ImportantData attribute by typing out: {{Contact.Attribute."LevelOne"."ImportantData"}}.

The CriticalStuff field can be accessed with {{Contact.Attribute."LevelTwo"."CriticalStuff"}}.

That's cool and all, but how to easily get values like this and avoid typing (which is error prone)? What should you start the string with when you want to get values from the Journey Data?

The easy way of grabbing the data

Just follow those steps:

  • Get a text editor open - we'll be copying and pasting those data binding strings
  • Create a Task or any other SF object block in your journey and start configuring it
  • Choose Create New in the Select Action step
  • Choose any field from the list that corresponds to the data type you want to grab
    • Subject is my favorite for text values
  • Select if you want to use Contact or Journey Data and select the value you want to insert with your Update Contact activity
  • The data binding string you want will appear on the left side of the screen below the name of your Sales and Service Cloud Field of choice
  • Copy the string and paste

Custom attribute group

  • Copy the string into your text editor, close the Task activity and past it in your Update Contact activity

Custom attribute group


If we were to choose our LevelTwo data extension as a Data Extension entry source we could get the CriticalStuff field value in two ways:

  • Contact Data: {{Contact.Attribute."LevelTwo"."CriticalStuff"}}
  • Journey Data: {{Event."DEAudience-a33c4f76-f98c-1210-8205-df62800d6778"."CriticalStuff"}}

Data binding can be used to grab context values referring to the journey as well, here are some other examples from the documentation:

  • Default email address or mobile number grabbed by the journey settings:
    • {{InteractionDefaults.Email}}
    • {{InteractionDefaults.MobileNumber}}
  • Journey version number: {{Context.VersionNumber}}

Hope this will be useful to somebody :)