Skip navigation
All Places > Marketo Whisperer: Implementation Tips > Author: John M
1 2 3 Previous Next

Marketo Whisperer: Implementation Tips

31 Posts authored by: John M Employee

I've talked before about using Postman to make REST API calls, and it's perfectly fine for one off calls for testing.. but what about those times when you need a full on programming language to upsert leads or custom objects, or perform some other function using the REST API? Well, you can write your own libraries to make it easier, or you can leverage the Marketo Rest Python library created by Jep Castelein


This article will serve as a step by step guide for getting up and running and making basic hello world calls using Python.



We'll be using the following, all of which are free.

Python (Download the latest version here)

pip for Python - A great installer program we'll use to install the library

Marketo-Python-REST library

PyCharm - A great Free IDE (the Community Edition is free)


Step 1 - Python 3.x.x

In MacOS , you'll notice that python 2.7 comes pre installed, but its perfectly acceptable to run more than one version of Python. Download the Python DMG file and install it. Make sure it installed by opening up a terminal and typing python3. Simple!


Step 2 - PIP

You can follow the directions here, downloading from , then running the following command, making sure you run it against Python 3.51 as follows


Seriously. It's that easy.


Step 3 - The Marketo Rest Python Library

Again, very simple. At the command line, ensure you have pip installed by typing

pip -V

It should indicate that you're installed on version 3.x.x (depending on your version)
Note that you might have installed it as pip3, so check that.


Next, type the following (adding sudo on the mac)

pip install marketorestpython


It should look rather like this:

Screen Shot 2016-03-30 at 5.05.31 PM.png


Step 4 - PyCharm

You guessed it. Download the dmg file for mac, and install it.

Create a project called "Marketo Python" and get creative.. maybe you want to set up folders for your different tasks. For this one, I created a hello world folder



Create a new file, and enter the following substituting your own Marketo instance credentials


from marketorestpython.client import MarketoClient

munchkin_id = "your value"
client_id = "your value"
client_secret = "your value"
mc = MarketoClient(munchkin_id, client_id, client_secret)

lead = mc.execute(method='get_lead_by_id', id= 1001)



The library is quite well documented here.. so get creative! Let us know in the comments how you're using it!



If you get an error like "HTTP Get Exception! Retrying....." and / or "SSLV3_ALERT_HANDSHAKE_FAILURE" in Mac OS Sierra, you likely need Install requests with extra security packages using: pip install requests[security]. It's further discussed in this requests issue on github.

Previously I talked about creating nested SPF entries, but as was pointed out to me by our excellent deliverability team and Kiersti Esparza specifically.. there is another way to handle this, and there are a few things we commonly see as misconfigurations and causes of breakage with SPF, and I'll talk about them here! If you have a large set of IPs and or domains and want to include them ALL in SPF, it can get out of hand quite quickly.


Character String Length

SPF records have a limit of 255 characters in a single string. Any more than that and the record will come back as invalid. We have some workarounds, however...


Approach 1 - Multiple Strings

To have more than 255 characters in an SPD record, the record can be broken into multiple strings. The strings are then concatenated together, without spaces, as shown.


IN TXT "v=spf1 .... first" " second string..."

MUST be treated as equivalent to

IN TXT "v=spf1 .... first second string..."



text = "v=spf1 ip4: ip4: ip4: ip4: ip4: ip4:  ip4: ip4: ~all"

(could be)

text = "v=spf1 ip4:" " ip4: ip4: ip4:" " ip4: ip4:" " ip4: ip4: ~all"


Approach 2 - Some more detail on the previous blog - Nested or Cascaded entries

This example if for, and you can see that is the top level SPF entry.

