Skip navigation
All Places > Champion Program > Blog > Authors Erik Heldebro

Champion Program

3 Posts authored by: Erik Heldebro Champion

This post details some of the tactics I presented at the Marketing Nation Summit this year, the slides can be found here: Cut me some Slack! Leveraging The Slack API With Marketo Webhooks And Bots

 

Slack is a powerful tool for communication and collaboration. I think it's safe to say that the most of us have at least used Slack at one workplace if not on a daily basis. With the many useful integrations built by other tools we use, we have access to all useful information in one place and it's great at replacing tedious email threads.

 

A couple years back, I discovered the Incoming Webhooks integration from my previous colleague Henri Syvänen at Avaus and it gave an amazing opportunity for sending relevant lead alerts to Slack channels where teams could monitor the most interesting touchpoints Marketo was processing.

 

Starting with a fresh Marketo instance last year, we quickly got to setting up relevant alerts for marketing & sales to keep people in the loop of what Marketo helps us with how we can track high-intent conversions in the funnel:

 

marketo-alerts-across-funnel.png

Overview of Slack alerts across lead lifecycle stages

 

Although very insightful with alerts split up in different Slack channels, it was easy to miss/forget interesting leads in MQL alerts. I was setting up a few API integrations with other tools we use and got quite interested in how Slack apps work and the possibility of creating smarter alerts that were interactive to push data back to Marketo from Slack - the way an "integration" should work.

 

How the Slack API works

I'm not going to get into the Incoming Webhooks setup too much except for the fact that Slack gives you a "hooks.slack.com..." URL to POST to using your Marketo Webhook and Slack handles the rest, basically as a static message in Marketo.

 

incoming-webhooks-post.png

Incoming Webhooks post with a whole chunk of formatting in text field and "ok" response from Slack

 

Now, using the Slack API to post a message allows you to specify which channel to post to in the payload along with the opportunity of adding interactive components like buttons, menus and (quite recently) custom actions. This is how it flow of data looks like:

 

 

slack-marketo-flow-of-data.png

Payload, Slack post and Response using API

 

 

What's interesting about this setup is that when Slack receives the data it responds with the whole message and some other parameters like the timestamp/id (ts) of the message, that can be mapped to a Marketo field in the webhook's settings. The ts value would allow Marketo to interact with the original message, for example adding a thread comment with more data:

 

 

thread-comment-slack.png

 

Creating your own Slack app

What you'll need for this setup is to create your own Slack app and the great thing is that you can keep it in your internal workspace. Once your app is created, what you'll need is to set up is a bot user + permissions to post using a Bearer token in the header of your posts.

 

I have covered a detailed guide on this part here: Configuring a Slack app for use with Marketo

 

Posting using the Slack API

With all app settings ready, the app will be able to post to Slack through its bot user. This is basically the same as a normal Slack user posting, the bot needs to be invited to the channel it posts in and the channel ID needs to be specified in the payload as attachments.

 

The two part post from above is created using two webhooks and a wait step where the ts value is used to refer to the first webhook's posted message:

 

 

two-part-webhook.png

Using Marketo for formatting data

 

For those interested, I have put together a detailed guide on structuring webhook posts: Structuring Marketo webhooks to post via Slack API

 

It's quite easy to get into a disaster use case of either having (1) too much text in alerts with default values or (2) creating 20 different webhooks. Marketo knows what data is available and can be told what to actually post before calling a webhook.

 

One method that works quite well is creating a webhook template that is tokenized and defines all relevant data on the program / campaign level:

 

 

slack-payload-template-1.png

 

This webhook defines the Slack Channel ID and the title/pretext of the message using My Tokens and uses a custom field called Slack_Contact Details for preparing data before posting to Slack by running through a whole list of Change Data Value flow steps with choices:

 

 

Slack-post-flow-steps.png

 

What this can translate to in Slack is either using one webhook for multiple types of posts or simply removing fields when they're empty:

 

comparison-two-different-posts.png

 

Interactive components and passing data back to Marketo

