Automation growth hacker: How to identify anonymous Intercom leads using Marketo forms + the Tray Platform
September 5 2019
By Niels Fogt
Disclaimer: This is a get-your-hands-dirty type of blog post. It’s long and leverages somewhat technical concepts. However, you don't need to be an engineer to build out this kind of thing. You just need to be comfortable rolling up those sleeves!
Hey there Blue Whale from Bonnaroo hunters! In this very first edition of Automation Growth Hacker (a working title), I’ll show you how to use your lead capture forms to identify anonymous leads in your chat solution. For this blog, we’ll be using lead capture forms from Marketo and Intercom for chat, though you could very likely use a similar approach with forms generated by another marketing automation platform (MAP) in concert with another chat solution.
If your sales development representatives (SDRs) staff Intercom chat, you’re probably familiar with seeing new conversations from the likes of "Indigo Camera from San Jose":
This is Intercom’s way of letting you know you’re talking to an anonymous prospect.
From a customer experience standpoint, it’s great to not force an early-stage prospect to cough up their email before getting basic questions answered. However, for your sales team, it can be really frustrating to not get any credit after spending gobs of time helping someone, only to see the Purple Cows from Albuquerque vanish like Amber Gorillas in The Mist. For SDRs, whose job it is to actively warm up prospects in order to qualify them as opportunities, time is precious. The difference between hitting your goal or not often comes down to making sure you spend your time wisely.
Wouldn’t it be way cooler if you could use the form submissions you're already getting for inquiries, gated content, sign ups, or webinar registrations to help identify your anonymous chats BEFORE they ever start the chat? Like this:
Well, my friends - that's what we're here to do today! Here are the tools we’ll use:
Marketo form submissions - already live on our website
Intercom - to field inbound chats - already live on our website
Google Tag Manager - a popular website tool that lets you add tracking elements into your websites without having to modify any code
Tray Platform - a General Automation Platform (GAP) that lets you integrate tools like Marketo and Intercom and orchestrate sophisticated processes with automation like the one we’ll build today
Here’s a high-level architecture of how our solution will work:
A prospect submits a Marketo form on your website
A callback function listens for the form submission and sends the form data to a webhook-based workflow in the Tray Platform via an AJAX call. (Don’t worry! This is easy stuff that anyone can do!)
The webhook workflow receives the data and converts the anonymous person to a known lead in Intercom
For reference, a callback function is a software operation that you queue up to execute after another function runs to completion. In this case, our callback will listen for an event occuring (the prospect filling out our form).
After our callback hears the form submission, we'll use an AJAX request to send data from our form submission to a workflow which recieves that data using a webhook. (Again, this is much simpler than it sounds, and we’ll walk through every step.)
For those not familiar, let’s level-set on a few Intercom concepts/terms:
Conversation - Any new chat coming in to the Intercom "Inbox".
Visitor - An anonymous person who has yet to have a "Conversation".
Lead - A person who has started a Conversation, but is not yet a "User." Leads can be anonymous or "known." The difference is that you have the email address of "known" Leads.
User - Usually people who have a login to your application. If you’re SaaS, they’re often in trial or are already a paying customer.
To clarify, we’re also assuming you’re using Marketo forms. This is important because the "callback" function I’m using is part of Marketo’s JS forms library, MktoForms2.
If you’re not using Marketo forms, you can still do everything we’ll cover here, however, you’ll have to figure out the callback part for your solution. Additionally, while we're loading our callback using Google Tag Manager (GTM), yours might be hard coded or deployed via another tag manager, like Tealium.
Setting up the Marketo form submission callback
.whenReady(callback) fires a callback one time for each form on your page.
.onSuccess(callback) fires a callback after the user submits one of those forms.
Setting up your Tag & Trigger in GTM
Here’s a skeleton of our code with comments explaining the execution logic. Again, don’t let the code scare you off. You can just copy-paste this entire block directly into GTM.
What we’re really doing here is:
Ensuring the code only runs when the Marketo forms library is present
Prepping the callback function to run when prospects fill out a website form
Pass the data from a filled-out form to the Tray Platform workflow we’ll build next!
To load this into GTM, we need to create a new "HTML" tag and drop in the skeleton:
For testing, in order to simulate being an anonymous Visitor/Lead, use your browser’s private or incognito mode. Since it would be difficult to test using GTM’s "preview" mode, we can instead create a separate trigger. Specifically, we’ll build a trigger that looks for the following query parameter within the URL in order to fire our code: ?test=mkto2int. We’ll enter this string into our trigger configuration in GTM:
Set up your payload object
In order to update your anonymous Visitors/Leads, you'll need two sets of data:
The form contents - The values to set on the Intercom lead (including email, name, and other relevant fields)
A visitor ID - The unique ID we’ll use to pick which Visitor/Lead record to update. (I don’t recommend using the email address to do this for Intercom leads.)
We’re going to insert both into a payload data object - the actual data that we’ll transmit in this process - which we'll stringify before sending to the Tray Platform (where we’ll automatically parse the payload upon receipt):
Code sample here
Try this! To follow every step in this process, add console.log(vals) inside your .onSuccess() callback. console.log is a logging/debugging function you can use to inspect different outputs of your code. After adding it to your callback, open your browser's console and submit a test form to see what this object looks like for your forms. Don’t forget to add your testing query parameter (?test=mkto2int) or to remove the console.log() when you’re done!
Set up the AJAX call to Tray.io
The objective here is to get the payload to arrive inside our Tray Platform workflow (which we’ll build shortly) where you can use it to identify your anonymous person.
Since we’ve already packaged everything up into the "payload", we can now pass it over to the Tray Platform using an AJAX call. The inline comments below cover what we’re going to do:
You don’t have a Public Workflow URL yet - that’s next!
The X-CSRF-Token is an optional security precaution which can be any complex string of letters/numbers/characters. You can use an encryption helper to generate one in a separate workflow.
Alternately, you absolutely could send this to your own service. If you’re curious, I encourage you to learn the hard way, as I did. Within a few weeks or months, you’ll come back to using a GAP due to the giant pain in your rear! Monitoring, troubleshooting, updating functionality, and all the other crud that comes with maintaining your own scripts and services just isn’t worth it. Using a GAP gives you much better visibility and agility in doing all of this. (Take it from someone with the scars to prove it!)
Setup a Tray workflow to receive the payload
Now that you’re set up to send the payload somewhere, you’ll need an automated workflow to "receive" it.
We’ll create a new workflow with a "webhook" trigger, open the workflow settings, copy the "Workflow Public URL", and finish by enabling the workflow:
As you can see from the above animated GIF, we begin our workflow with a webhook trigger. This trigger generates a public URL we can use to connect our workflow with GTM. Copy the Workflow Public URL from the workflow settings menu and paste it over TRAY_WEBHOOK_URL in your GTM tag.
If you created an X-CSRF-Token, swap out YOUR_TOKEN in the tag as well. You can then finish this step by going back to the Tray Platform adding the same token in the "CSRF Token" field found under our webhook trigger’s "advanced settings" menu located at the very bottom right of the panel:
Your code in GTM should look something like this by this point:
Code sample here
Assuming you’ve associated your testing trigger to the tag, you can now publish your GTM changes. Let’s test out some form submissions, shall we?
Testing a form submission
With your callback published and webhook workflow enabled, go to a page on your website while using your test query parameter (for instance, https://tray.io?test=mkto2int).
Fill out a form, then check the "output" of the trigger step in the "debug" panel of your Tray Platform workflow to see what you get:
In my case, I see the payload in the output of my logs has everything I need:
Convert Visitors and Update Anonymous leads
For Visitors, this is the "user_id" attribute on the Intercom Visitor object which can be used to look them up and convert them:
But! Not every person on your site is a Visitor in Intercom’s eyes. Some are already Leads (both anonymous and known) or Users. If you attempted to look up a Visitor by "user_id" using this ID, but they were in fact a Lead/User, Intercom’s visitor API will return a "not found" (404) response, even though Intercom technically returns a visitor ID for them using the aforementioned Intercom("getVisitorId") function.
The good news is that Intercom uses that same visitor ID as the Lead’suser_id when they're converted to a lead:
With this in mind, here’s how our workflow logic will function:
Listen for the data payload from our Marketo form submission
If we don’t find a Lead - this person was a User. Since we know their email already, we take no further action.
Let’s break down how this set of operations looks in workflow form. (Don’t worry, we’re almost done!):
Because we’re using some newer Intercom Visitor APIs, we’ll be using our HTTP-based Universal Connector (UC) for the steps leveraging the visitors API. The UC, which is the globe icon on the second step in the above screenshot, can accommodate these newer visitor-related calls. (Part of the beauty of a GAP is that even without pre-built operators, you can use the UC to write HTTP-based connectors to make the connections you need.)
We’ll use the same authentication in our Universal Connector as we're using in our Intercom connectors, we just need to add some headers. After doing this once, you can duplicate the configured UC and retain that same auth setup for the other calls.
Looking up the visitor using the Universal Connector
This may look complicated, but don’t panic! It really isn’t. As we discussed, our workflow uses a webhook trigger to kick off the process when it receives the signal from GTM that someone has filled out a Marketo form. We then use our Universal Connector (UC) step to ascertain whether this person is a Visitor, as noted in the diagram above.
In the output of the UC’s "Lookup Visitor" step, there's going to be a "response object", which we can think of as the answer to the question: "Is the person who just filled out a form a Visitor in Intercom?" In that object is a "status code" attribute, the answer to that question.
We’ve built the next step in our workflow to pass that response object value to the "Visitor found?" Boolean check to ascertain whether the person is, in fact, a Visitor. We build out our Boolean step to detect a status code equal to 200. If the status code is 200, that means the person is a Visitor, which means the Boolean is considered to be "true". As a result, the process moves down the true path to the "convert to lead" step. However, if the status code didn’t equal 200, we move to the false path.
Let’s look more closely at what happens if the Visitor wasn’t found. In this branch of our workflow, we look up leads in a nearly identical process. The main difference is that we use ".../contacts" rather than ".../visitors":
We use another UC step to "Lookup lead by user_id" and a similar boolean step to check the status code in the response object. If it finds a lead, we use the "Update Lead" operation in our Intercom connector. In this case, we pass the form contents we wish to add to the lead to Intercom:
Now let’s go back a few steps and see what happens if our initial Boolean condition was "true" - that is, if we actually found a Visitor in the first step following the trigger.
Within that same Intercom step, further down the right-hand connector configuration panel, we can add a "visitor" object with the user_id as an attribute inside the "raw" body object like this:
Finally, we can update that lead using the ID we got back from the response in the conversion step:
That's pretty much it! All you need to do to finalize this workflow is test it a few times. Once you're feeling good about it all, change your GTM tag to fire on "all pages:"
This blog may have gotten a bit technical, but you should hopefully see how you can use automation to fill in the gaps between your Marketo forms, Intercom chats, and GTM website tags. By stitching together the data, you can identify otherwise anonymous users and help your SDRs know who they are talking with. These are warmed-up leads who have demonstrated clear interest in your company’s products or services, and could become valuable opportunities for your sales team.
One last addition: I recommend going back and watching the example video showing the end result at the top of this post. Notice that little pop-up on the Thank You page after the form submit? That has a link in it to book an SDR meeting mapped to the email used in the form. We call this "Insta-book," and it’s already started to bring in meetings to our eager SDR team.