In this case, the SPF record includes a number of other, different SPF records.  (


All entries in the “included” entries are now considered to be part of the record.


A great tool to see all nested records in an SPF record is the DMARCIAN SPF Surveyor.


Screen Shot 2016-03-24 at 11.05.19 AM.png

Screen Shot 2016-03-24 at 11.05.31 AM.pngCaveat: This approach has limits There is a limit of 10 additional “include:” records in an SPF record. The "include", "a", "mx", "ptr", and "exists" mechanisms as well as the "redirect" modifier count against this limit of 10, but the "all", "ip4", and "ip6" mechanisms do not count against this limit.


Also remember, when you “include:” a record in your SPF record, then your record now includes all mechanisms in the “include:” record.  So if your SPF record has 1 “include:”, but the SPF record you are including has 10 already, then your record will now have 11 and will break!


Null Records in the SPF Record

A record that is NULL or does not exist will break an SPF record.  This means be extra careful about typos in your record.  If you “include:” a domain that doesn’t exist, this will break your record.


Repetitive Records in the SPF Record

In order to prevent against unnecessary processing that can cause mail systems to slow down repeated mechanisms aren’t allowed.  There is a MAX of 2 repeated look ups in an SPF record.  More than that and the record will break.  This prevents SPF records from being used in Denial of Service style attacks.


If we have learned anything at Marketo over the years it is that DNS for email is hard!  We have experts on our team who can help unravel the most complicated SPF records.  Raise your hand and let us know if you need help.

John M

Creating Nested SPF Entries

Posted by John M Employee Mar 15, 2016

If you're setting up Marketo you're no doubt familiar with how to set up SPF and DKIM to ensure higher deliverability rates, but did you know that there is a limit of 255 characters in an DNS entry, and you'd have to span DNS entries to have an SPF entry longer than 255?


so, if you have a TON of domains you want to include in your SPF.. how do you do that? Excellent Question. In short you're able to nest them within the top level domain. I've enclosed an example below, blurring the domains and IP's to protect the innocent.


In order to see if SPF is set up, head over to and type in the domain. For example, type in "" and you'll see that Marketo allows MArketo to send emails on behalf of Marketo. Not surpriusing, Marketo has always been a great customer of Marketo. Again, I'm blurring everything not related to the discussion at hand.




So, here's how it looks when you NEST entries.



the top level SPF entry.


In this case, the include is in spf-c, so if we run the MXTools query on (name redacted!) youll see this



Meaning that all the sub entries will be added to the list of SPF entries.

That's a mouthful isnt it? In the spirit of "a picture is worth a thousand words", I've recorded a video walking you through how to do this in Boomi. Its tricky only in that you have to tweak the XML that Boomi finds in the Marketo WSDL.


You can see the video here! Using Boomi: Uploading Opportunities and Opportunity Person Role


Screen Shot 2016-03-10 at 1.25.28 PM.png

Fig 1 - the completed Opportunity and Opportunity Person Role Process


What I really wanted to share here is a bit more about the XML format you're creating in the video. The following are the XML's being created by Boomi with the recommended configuration.


<ns1:Opportunity xmlns:ns1="">








      <Name>Opportunity from Boomi</Name>





Fig 2 - Opportunity Upsert XML


<ns1:OpportunityPersonRole xmlns:ns1="">



      <Role>Marketing Manager</Role>



















Fig 3 - Opportunity Person Role XML


Screen Shot 2016-03-10 at 1.38.02 PM.png

Fig 4 - The XML Setup as seen in SOAPUI

So, you can see where the structure of the XML comes from. Cool right?

Quite a few people have asked recently what a good use case is for using RTP's User Context API, Document here on the developer site.


At a high level, what the User Context API allows us to do is store bits of information about a (typically anonymous) user within RTP, and then leverage those bits of information for segmentation. Obviously RTP's set of data about an anonymous user is rich, but there could be custom items we might not return. Here are some examples:


  1. RTP doesn't return longitude and latitude, but other 3rd party products might. If that's important in the context of a campiagn, you could choose to store those in two "custom" variables
  2. RTP doesnt know if an anonymous visitor is a customer... but other 3rd party products might. In that case, you could use that 3rd parts's API to get that information, store it in a custom variable.. then segment on it.


When you're building your segment, here's how you use all this information


Step 1: Look under API for User Context API

Unknown.pngStep 2: Drag over User Context API



Step 3: Choose the custom variable you're storing your data in


Step 4: Choose the value in the fiedl you want to segment on!




You can then create a campaign based on this segment and serve up the right content to the right people! The User Context API is not on by default.. so talk to your support rep to get that enabled.


Its important to note that the custom fields in RTP are actually named "Custom 1" - "Custom 5". Whatever data you get from your other source is just placed in a variable with that name, then used.

I freely admit this is an esoteric topic, but trust me when I tell you when you need to use it, it's best not to mess it up. The use case is as follows.. suppose you have customers that might exist in some home grown external system with a unique PID (Person ID) that is not the marketo ID, and your business depends on that being unique. In addition, imagine some people in your database may not have emails (I know, I know, but this happens). Now imagine that you can have duplicate emails in Marketo.. but youll never have a duplicate PID.


An example would be when a caretake signs up for an account for someone else (Im leaving that intentionally vague).


In such a case you need to upsert data into Marketo, but you may or may not have email.. and you definitely dont have a Marketo ID. If you're using REST, its not a problem as you can specify a non email dedupe field.. but if you're using SOAP.. its not that simple. In that case you might consider using the "Foreign System ID".


Wait.. the Foreign System what?


It's true, this exists, and its documented, if rarely used, and its important you use it correctly. In the above use case you'd use the following two versions of an input XML to upsert a lead into Marketo.


In my humble opinion, Case 1 is more insteresting... because you're passing in the MarketoID and UPDATING the Foreign System Person ID.


Case 1: NO Email

<soapenv:Envelope xmlns:soapenv="" xmlns:mkt="">




























Case 2: With Email

<soapenv:Envelope xmlns:soapenv="" xmlns:mkt="">































The key it turns out is the ForeignSystemType. In order to properly upsert the lead, you NEED to tell marketo what the ForeignSystemPersonID is.. as well as the ForeignSystemType!

In Marketo Opportunities are linked to Leads via the Opportunity Person Role typically. You can peruse the Opportunity REST API here and see what's possible. Often times though, customers express that for their business case, Opportunities should be linked to Accounts (which I'll use interchangeably with "companies" from the Marketo perspective) instead, which poses a problem.