When first testing this, I was tempted to use one button next to MQL alerts, but it seemed a bit risky if people get tempted to press it. Instead I opted for putting in a bit more work and adding a menu with three different choices to start: Disqualifying, Adding as contact (claiming) and Creating a deal/opportunity.

 

Adding interactive components to Slack requires a URL for Slack to post to. Contrary to "hopeful beliefs", you can't really configure so much from Slack's end and it's up to you to decide what to do with the data. This underlying process of sending data back to Marketo is configured with a tool called Integromat that I personally prefer over Zapier. Both tools work great if you're not very technical and posting to your own server.

 

How this type of setup looks like:

Slack-Qualification.gif

 

 

Underlying workflow for passing data back to Marketo

 

Integromat's webhook URL is added in the Slack app's settings and once a request is made, the JSON is parsed to grab the important values:

 

  • The ts value for updating the originating message
  • The action value from the drop-down menu for sending to Marketo
  • The lead's attributes for knowing who to update
  • The ID of the Slack user who took action to know who claimed/disqualified the lead

 

api-workflow-slack-marketo.png

The integromat scenario for receiving data from Slack

 

 

Integromat authenticates through the Marketo REST API and receives an authentication token. The lead's information is retrieved from Marketo using the token and Integromat syncs the data (points above) on the lead. After this is done, the originating message is updated with three different values based on what the action was that mentioned (1) What the action was, (2) Who took an action (3) Who the lead was.

 

For a more detailed guide on this part, I wrote up a post here: Sending data back to Marketo from Slack

 

 

marketo-triggered-workflow.png

 

Once Marketo receives the data, this triggers flow steps to update the revenue cycle stage along with details on the lead owner before running more actions to sync the lead to CRM and as a final step... Comment on the original slack message's thread mentioning the user and attaching a link to CRM to the Contact or Opportunity depending on what was chosen - in best case scenarios this takes 15 seconds to run through the whole flow.

 

I hope this was insightful and helpful for anyone interested in building something similar!

 

Best,
Erik

 

One thing I have noticed when creating a more complicated nurture in Marketo, you have to be creative to make things work the way you want them to and the great part about Marketo is that you have a whole arsenal of features available.

 

This hack works with a lot of use cases, but the specific way I got to making it was when a client wanted a specific nurture for free trials for licenses from their website that would be sending on specific days of the trial.

 

variable cadence.png

 

I've seen a lot of questions about variable cadence on the community. I was overjoyed seeing Marketo's announcement of this feature (screenshot above from summit slides) on the Summit this year. There is still some time remaining until that so I figured I will share this method. This has been tested for a few months and is proven to work given the right setup.

 

I will also share some learnings from setting up this a few different ways which I would strongly not recommend .

 

Example of 30 day product trial nurture with fixed days for sendouts

 

If you're looking to nurture leads who signed up for a product trial during a fixed amount of time for the trial, you would probably want to deliver some content on specific days of the trial to try to convert/activate them on milestones. Multiple products will be tougher to nurture as managing dynamic content in one stream can become a lot of work.

 

Main asset setup

variable-cadence-example.png

 

Using similar naming conventions for different products, it allows you to globally maintain sendouts, making it easier if you want to add new streams or make changes on the days you want to cast.

 

Stream setup

engagement-stream-setup.png

 

Adding one stream per product and emails for each in the same order will allow for maintaining your casts from the same place. This is of course if you want to be sending the same amount of content and on the same frequency for your products.

 

Setting stream cadence

setting-stream-cadence.png

 

In order for the setup to work, casts should be set to recur every day at the same time, in this example 10 am. The space between the days for casts will be maintained by scheduled batch campaigns.

 

