Generating Munchkin Associator Tokens in SFDC/Apex or FlowBoost/JS

💡
Unfortunately, Marketo no longer supports the Munchkin associateLead function so this post is obsolete as of 2021-ish. Kept around for posterity.

The code in this post is used in the follow-up Tracking clicks from non-Marketo email sends, so read that one next!

The Munchkin API function associateLead is magical and underused. It's key to synchronizing certain 3rd-party data with your Marketo database, and bizarrely enough was the first Marketo feature I ever used (well before understanding anything about campaigns and flows!).

I have a post set to publish re: tracking engagement with non-Marketo emails, and since that post concentrates on the browser side (how to use specialized tokens in link URLs to associate leads, even when emails are sent via other ESPs) I decided to dedicate a post to how you generate those tokens.

The info below is a must-read preface to the main post, but it'll also be useful on its own to some readers.

What's an “Associator Token”?

First, I'll tell you what it's not: it's not the Munchkin cookie, it's not the mkt_tok value that's appended to tracked URLs, and it's not a REST API access_token.

It's related to other browser-side tech (it's kind of a semi-substitute for the mkt_tok) but its role is totally distinct.

We'll dive deep in the main post, but for now let's say the Associator Token (AT) allows you to associate a web session with a known lead in a secure, scalable, cross-platform fashion — there's no other technology that merits all those positive adjectives!

(By the way, “Associator Token” is my term. It's so low-key, it doesn't even have a name in the docs, just a position: “the third parameter.”)

The “secure” part is possible because you generate ATs on a server (or, I suppose, desktop) that has access to your Munchkin secret key. This key is never exposed to end users. As a result, no random member of the public can generate anyone else's AT, even if they know the other person's email address is in your Marketo database.

But while the algorithm to create ATs is incredibly simple (provided you know the secret key) Marketo doesn't generate them for you. So you need to run code somewhere to create an up-to-date token for a each lead.

Emails sent straight from Marketo need the token to be in a lead field. So you can either use CRM code/formulas and sync the field over, or keep the field Marketo-only and call a webhook.

For emails sent via other ESPs or partners, you can export tokens from Marketo if they're already in there (recommended) or do it fully offline with an Excel or Sheets macro (I don't have examples of such macros right now, but they are certainly feasible).

In SFDC/Apex

A couple of years ago, before I became addicted to webhooks, I wrote an Apex class to compute the Munchkin associator (syncing that field over to Marketo).

Feel free to hit the problem from this side if you're more comfortable, but there's no reason for the field to be in SFDC at all unless you're exporting lists from SFDC.

public class MunchkinAssociator {

  // transients won't appear in JSON.serialize
  transient private String secretKey='990672999390035D551177556622445C88DD9AB0C63G'; 
  private String email;
  private String hash;

  // create (binary) hash of secretKey+email, store hex version of hash
  public MunchkinAssociator ( String email ) {
    this.email = email;
    Blob preHash = Blob.valueOf( this.secretKey + this.email );

    this.hash = EncodingUtil.convertToHex( 
      Crypto.generateDigest( 'SHA1', preHash ) 
    );
  }

  // intermediate conversion to JSON, in its own method to ease testing
  public String toJSON() {
     return JSON.serialize(this);
  }

  // final string output is Base64'd JSON
  public override String toString() {
    return EncodingUtil.base64Encode( Blob.valueOf( this.toJSON() ) );
  }

 }

 // email will actually be pulled off the Contact in the trigger
 String currentEmail = 'sandy@teknkl.com'; 
 MunchkinAssociator munch = new MunchkinAssociator( currentEmail );

 // ... then set the Contact's MunchkinAssociator__c = munch, etc...

In FlowBoost

If you use FlowBoost, the FBMunchkin helper has a built-in method to generate associator tokens:

FBMunchkin.getAssociator( email, secretKey )

Called like this, of course:

ss

With email@example.com, that's running:

FBMunchkin.getAssociator( 
  "email@example.com", 
  "990672999390035D551177556622445C88DD9AB0C63G" 
);

And the webhook response:

{
  "response": { 
    "tokenOnly": "b6654e24595860e2c1c23a18b3c84f3e5cd5c745",
    "munchkinArgumentsBase64" : "WwogICJhc3NvY2lhdGVMZWFkIiwKICB7CiAgICAiRW1haWwiOiAiZW1haWxAZXhhbXBsZS5jb20iCiAgfSwKICAiYjY2NTRlMjQ1OTU4NjBlMmMxYzIzYTE4YjNjODRmM2U1Y2Q1Yzc0NSIKXQ==",
    "munchkinArgumentsDebug" :
      [ 
        "associateLead", 
        "email@example.com",  
        "b6654e24595860e2c1c23a18b3c84f3e5cd5c745" 
      ]
  }
}

What's the extra stuff in the FlowBoost response?

When building FBMunchkin, I kept in mind how Associator Tokens would actually be used, that is, appended to email links, like:

<a href="http://example.com/landingpage.html?email={{Lead.Email Address}&munchassoc={{Lead.MunchkinAssociator}}">Click here!</a>

As such, it would be cool if you could just attach one token to the link, and have it be lightly encoded so it looks random like the mkt_tok or other tracking info (it's anything but random, but the vast majority of people would have no idea). This way you don't have to expose the email address unencoded in the link, which IMO looks a little sloppy.

So while response.tokenOnly gives you just the token (which you can do whatever you want with), response.munchkinArgumentsBase64 is everything you need wrapped for tracking, wrapped up in one field, so you can do this in your emails:

<a href="http://example.com/landingpage.html#at:{{Lead.munchkinArgumentsBase64}}">Click here!</a>

And the recipient sees this in their browser's location bar:

ss

We'll make magic with this token in the next post.