To address this, we have a hidden feature that can be turned on which enables a new filter called "has Opportunity Account" which enables you to pull back a list of leads that have an opportunity with and also have a given companyID. Note, however that this is ONLY available in Marketo instances that are not natively integrated with Salesforce or Microsoft Dynamics CRM


Cool! How Does it Work?

Im glad you asked. The basic data model is illustrated below.

Screen Shot 2015-12-03 at 9.17.54 AM.png

Fig 1 - Opportunities associated with Companies


So to get this to work there are a few things you need to know, do, and keep in mind.


  • There is currently no concept of a many to one relationship for companies to leads in Marketo
  • You must populate the list of Companies using the Company REST API.
    • This API is only available when you are NOT natively synched to Dynamics or Salesforce.
    • This API allows you to create a one to many relationship between Company and Lead, similar to the model in Dynamics and Salesforce.
    • The "externalCompanyID" you establish will serve as the link to the Opportunity and the Lead
  • You have a filter, but NOT a trigger, meaning you can create a smart list, but not trigger a campaign.


Once the Companies are set up properly set up with Leads, you can begin adding opportunities for those Leads using Create/Update/Upsert Opportunities being sure to add the "externalCompanyID".


That's it! youll then be able to use the "has Opportunity Account" filter to build a smart list!

Now lets move on to completing out many to many example. The example, as you may remember, is to model student enrollment in courses. Some terms I'll be using..


The "bridge" object Is the object that contains the data resolving the objects, the enrollment in this case. It tells us which lead is enrolled in which course, allowing many enrollments by many leases into many courses

The "edge" object is our standalone object. In this case, the course.


The example below may help. Here, the Opportunity Person Role is the "bridge" object and the Opportunity is the "edge".

Screen Shot 2015-11-02 at 10.50.06 AM.png

So lets continue by creating our enrollment object in marketo


Step 1: Create the Object



Step 2: Create Link Field #1 (to the Course Object)



Step 3: Link Field #2 (to the Lead Object)



Step 4: Create a Dedupe Field (EnrollmentID in this case)

Screen Shot 2016-01-14 at 11.22.13 AM.png

I really recommend thinking through what you want your objects dedupe fields to be. What makes the bridge object unique? In the case of the edge object its often just something like a course ID.. but for enrollment it might be EnrollmentID AND CourseID... or simply a GUID. Remember once you publish you cant change dedupe and link fields.. so think through it carefully!