Another point to note before continuing, this can be applied on normal nurturing streams with longer spaces (let's say 2-3 weeks) where you want new leads in nurture to receive content immediately instead of waiting 2-3 weeks if they just missed the last cast. In this type of situation where you don't want to send out on numbered days, you can just choose the weekdays for when to cast, e.g. Tue, Wed, Thu with the same weekly repeating cadence.

 

Entry to nurture and Custom Object

 

Smart List

Added to Trial.png

 

In the example above, a Custom Object has been added for Trials and the trigger for entry to Stream 1 is being added to a trial for Product 1. This works great if you have an external database that confirms a new trial and is scheduled to import daily at a specific time to Marketo.

 

Flow

trial-flow.png

 

Once the lead qualifies for the flow, they will be added to the appropriate stream (in this case Product 1).

 

This is also a great time to send out a welcome to trial email directly. If you're using a Custom Object for the trial you can add information from it by using Velocity Scripting with $TriggerObject values, more on there here: http://developers.marketo.com/email-scripting/marketo-objects/

 

After that:

  1. Cadence is paused (should be sent on the third day)
  2. Wait step for 2 days
  3. Cadence is resumed to Normal to send out the first email in the stream (-Day3-)

 

Smart Campaigns for managing cadence

 

Smart List

Smart Campaign-SL.png

 

Here is an example of the first batch campaign applying for the first email sent on Day 3, looking almost identical for all days, you set up the first one and then clone and adjust from there.

 

Filters explained:

  1. Only applies to members of this engagement program
  2. Was Sent (Not delivered*) an email that contains the naming convention (-Day3-) for this email in the past 2 hours (explained next in Schedule)

 

*The positive aspect of using filters is that there is a sent choice as opposed to triggers that only have "Is Delivered", this is important because if you would use the was delivered option you risk sending your emails daily.

 

Flow

Smart-Campaign-Flow.png

 

Once a lead qualifies for the flow, their cadence will be paused for a fixed amount of time.

 

Flow steps explained:

  1. Pause the cadence for the Engagement Program (will not receive casts)
  2. Wait for a fixed amount of time - The time between Day 3 and Day 8 will be 5 days, so taking away a few hours from that will place the person on the cast of their 8th day.
  3. Once the wait is over, cadence is resumed.

 

Schedule

Smart-Campaign-Schedule.png

 

Every batch campaign for maintaining cadence will be scheduled to recur daily at the same time. In this case, every cast is scheduled for 10 am and the batch campaigns run at 11 am (after). The Smart Lists specify the email (e.g. -Day3-) delivered in the past 2 hours, so this will ensure the right batch campaign runs.

 

Repeating setup for all Smart Campaigns

 

Once the first campaign is set up you can clone it and:

  1. Adjust the name of the Day of the email (ensure to use contains)
  2. Adjust the wait time, so for Day 8 (Next cast is Day 14) it would be 5 days 12 hours to land on the next cast.

 

Changing streams after nurture is done or lead has purchased

engagement-empty-streams.png

 

When the nurture is done on the last day, leads can be added to a separate stream without cadence. The main reason for this is that with daily casts setup and no more content to send, you will get a lot of notifications in your Marketo top menu. Also it is better knowing that those inside of a stream are currently in the middle of a trial.

 

When a lead purchases a paid version of your product you can set up a trigger to pause trial nurturing, add them to the purchased stream (ensure Success Program Status is set up) and send a welcome email or whatever you choose.

 

Survey after trial

 

One great use case for globally managing your trials is sending a general survey to request information on what the lead thought about the trial. I have configured custom Marketo based surveys with a rating scale of 0 - 5 composed of Image links to the same Marketo landing page with URL parameters for tracking response on the email click and then asking a couple general questions (picklist it) regarding the product.

 

If you configure the entry campaign with a Change Data Value flowstep to update the product name, you can personalize one email with tokens.

 

Necessary Quality Management

 

To keep quality you will need the following:

  • Bounce management (Soft/Hard): If there is bad email quality, make sure to create Smart Campaigns for removing leads from the stream. You could create an empty inactive stream for Invalid Emails.
  • Communication Limits: If your communication limits are strict and leads are receiving other emails during the nurture you will need to take this into account since it could possibly change the time of delivery.
  • Make sure to test the nurture and double (or triple ) check your smart campaigns. When you're configuring a lot of smart campaigns too quick and don't let the system save before moving on, you may keep the same value twice.
  • Unsubscribed Leads: If you have a subscription center or custom unsubscribe you need to take this into account for removing the leads from nurture and most likely having an Unsubscribed Stream / Status. You can use trigger tokens for changing the data value on a custom field that writes the name of the email asset that triggered the unsubscribe to get information on where you should optimize.
  • Take into account use cases of someone doing a trial for two products and ensure you can manage moving them to the new product trial stream if they've already run through one.

 

Other use cases

 

As mentioned above, this does not need to be a fixed day nurture for a trial. You can use this method when you have a 2-3 week nurture where you want to include leads every week so they don't have to wait too long if they have missed the latest cast (they're all run at the same time). So if you were to name all your nurturing emails like NUR-01-, NUR-02-, ..., you can set a weekly cast on a weekday but set a wait step for 2-3 weeks with cadence paused, and of course Schedule set to run every time.

 

