SFMC Code Resource
Learn how to use and abuse SFMC Code Resources, the free-of-charge programmatic powerhouse.
What are the Code Resources?
Code Resources in Salesforce Marketing Cloud are a solution for hosting JavaScript, CSS, JSON, RSS, Text and XML files within your account.
They were part of the legacy Classic CloudPages. However, their features and usefulness allowed them to survive sunsetting and thrive in the Web Studio.
Why use Code Resources when we have new CloudPages in Web Studio and Code Content Blocks in Content Builder? Unique set of features makes Code Resources irreplaceable:
- Unlike Content Blocks, Code Resources have their own URL. It means that they are not just a building block but can work alone as a web asset. It also means that they can be linked and API called as any other website.
- Unlike Cloud Pages, Code Resources have no HTML structures appended automatically by Marketing Cloud. It allows you to have complete control over what is returned by the Code Resource.
- Unlike externally hosted files, you can leverage SFMC programmatic solutions - SSJS and AMPScript - to provide a backend logic to your Code Resources.
- Finally, unlike Cloud Pages, there is no cost associated with loading a Code Resource.
That combination makes Code Resources perfect for multiple use cases - from basic to complex ones. Let's see some examples.
Code Resource Use Cases
Code Resource Basics
The most obvious use case is hosting shared CSS and JavaScript, just as you would on a CMS. It works great - you can paste your stylesheet or scripts and import it the standard way to your Cloud Pages benefitting from storing all assets on the same server:
<link rel="stylesheet" type="text/css" href="https://code-resource.sfmc.com/my-css" />
<script src="https://code-resource.sfmc.com/my-js"></script>
Similarly, you can store complex data structures in JSON or XML files to leverage them later with SSJS or AMPScript/GTL. It can be a better solution for deep immutable structures than Data Extensions.
As practical as it is, this approach does not showcase the true strength of the Code Resources, so let's check something more interesting.
Code Resource Fun Things
The real power comes with using Salesforce Marketing Cloud programmatic languages - AMPScript and SSJS. Those two allow you to execute logic on the backend and impact the front-facing outcome on the Code Resource. It enables some powerful use cases.
Dynamic Code Resources
For example, you cannot host fonts in Marketing Cloud. But, you can encode them to base64 and, in that format, add them to your CSS Code Resource.
%%[ SET @SalesforceSansRegular = "AAEAAAASAQAAABAAgR0RFRgQOBQMAAN38AAAAKEdQT1N..." ]%%
@font-face {
font-family: "Salesforce Sans";
src: url(data:font/ttf;base64,%%=v(@SalesforceSansRegular)=%%) format('truetype');
font-weight: 400;
font-display: swap;
}
What if you need a different font depending on the market to cover various alphabets? Adding all of them to your CSS is not a good idea from the performance point of view. However, you can leverage the power of SFMC programmatic languages to load only the required font. How? By requesting the specific font using a query parameter:
<link rel="stylesheet" type="text/css" href="https://coderesource.sfmc.com/my-css?font=salesforce-sans" />
%%[
SET @FontSelected = RequestParameter("font")
IF @FontSelected == "salesforce-sans" THEN
SET @FontName = "Salesforce Sans"
SET @FontInBase64 = "AAEAAAASAQAAABAAgR0RFRgQOBQMAAN38AAAAKEdQT1N..."
ELSE
SET @FontName = "Different Font"
SET @FontInBase64 = "AAAEEMDJJEkdEDKEJ849DJEHD33DJslsAAAA3EKFEK03..."
ENDIF
]%%
@font-face {
font-family: "%%=v(@FontName)=%%";
src: url(data:font/ttf;base64,%%=v(@FontInBase64)=%%) format('truetype');
font-weight: 400;
font-display: swap;
}
Personalised Code Resources
Making your CSS or JS dynamic is just the beginning. Code Resources lets you leverage the Marketing Cloud Data Model. With SSJS and AMPScript, you can make Lookups and use other functions to adapt the outcome to a specific subscriber.
It is handy when you want to hide the business logic from the competition. For example, you might have a script for a web form that calculates rates based on loyalty status, purchases and LTV. You don't have to share your logic in an accessible JavaScript - you can Lookup required data for each subscriber with SSJS and calculate everything on the server side - outputting only the final multipliers to your JS Code Resource.
You can even perform API calls with SSJS or AMPScript to external systems to securely take advantage of their data. That can be especially useful when working with JSON Code Resources that can hold whole data structures used for the presentation layer on the Cloud Page.
Generated Code Resources
JSON Code Resources are where the real magic happens. They pair beautifully with SSJS and allow us to generate whole outputs from scratch with a nifty combination of SSJS object, Stringify()
function and <ctrl:var name=string />
personalisation string. Yeah, you can have no line of JSON in your JSON Code Resource and still use it to its fullest potential. Let's dive into details.
<script runat="server">
(...)
var stringifiedResult = Stringify({ 'created': createdAssets, 'deleted': deletedAssets });
</script>
<ctrl:var name=stringifiedResult />
As you can see above, there is no line of JSON, but the Code Resource will output a proper JSON. How?
Once Marketing Cloud executes SSJS and AMPScript on the backend, it removes that code from the output. However, you can push some data to the frontend with a personalisation string. If that data is an SSJS object, you can convert it to proper JSON with Stringify()
.
This trick enables many different use cases that make Code Resources shine:
- AMPScript and SSJS debugging - there are many places where you might want to use SFMC programmatic languages. Most of them either doesn't allow for easy debugging or drive SuperMessages costs. Code Resources are free and allow you to output error descriptions.
- Deploying, cleaning and retrieving scripts - in many situations doing things through SFMC User Interface is not the best option. Deploying dozens of Data Extensions on multiple business units, cleaning hundreds of archival images or pulling assets JSON for version control. We can cover all those use cases with a script that can do the work in a fraction of the time needed for a manual approach. Then, some things cannot be done through UI at all (like targeting AutoSuppression List with Query Activity). Code Resource again will allow you to write, test and run such solutions. For free.
- Creating custom mini backends - that use case deserves a separate section ;)
Code Resource Backends
Code Resources can do so much more than just serve some content. Thanks to the Salesforce Marketing Cloud programmatic languages, they can become a dedicated backend for various solutions.
The most popular use case for SFMC's Web Studio is a Cloud Page with a form (for leads, data capture, preference management or whitepaper download). As far as creating the form is a relatively simple task with the modern HTML, the complex part is capturing the submitted data and saving it into the Data Extension.
Easy Form Backend with Cloud Page
The most basic solution utilised two Cloud Pages. One contains the form, while the other contains the data capture logic and displays the thank you page. This approach is straightforward, as you can create a standard HTML form with action pointing to the second Cloud Page, and the modern web standards will do most of the work automatically. You are just left with the need to capture submitted data with SSJS Request.GetFormField()
or AMPScript RequestParameter()
and push it to a DataExtension.
This approach, while easy to implement, has many drawbacks:
- Submission redirects to another page - it takes time and creates suboptimal User Experience
- You can create only limited (frontend JS-based) validation - if you need some checks against the SFMC data, that needs to happen after submission on the second Cloud Page. And if the validation fails, the user will be redirected back to the form page (in many cases, losing the data submitted in the form).
- As each Cloud Page load costs a SuperMessage, this solution will require 2 in the best scenario - and more if there is a validation fail on the thank you page
- If you want to make your form dynamic, you need to have all required data in the front end (showing your business logic)
- You will have limited antispam capabilities (only basic honeypots and validations)
The second popular pattern is using a single Cloud Page and changing displayed content depending on the request type thanks to SSJS Request.Method()
(GET outputs form view and POST shows thank you page). Unfortunately, all drawbacks (including the cost) are the same as each Cloud Page load (whether it is the same or different) costs 1 SuperMessage.
Good Form Backend with Code Resource
Code Resources come to save the day (or at least your forms and license limits). Instead of hosting your data processing code on the second Cloud Page - put it on the JSON Code Resource and generate responses. On the form page, add AJAX calls to the Code Resource for all required interactions:
/**
* @function request
* @description AJAX handler for POST calls to Code Resource Backend
* @param {Object} payload - request payload with at least action key
*/
function request(payload) {
return new Promise(function(resolve, reject) {
const xhr = new XMLHttpRequest();
xhr.timeout = 30 * 1000;
xhr.open('POST', codeResourceBackendURL, true);
xhr.setRequestHeader('Content-type', 'application/json');
xhr.onload = () => {
if (xhr.status === 0 || (xhr.status >= 200 && xhr.status < 400)) {
resolve(JSON.parse(xhr.response))
} else {
reject(xhr.status)
}
}
xhr.onerror = () => {
if (debugging) console.log('Connection Error')
}
xhr.ontimeout = () => {
if (debugging) console.log('Request Timed Out')
};
xhr.send(JSON.stringify(payload));
})
}
/**
* @function pushData
* @description UI handler for POST calls to Code Resource Backend
* @param {Object} payload - prequest payload with at least action key
*/
async function pushData(payload) {
if (debugging) debugValue('Processing', payload);
/* Make the request with the optional spinner overlay during load time */
overlaySectionSpinner.classList.add('overlay__section-show');
let response = await request(payload);
overlaySectionSpinner.classList.remove('overlay__section-show');
if (debugging) debugValue(`${payload.action} Response`, response);
return response
}
With that code you can trigger calls in an easy and readable manner:
pushData({
action: 'createLead',
payload: formData,
sourceName: '<ctrl:var name=sourceName />'
}).then(response => {
/* Display appropriate feedback overlay based on the response */
if (response.Status === 'OK') {
overlaySectionSuccess.classList.add('overlay__section-show');
} else {
overlaySectionError.classList.add('overlay__section-show');
};
});
Finally, that data needs to be captured, processed and responded on the Code Resource:
<script runat="server">
/* Get the Form Submission Data from JSON POST */
var postedData = Platform.Request.GetPostData();
/* Parse Stringified JSON back to Object */
var parsedData = Platform.Function.ParseJSON(postedData);
if (debugging) debugValue('parsedData', parsedData);
/* Capture data from POST body */
var action = parsedData.action;
var payload = parsedData.payload;
switch (action) {
case 'validateEmail':
/* Your Validation code */
result = { Action: 'validateEmail', Status: isEmailValdiated }
break;
case 'createLead':
/* Your Lead processing code */
result = { Action: 'createLead', Status: isLeadCreated }
break;
};
stringifiedResult = Stringify(result);
</script>
<ctrl:var name=stringifiedResult />
With this approach, any interaction (like form submission) is inserted into an object along with optional metadata, pushed through AJAX asynchronously, loaded in the Code Resource and directed to the appropriate processing unit within a switch block. Once SFMC completes the processing, the response is saved into an object and outputted as a JSON. Then it comes back from Code Resource through AJAX to the frontend with the form.
Whoa, that's a lot. So why choose all of this instead of the easy solution?
Let's start with the obvious drawback: it's more complex and harder to implement.
There is, however, a prize for all that work:
- It's using asynchronous AJAX calls, so the user never leaves your form - better User Experience.
- It separates your front end and backend - you can leverage a single Code Resource for many different forms.
- It enables the full power of the backend - you can build dynamic form, full-blown validation, antispam and more, as everything can just make a hidden call in the back of your experience.
- It minimises cost - Code Resources are free, so no matter how many AJAX calls you make, there will be just 1 Supermessage cost for the initial load of the Form Cloud Page.
- Once you complete the complex implementation, it becomes portable and can be easily copy-pasted to all your forms with minimal changes.
- You can create a Code Resource on a different Business Unit than the Form Cloud Page allowing for the data being added in a different context (for example, centralised parent BU backend managing all child BU specific front ends).
And then there is more! Code Resource is available not only for Cloud Pages - you can use precisely the same approach for any form hosted on your CMS or even within internal systems. As long as your front end can make an AJAX call, you can target your Code Resource and use Marketing Cloud power. Nifty solution for providing Triggered Sends for 3rd party forms without the need to implement SFMC API on external services.
More ideas
Using Code Resource as a form backend is a practical and frequent use case, but it is not the only one. It's worth considering whenever you need a more complex interaction with the Marketing Cloud features or data model.
Custom Preference Center backend, personalisation builder for external websites, lookup tool for internal sales or support tools, trigger for communication pushes. Sure, we can build many of those approaches with the official API. Still, leveraging Code Resources might allow you to create a wrapper that will wrangle the data before outputting it to an external system.
Code Resource Security
With great power comes great responsibility. Security should be a top priority whenever dealing with Code Resources, as after publishing, they are available for everyone with the link. There are a few ways to protect your data:
Security through obscurity
The most obvious form of security is the obscurity of the solution. While standard static Code Resources are fully transparent, any programmatic part written in SSJS/AMPScript won't be accessible from outside the Marketing Cloud.
And you can leverage that fact to your advantage by using SSJS Request.Method()
to control output depending on the request type. For example, if you are creating a web form backend, you will only need to output something for POST calls, so you can catch GET method calls and output an empty page.
Another layer you can apply is looking for specific elements within the payload. In the examples above, I used the action
key in the frontend payload and built a switch
block around it on the Code Resource. Thanks to it, you not only need to know the correct action
value, but even then, you will only see its specific response.
This level of protection might be acceptable for low-risk solutions (for example, dynamic CSS/JS or publicly available data structured for processing), but you should consider additional security for anything more critical.
Allowlisting
Another option available in the security arsenal are three types of allowlists:
- Referer Allowlist allows you to limit which pages can interact with the Code Resource by using either SSJS
Platform.Request.ReferrerURL
or AMPScriptHTTPRequestHeader('Referer')
to check the URL. - IP Allowlist enables simillar feature, but checks IP address instead of URL with the help of SSJS
Platform.Request.ClientIP()
or AMPScriptHTTPRequestHeader('X-Forwarded-For')
. - Cookie Allowlist let's you validate cookies created on previous step with SSJS
Platform.Request.GetCookieValue('CookieName')
.
DE Lookup
If the request comes from Marketing Cloud controlled resource (Cloud Page, Email, another Code Resource), you can also leverage Data Extension for even more strict security. Insert some data into the Data Extension in the first step of the process and validate it with Lookup against the payload content within the Code Resource.
SSO
Finally, if the Code Resource is part of your internal solution created only for Marketing Cloud users, you may leverage full-blown SSO to make it as secure as the whole platform. Read more on that approach in the Cloud Page Apps article.
Examples
With the flexibility of Code Resources, the sky is the limit for compelling use cases. Here, I want to share a few of my favourite ones to show you what can be done with this fantastic tool:
- Protect your Cloud Page Forms from spambots with Google reCaptcha v2 and v3 by Ivan Razine.
- Run SSJS within a Journey Activity by Sascha Huwald.
- Create a custom Chrome search engine that can find and directly open SFMC Data Extensions right from your URL bar by Michał Rzepka.
- Create Data Extension Search Engine in your Slack by Cam Robert.
- Build Cloud Page Apps to make your and your team lives easier.
Know other inspiring Code Resource use cases? Let me know!
Learn more
Looking for more? Check out follow up materials for added context and deeper dive:
- Webinar recording on Architecting Web Solutions in SFMC.
- Webinar recording on Cloud Page Apps.