Step 5: Publish The Object


This is how it looks...



That's all great.. but how do you use it? Great question. Under your triggers and filters you'll see the following

  • Added to Course (Trigger)
  • Was added to Course (Filter)
  • Has Course (Filter)
  • Was Not Added to Course (Filter)


The cool magical thing here is that when you select the filter... you can also see the bridge object! You can get a list of leads who have a Course with a certain instructor and also are enrolled in a program of study, for example.


Screen Shot 2015-11-02 at 11.37.03 AM.png

In case you missed it, there was a recent change to custom object in Marketo.. they're now available to the end user in the UI! Here's a list of my blogs on that topic.



Well good news! We're finally getting Stand Alone custom objects, but its not EXACTLY what you might be thinking.. YET. Standalone custom objects currently exist to enable many to many custom objects in Marketo, which people have been asking about for a very long time. An example of the many to many relationship that you already know about is the Opportunity to Lead relationship, which is assisted by the Opportunity Person Role... but I'm getting ahead of myself.


In order to create a standalone custom object, the process is very much like creating a normal custom object. You just leave out the link field. The one I'll create here is a "Course" object, (Physics, Math, English, History, etc.)


Step 1: Create the Object

Screen Shot 2015-11-02 at 10.40.23 AM.png

Step 2: Add the Attributes

Screen Shot 2015-11-02 at 10.41.34 AM.png

Step 3: Publish

Screen Shot 2015-11-02 at 10.41.46 AM.png


Step 4: Wow!

Screen Shot 2015-11-02 at 10.41.58 AM.png


Look, Ma, no link field! You've created a fully standalone object in Marketo. We refer to this as an "Edge" Object. In part 6 of the Custom Object Blog Series, you'll learn why.


What are you using Custom Object for? Are you having success? Please tell us in the comments.

John M

Leveraging RTP for EU e-Privacy

Posted by John M Employee Dec 17, 2015

In a previous blog post (Handling Cookies and Privacy in the EU )  I talked through a method for conditionally loading Munchkin based on location. The solution depended on a 3rd party to provide the location based lookup data. In the meantime, I've revised the solution to leverage our very own RTP product, because one of the things that RTP does very well is determine the location of an anonymous lead without storing any personally identifiable information (PII)


Screen Shot 2015-12-17 at 2.54.47 PM.png

The first step is to define a segment which will trigger on any visitor from the EU, the EU countries being Austria, Belgium, Bulgaria, Croatia, Republic ofCyprus, Czech Republic, Denmark, Estonia, Finland, France, Germany, Greece, Hungary, Ireland, Italy, Latvia, Lithuania, Luxembourg, Malta, Netherlands, Poland, Portugal, Romania, Slovakia,Slovenia, Spain, Sweden and the UK. (whew)

Screen Shot 2015-12-17 at 4.02.16 PM.png

So, once we have that, we have a segment to match, and we can leverage the RTP Javascript API. Now, assuming you have RTP installed peroperly on your site, you can trigger a callback function with a single line of code


rtp('get', 'visitor', examineVisitor);


In the examineVisitor function you can do things like