Lessons Learned

 

From previous experience I have tried a couple different methods that don't work so well and have come up with this custom solution to get a scalable workaround. Some of the things I tried which did not work so well in the past years:

 

  • Setting this up without an Engagement Program and a whole lot of Smart Campaigns: This becomes very tedious work as using Smart Campaigns will not prevent leads from receiving the same email twice. If you need to make a change in even one Smart Campaign you will need to run batches to remove those who are in wait steps from the flow and manage everyone manually, which I could say is not so much fun.
  • Setting up an Engagement program for one product and using one stream per day: This was a similar setup to the one given here, it worked for the most part but was just a pain to maintain and resulted in a lot of notifications

 

As always if you want to know more feel free to ask and I'd be happy to help. Also if anyone has anything to add here, do it!

 

For more tips and tricks, feel free to check out erikheldebro.com

Working with cross-channel marketing, where you have a lot of different entry points to your landing pages, it’s a good idea to keep track of which sources, campaigns, content variants and more are generating traffic and which are converting on your content.

 

One thing I noticed is that it can get quite messy to keep track of touch points, traffic sources and much more in a manner that doesn’t for example require exploring an activity log for an interesting lead, going through interesting moments for an individual, or sifting through the Opportunity Influence Analyzer (great report but requires manual follow-up).

 

Grabbing UTM Parameters in hidden form fields

This one is a pretty well-known tactic that allows you to autofill a chosen field with a value from any parameter in the query string of your URL, it will be key to set up for the following parts and more information can be found here: Set a Hidden Form Field Value - Marketo Docs - Product Docs

 

Preparing Marketo for tracking five different UTM Parameters

The normal uses of UTM parameters are Campaign, Content, Medium, Source and Term. More information on these and their uses can be found on Google’s URL builder: Campaign URL Builder — Google Analytics Demos & Tools

 

The first step would be to create a custom field for each of these parameters in order to allow for getting the data into Marketo when a lead converts on a form. If they came in to your website through a sponsored ad, you should know what source, medium, campaign and content drove this conversion. I would recommend using a naming convention for your custom fields so as to not get them lost/forgotten or mixed up with your fields that came out of the box, more on that here.

 

Now instead of only tracking a lead’s last touch on a UTM parameter, I would recommend creating corresponding First and Multi-touch fields to be able to track the first touch value a lead had when converting, the last one and a log of all values (this proves to be important in the next step), looking something like this:

We use the prefix AMI for Avaus Marketing Innovations, you should decide how you want to name/structure your field names.

 

Setting up forms and a smart campaign for assigning values across fields

Once these fields are in place you should make sure to set them as hidden fields in all your forms. The ones that are needed for this are the Last Touch fields, as a form conversion will always be the last touch and a smart campaign will be used for assigning values to the first and multi-touch fields.

 

Form setup

Add all the LT fields into your form as field type Hidden, configure autofill settings for each field for the corresponding UTM parameter. From my example above, the field AMI_LT_Source would be configured with the parameter utm_source, like this:

