Your marketing team churning out content? Uploading this content to the Marketo Design Studio and setting up content performance tracking programs taking up a lot of your time? Take a look at how you can automate this process using the Marketo, Dropbox, Rebrandly, and Airtable APIs in Zapier.
Content Operations Introduction
As part of the marketing operations role, it is necessary to take content from the product marketing team and upload it to the Marketo Design Studio so that the content can be accessed when shared via blogs and social media posts. Since the Marketo content link is long and LinkedIn posts share the entire URL, ReBrandly can be used to get a custom branded and shortened link, which is more aesthetically pleasing e.g.
- Original Link: https://go.telnyx.com/rs/telnyx/images/Content_eBook_YourGuidetoChoosingtheRightVoiceAPI.pdf
- Rebrandly Branded Shortened Link: https://tlyx.co/eb-voiceapi
Additionally, Airtable can be used to store and categorize all the content links from your Marketo Design Studio for easy location by either the sales or marketing team. Last but not least, a Marketo program should be set up to track visits to the blog post containing the piece of content and email the content link when the download form is filled out.
Of course the process of
- Downloading the content (pdf, png, etc) from Dropbox
- Uploading the content to the Marketo Design Studio
- Getting a shortened version of the content link using ReBrandly
- Uploading the Rebrandly link to Airtable
- Creating the Marketo program to track content performance and to send content to customers
can be done manually, but if you have multiple pieces of content to upload on a weekly basis then it is worth streamlining the handoff from the content marketing team and then automating the 5 tasks above using the Dropbox, Marketo, ReBrandly, and Airtable APIs from within Zapier.
The Github repo containing all the code used within the Zapier actions described below can be found here.
N.B. If it is your first time using the Marketo REST API or you need a quick refresher then check out the Marketo API Quick-Start Guide to see how to make your first Marketo REST API requests in Postman before transitioning to making requests in code or in the Zapier automation tool.
Take a look at the video below to get a walk-through of how each step within Zapier is set up and get a look inside the Marketo content performance tracking program.
Marketo Design Studio Upload Walkthrough Video
Marketo Design Studio Upload Request Google Form
The first step in the process is to obtain the Content Type, Content Name, ReBrandly Slash Tag, Dropbox Asset Path, and hosting page URL from the content marketing team using a Google form.
Content Name
The file will be named as Asset_ContentType_ContentName in the Marketo Design Studio by the Python code in Zapier so when filling out the form the Content Type
should not be included in the Content Name
or else it will appear twice in the Marketo file name.
For example the “Apple” case study Content Name
should just be “Apple” so that the name in the Marketo Design Studio will then be Asset_CaseStudy_Apple
Only use spaces as separators i.e. no underscores, colons etc should be used to separate words, and avoid long names since this name will be used in the Marketo file name e.g. “Your Guide to Better Leveraging Conversational AI” should be shortened to just “Conversational AI” so that the filename will be Asset_eBook_ConversationalAI.
Rebrandly Slash Tag
This is the part of the Rebrandly url that appears after the custom domain i.e. for an ebook the slash tag could be “eb-market2020” and the full Rebrandly link would be https://yourcompany.co/eb-market2020
As a suggestion, the slashtag can follow the following formats for each piece of content where name is an abbreviated version of the content’s title (so that the ReBrandly URL stays short and looks nice) without any separators between words and in lower case e.g. the abbreviated names for “Modernize Your Call Tracking Application For Today’s Marketing” and “The Better Twilio Alternative” can simply be “calltracking” and “twilioalt”.
- Case Study: cs-name
- eBooks: eb-name
- Fact Sheets: fs-name
- Infographics: in-name
- Whitepaper: wp-name
- Guide: gd:name
Dropbox Path for Content
The path should look similar to the example below and can be obtained by right-clicking on the desired asset from a list view and selecting “Copy Link Address” (see demo video). Note that when copied there may also be querystring parameters appended after the asset path such as in the example below, these can be left alone or removed if desired.
https://www.dropbox.com/preview/Telnyx/Departments/BizOps/Growth/Design/Messaging/Fax/Factsheets/Factsheet_Fax/Factsheet_Fax.pdf?role=work
Blog post link
This is the link to the web page that will host the content download form and the link is provided here so that visits to this webpage can be tracked in Marketo
Dropbox > Marketo Design Studio > Rebrandly > Airtable
Once the content information is obtained from a Google form the information then gets stored in a Google sheet row, which in turn triggers the “Get Submission from Google Form” action of the “Marketo Design Studio Upload” zap in Zapier.
N.B. Although there is a Python library for the Marketo REST API, which allows you to make requests in one line of code by passing parameters to functions of the library, the Python integration in Zapier does not have this library installed. This is why in each of the Marketo actions defined below, we have to make the HTTP requests to the Marketo REST API endpoints using the Python requests library as well as specifying all the ancillary information needed to make the request i.e. headers and payload.
So be wary when building Python scripts outside of Zapier. Always check in Zapier first that the libraries you want to use are installed (I will share an ordeal I had when finding a workaround for Beautiful Soup not being installed on Zapier’s version of Python in a future post…. spoiler alert: it was not fun!).
Get Dropbox Link
The “Get Dropbox Temporary Link” action (get Python code for Zapier Step 2: Get Dropbox Temporary Link) makes a request to the get_temporary_link
endpoint passing the path to the asset in Dropbox and then parses the response to obtain the link to download the asset using the Python regular expression below.
link = re.search('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', response.text).group(0)
It is important that this asset path from Dropbox is correct or else the request to the get_temporary_link
endpoint via the Dropbox API will not work (see the “Dropbox Path for Content” section above).
Marketo Design Studio Upload Via REST API
After receiving the Marketo API access token (get Python code for Zapier Step 3: Get Marketo Access Token), the zap then proceeds to make a request to the files endpoint to upload the piece of content using the Dropbox temporary link (get Python code for “Zapier Step 4: Upload File to Marketo Design Studio”). The urlib.request.urlopen
method is used to access the Dropbox file, from which the file extension and mime type can be extracted for later use in naming and then uploading the file.
f = urllib.request.urlopen(dropbox_temporary_link)
mime_type = f.info().get_content_type()
f_ext = f.info().get_content_type().split("/")[1]
The final preparation step before uploading the content is to use the content_type
dictionary to identify the folder that the content should be uploaded to as well as to get part of the name for the file. This is done by passing the content type to the dictionary as a key and then accessing the first and second elements of the list returned to get the naming piece and the Marketo Design Studio folder ID respectively.
content_type = {"Case Study": ["CaseStudy", "169"] , "eBook":["eBook","1569"], "Fact Sheet":["FactSheet","2076"], "Infographic":["Infographic","2070"], "Guide":["Guide","2076"], "Whitepaper":["Whitepaper","2067"]}
After the upload request is made, the response is parsed to obtain the URL of the newly uploaded file in the Marketo Design Studio.
Rebrandly Aesthetic Link Shortening
The first step of the “Get Rebrandly Link” action (get Python code for Zapier Step 5: Get Rebrandly Link) is to determine the destination URL of where the Rebrandly shortened link should point. In order to track visits to PDF content, Sanford Whiteman’s redirector page is the initial destination. Then using JavaScript code embedded on this page you will get redirected to the URL of the PDF asset (http://example.com/redirected.pdf
) that is appended to the redirector landing page URL (http://pages.example.com/redirector
).
http://pages.example.com/redirector#http://example.com/redirected.pdf
Note that this redirector does not work for images (png, jpg etc) and so if the asset is an image, conditional logic ensures that the redirector URL is not prepended to the asset link.
Once the destination URL has been obtained, it is passed along with the Rebrandly domain, and slashtag in a request to the https://api.rebrandly.com/v1/links
endpoint (see Rebrandly docs here).
The returned response is then parsed to obtain the Rebrandly shortened link, which will have the following format:
https://rebrandly_domain/slash_tag
where the slash tag is the string provided by the marketing team in the Google form fill (see “Rebrandly Slash Tag” section above).
Uploading to Airtable Via REST API
Airtable has a similar layout to Google sheets, where there will be a collection of assets e.g. “Marketing Assets”, which will have a table (similar to a tab in Google sheets) for each content type e.g. “eBooks”, “Fact Sheets”, “Guides” etc. Airtable has cool API docs specific to each collection of assets you have in Airtable. Once you arrive at the API landing page, you can then select the collection of assets you want to interact with and then you will be brought to a REST API docs page tailored to that collection of assets (get the Python code for Zapier Step 6: Upload Row to Airtable).
The content_type
dictionary takes the c_type
variable as a key and returns the list of values for that key, where the first index contains the content type id and the second index contains the URL encoded name of the table in Airtable. This URL encoded name is then appended to the base Airtable URL to get the full post_url
that will be used as the post request destination:
post_url = "https://api.airtable.com/v0/apppRyxNabc5LTYeR/"+content_type[c_type][1]”
Next, the payload of the response is populated with the values for the “Content Name”, “URL”, “Content Type”, and “Last Updated” header values. The “Content Type” field is a dropdown menu and in order to select a dropdown value the id of the value needs to be known. These dropdown id values are then accessed through the first index of the list returned for a content key from the content_type
dictionary (see paragraph above).
If you are wondering where to find the ids for a dropdown list in your table, comment below and I’ll help you find them 🙂
Once the payload has been populated it is then put in JSON format using the json.dumps()
method and passed in the post request to the post_url
. The response text is then returned at the end of the script so that it can be analyzed once the script has run to make sure that the new row was added successfully.
Creating Marketo Content Program
Get Folder ID
The first step of the “Get Marketo Folder ID” action is to make a request to the folder by name endpoint to check if the folder name “YYYY Folder_Name” exists for the content type (get the Python code for Zapier Step 7: Get Marketo Folder ID).
If
the folder does not exist then the content_type
dictionary is used to find the parent folder id for the content type and a request is then made to the folders endpoint to create the “YYYY Folder_Name” folder within this parent folder. The folder id is then stored as a string in the info
variable i.e. info = "New:"+fid
.
Else
the program was found successfully and the folder id is stored as a string in the info
variable info = "Existing:"+fid
.
Get Latest Program ID
If
“Existing” exists in the folder_info
string then this means that there is at least one Marketo program in this folder from the previous time that this zap ran. Therefore, the id of the folder that needs to be searched can be parsed straight from the folder_info
variable (get the Python code for Zapier Step 8: Get Latest Marketo Program ID).
Else
“New” exists in the folder_info
string meaning that the “YYYY Folder_Name” folder was newly created in the previous step and is empty of any Marketo programs. This means that the previous year’s folder id i.e. “YYYY-1 Folder_Name”, must be obtained, by making a request to the folder byName endpoint, in order to find the most recent Marketo program for this content type.
Once the correct folder id has been obtained, it is then passed as the root to the folders endpoint to return all programs within this folder. The findall
regex function is then used to find all instances of the regular expression below from the response that is returned from the previous request.
"createdAt":"\d*-\d*-\w*:\d*:\w*\+\d*","updatedAt":"\d*-\d*-\w*:\d*:\w*\+\d*","url":"https://app-ab20.marketo.com/#PG\w+","folderId":{"id":\d*,"type":"Program"}
The list containing these instances i.e. dates
, is then sorted in reverse order so that the instances with the most recent createdAt
date will be at the top of the list. Once the correct order has been established the "folderId":{"id":(\d*),"type":"Program"}
regular expression is used with the findall
function to isolate all program ids in the same order and store them in the program_ids
list. Therefore, the program id of the most recently created program will now be the first index of the program_ids
list.
N.B. That there is a simpler way to obtain the latest program id by using the max method in Python as shown below. Each successive program in Marketo will have a program id number 1 digit higher i.e. program_id = n+1
than its predecessor program_id = n
. Therefore, the most recent program in a list will have the highest program_id number and can thus, be extracted using the max()
method.
raw=response.text
pattern = '"folderId":{"id":(\d*),"type":"Program"}'
program_ids = re.findall(pattern, raw)
latest_id= max(program_ids)
Clone Latest Program
The latest program id is then passed in a request to the program clone endpoint along with the parent folder id to create a new program for the piece of content just uploaded to the Marketo Design Studio (get the Python code for Zapier Step 9: Clone Latest Marketo Program).
Get UTM Parameters from Google Sheet
UTM parameters are appended to each link within the piece of content (if it is a PDF) so that any visits to our site from the PDF can be tracked by a smart campaign (see how page visits with UTM parameters can be tracked in the Marketo UTM Tracking & Automation post). This step searches from the bottom up of the UTM Builder Content sheet to find the latest row which will contain the querystring of UTM parameters that are appended to each link within the PDF.
Update Program Tokens
The token names to be updated are collected in a list called token_names
and a corresponding list token_values
contains all the values that the respective tokens need to be updated with (get code for Zapier Step 11: Update Marketo Program Tokens). Once all the token values have been populated within the token_values
list, a for loop is then used to iterate through each token name, passing each name and the corresponding value to a request to the program tokens endpoint, thereby updating each token with the desired value.
Get & Rename Email
The Marketo content performance tracking program contains an email that is used to send the piece of content out to someone when they fill out the form to request the content. Provided that the piece of content is not a factsheet or infographic, which are not gated and do not get emailed out, then a request is made to the emails endpoint to get the email id from within the parent content program (get the code for Zapier Step 12: Get Marketo Email ID). Then in Step 13 this email id is appended to the email endpoint url so that the name of the email can be updated for the current content program (get the code for Zapier Step 13: Rename Marketo Email).
Get & Update Smart Campaigns
The Marketo content performance tracking program contains smart campaigns that are used to track when someone views/requests a piece of content, when they open a link within a piece of content leading to our website, and to track any conversions (contact sales or sign-up) that occur after they have interacted with the content (see how to track conversions after page visits with UTM parameters in the Marketo UTM Tracking & Automation post).
A request is made to the smart campaigns endpoint passing the content program id in order to get all the smart campaign ids within this program (get the code for Zapier Step 14: Get Marketo Smart Campaign IDs). In Step 15 these ids are parsed from the response and stored in a list (get the code for Zapier Step 15: Update Marketo Smart Campaign Descriptions).
A for loop is then used to iterate through the list of smart campaign ids and make a request to the id specific smart campaign endpoint i.e. /rest/asset/v1/smartCampaign/+sc_id+.json, to update the campaign description to contain the querystring that is appended to links within the content PDF.
These two steps are not strictly essential but since a lot of these smart campaigns require this content querystring in their smart list or flow it makes it easier to populate these smart campaigns by just copying the querystring from the description.
Unlock More With The Marketo API
Now that you have seen how the Marketo API can be used to automate repetitive workflows, take a look at the posts below to get more inspiration and ideas for processes that you can automate:
- Marketo UTM Tracking & Automation: Streamline the process of creating UTM parameters and tracking these parameters in Marketo using Google Forms, Google Sheets, and the Marketo REST API.
- Marketo Dynamic Email Content via API: Learn how to create and populate emails from Google Sheet templates using the Marketo API.
- Marketo Merge Leads in Bulk using the API: Merge leads in bulk with Python code that will allow you to set custom rules for how you want to prioritize conflicting values for the same fields on different leads.
As always if you are enjoying this content and want to get an email when I launch a new post then hit that shiny, pink, subscribe button at the top of the page 🙂