1. Parse out the response and see if the user matches your segment (in my case, #3861, which I get by hovering over the name in RTP)

2. If the user if from the EU, check for the existence of your Marketo Preference cookie

3. If there is NO User Preference cookie...

     a. If the user is NOT in the EU, create it and set the User Preference cookie to "true", meaning trackable

     b. If the user is in the EU, trigger your behavior to get the visitor's tracking consent (or at least inform them), then set the cookie accordingly

4. If there is a User Preference cookie (or you just set it)...

     a. Act accordingly, either loading Munchkin.init() or not.. and if not, you likely want to expunge the cookie as well!


Easy, right?

Many thanks to Jep Castelein who pulled much of this information together and tested it.


The best practice within Marketo is to work toward having no duplicate leads , but there are times this happens, especially since Marketo treats SalesForce and Microsoft Dynamics as the source of truth. Duplicates in those systems will result in duplicates in Marketo, and to be clear, a duplicate in Marketo is defined as a lead with the same email address.


I'll use the following as an example


Marketo IDFirst NameEmail


When considering the implications and the behavior of the system with regard to duplicates there are few key areas ..


Batch Campaigns

A batch campaign for which both leads above qualify will only go out to one lead. In this case, it will go out to the one with the LOWER Marketo ID, that is, the one that was created first in Marketo. When the email is sent and clicked on, the activities will be attributed to that lead as well.. and if the link in question leads to a page with munchkin code on it, any activity will also be attributed to this lead.


Trigger Campaigns

These are generally not a problem because they are a "Batch of 1" although they do not de-duplicate in the same way batch campaigns do.


Form Fills

If a lead that exists in Marketo more than once fills out a form, if a cookie exists on the machine they're using, the form filled will be attributed to whatever lead is associated with the cookie.. if NOT, it will be attributed to the lead that was updated most recently in marketo, and of course then the lead would be cookied.


Web tracking

The cookie ID stored within a browser can be linked to only one lead, but of course every browser can have its own cookie, and those can point to different duplicates. This happens when

  • A lead clicks a link in an email
  • A lead submits a form


List Uploads

Uploads will update the most recently updated duplicate


Lead Scoring

This is a big one. Lead scoring is triggered off of things like form fills, web visits, etc, so it follows the rules above. Obviously your risk here is that you can have a split lead score, with different actions attributed to different leads, leading to artificially low lead scores. Its not a huge problem though since much of the lead activity ends up being associated with the most recently updated lead.


Interesting Moments, Activity Types

Activities can end up also spread over multiple duplicates, as with lead scoring.



Another effect of the activity being spread out so you may see lower click and open rates than you might expect. As with the above, its most likely that it's the most recently updated duplicate that is being reported on


So... if your business case requires you to maintain duplicates, just keep this behavior in mind

Screen Shot 2015-08-24 at 11.15.34 AM.png


There is some confusion over what happens when leads are merged manually in CRM, SFDC, or Marketo. This guide provides some explanation and clarification on that topic... and some useful pointers to documentation in the product.


To summarize...

  • If two duplicate Leads or Contacts are synched to SFDC, if you Merge them in SalesForce, they are merged in Marketo
  • If two duplicate Leads or Contacts are synched to CRM, if you Merge them in Dynamics, they are merged in Marketo
  • if two duplicate Leads or Contacts are synched to Salesforce.. and you merge them in Marketo.. they are merged in Salesforce
  • if two duplicate Leads or Contacts are synched to Microsoft Dynamics, the leads cannot be merged in Marketo. They would have to be merged in Dynamics.



Merging a Lead in Salesforce

Merging a Lead in Marketo

     SFDC Effect:



John M

Timezones and the SOAP API

Posted by John M Employee Nov 9, 2015


We often get questions on DateTime fields in the SOAP api, and how Marketo handles them (yes, this applies only to SOAP).


So, rule #1. Always use W3c formatted dates. What's that, you ask? I'm glad you asked.. here are the details on Date and Time Formats

     Timezone (U.S. Pacific): 2015-11-09T16:19:52-07:00

     No Timezone: 2015-11-09T16:19:52


So the issue here is how DateTimes are handled when the timezone is not specified.

  • For a custom object the timezone is assumed to be the same as the instance into which the request is sent. That's configurable in the admin section.
  • For a lead, the time is assumed to be US Central Time (GMT-0600)


To avoid this, simply specify the DateTime.

There's some confusion out there on one of the coolest new APIs that Marketo has recently released, the asset API. The asset API enables integration with external content repositories and really raises the bar on the API access to Marketo. It allows you to create, update and delete emails and email templates, approve and unapprove emails, create and update folders and tokens on folders, and even allows you to create, edit and delete at the program level.


Wait.. program level? What?


It's true. If you look at the Get Folder By ID endpoint you lss see that it expects an ID and a Type... and the type is Folder or Program... what that means is that where you see "folder", you can also think "program"


Screen Shot 2015-10-13 at 4.11.02 PM.png


So here's the issue. The ID that the API is looking for isnt the "program ID" as you might expect, it's the folder ID of the program, which can be slightly confusing. To get this value use the "Get Folder By Name" endpoint, passing in the program Name, and of course the type of "Program". That will get you the ID you need.


Note, this is true for Folders as well as programs!