To make this process easier it would save you time and make everything more scalable to use global forms for your different form types (content, event, newsletter sign-up, contact, etc), which you can read more about here.

 

Smart Campaign setup

You will need a Smart Campaign to assign values to your First and Multi-touch fields. In order to avoid an excess of Data Value changes triggers, this can be done with 5 Smart Campaigns (one for each utm_parameter).

 

Trigger:

Data Value changes – LT field (the one used in your form) as well as a Lead is created trigger with the filter for the same field not being empty (since most times a data values changing from null to a first value does not trigger a data value change).

Flow:

 

1. If the FT field is empty, it will be populated with the LT field value, otherwise nothing will happen.

2. a) If the MT field is empty it will be populated with the System Date/time and the FT value. The system token here could get unnecessary and make the MT field quite long so it’s all up to the person making it.

2. b) If the MT field is not empty it will add the LT field first and concatenate the MT field after with a divider:

{{system.dateTime}} {{lead.AMI_LT_source}} | {{lead.AMI_MT_source}}

 

The Multi-touch field is great if you have a lot of touch points that leads run through and it can give a good overview that can be used in alerts.

 

Note: There are a few different ways of making this setup, if this does not work for you I would suggest setting up a separate smart campaign for when leads are created with a wait step and to assign values to first touch fields. Also you could optimize this by only listening for data value changes in the most common parameter/or form fills with filters and requesting other campaigns for the other fields. I will not cover this here because it requires a complex structure that is in most cases unique to your setup.

 

For more information on load balancing and slowdowns in instances, Josh Hill covered the topic in a well-written post here: Load Balancing in Marketo and Marketing Automation - Marketing Rockstar Guides

 

Auto tagging your emails with predefined UTM parameters

Now assuming you have a tagging strategy in place with naming conventions for Internal banners/CTAs on your website, Retargeting, Paid Social, Organic Social, AdWords, + more.

 

To give a holistic tracking for all your emails in Marketo (including Newsletters, Snippets, Nurturing, Events), you would want to ensure that these assets get tagged and are tracked both in Marketo on conversion but also in Google Analytics.

 

For this you would need both a set naming convention for your Marketo programs and to make some changes to your email templates.

 

Setting up local variables in your templates:

<meta class=”mktoString” id=”link-variable” mktoName=”URL” default=”#” mktoModuleScope=”true”>

<meta class=”mktoString” id=”utm-tag” mktoName=”UTM” default=”?utm_source=mkto&utm_medium=email&utm_campaign={{program.Name}}” mktoModuleScope=”true”>

 

Adding the variables to each module/link:

<a href=”${link-variable}${utm-tag}”>

 

Note: At the moment of posting, variables are not supported in text versions of emails and should be edited separately (for links) or removed (for parameters) in text versions. I have covered this in a separate post which can be found here: Email 2.0 Hack - UTM Parameters as local variables

 

This has definitely proven to be a good use-case when there are a lot of Marketers using the same instance, some work with only Newsletters, some with Content, others with Events.

 

Having the tagging in place with utm_campaign (or whichever you wish to use) with the default value {{program.Name}} gives you insights as to which programs are generating traffic to your website and is especially useful when you have goals setup in Google Analytics and even more interesting with E-commerce where you can track the exact revenue generated in your webshop from different Marketo programs.

 

Other uses for Multi-touch fields

 

Using a trigger for Program Status changed with Success = True:

You can use a LT field for populating the program name with a trigger token {{trigger.Name}}, then having a second flowstep for adding this to a MT log of program successes to see which programs a lead has converted on.

 

Creating a content download log:

Having two fields e.g. “Last Downloaded Content” and “Content Download History”, where the former is used in your program templates for downloadable content in a Change Data Value flowstep by default on conversion, “Downloaded {{my.Content Name}} on {{system.date}}”, and concatenating this value on the latter field. This creates a great log for lead alerts.

 

Hope this will help anyone who has the need to set up something similar

 

For more tips and tricks, feel free to check out more here