Where SSJS Runs
CloudPages, Email, Automation Studio, JSON Code Resources — the full list of SSJS execution contexts and their differences.
SSJS executes in several different contexts within Salesforce Marketing Cloud, each with different capabilities and constraints.
CloudPages (Landing Pages)
CloudPages is the most flexible SSJS environment. A landing page is a publicly accessible URL hosted by SFMC.
Capabilities:
- Full request/response access (
Platform.Request.*,Platform.Response.*) - Read query strings, POST bodies, cookies, headers
- Set response headers, cookies, redirect
- Make external HTTP calls
- Full Data Extension CRUD
Limitations:
- Requests time out (no documented limit, but ~30s is a practical ceiling for external calls)
Platform.Load("core", "1.1.5");
// String() converts the CLR value so === against a literal works
var method = String(Platform.Request.Method); // "GET" or "POST"
Write("<p>Request method: " + method + "</p>");
Show test script
<script runat="server">
/*
* Chapter: CloudPages
* Proves:
* 1. On this CloudPage GET, Request.Method is GET.
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function typeOfThunk(fn) {
try { return "" + fn(); } catch (ex) { return "THREW:" + ("" + ex.message); }
}
assert("Method GET", "" + Platform.Request.Method, "GET");
</script>
JSON Code Resources
A special CloudPages type that sets Content-Type: application/json. Perfect for building simple API endpoints:
Platform.Load("core", "1.1.5");
var result = { status: "ok", timestamp: Platform.Function.Now() };
Write(Platform.Function.Stringify(result));
You cannot write HTML and JSON in the same resource — the first Write() determines the content type behavior. Set the header explicitly at the top.
Show test script
<script runat="server">
/*
* Chapter: JSON Code Resources
* Proves:
* 1. ContentType assignment works (opaque read is CLR).
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function typeOfThunk(fn) {
try { return "" + fn(); } catch (ex) { return "THREW:" + ("" + ex.message); }
}
Platform.Response.ContentType = "application/json";
assert("ContentType read typeof clr", typeof Platform.Response.ContentType, "clr");
</script>
Email (Precompile)
SSJS in emails runs during precompile — when SFMC personalizes the email for each subscriber before sending. This is the most constrained environment.
Limitations:
- No request/response access (
Platform.Request.*returns empty values) - No
Platform.Response.* - Significant performance penalty compared to AMPscript — prefer AMPscript for data lookups
- Short execution window — keep logic minimal
WSProxyworks but is slower per-send than AMPscript equivalents
Valid use cases in email:
- Complex conditional logic that AMPscript can’t express cleanly
- JSON manipulation
- Custom function definitions for reuse
<script runat="server">
// String() first — a Lookup result throws on a truthiness test when the field is empty
var firstName = String(Platform.Function.Lookup("Subscribers", "FirstName", "SubscriberKey", _subscriberKey));
var displayName = (firstName === "" || firstName === "null") ? "Subscriber" : firstName;
Variable.SetValue("@displayName", displayName);
</script>
%%=v(@displayName)=%%
Show test script
<script runat="server">
/*
* Chapter: Email
* Proves:
* 1. NON-ASSERTABLE on CloudPage: email precompile context.
* Recorded as CloudPage-only probe.
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function typeOfThunk(fn) {
try { return "" + fn(); } catch (ex) { return "THREW:" + ("" + ex.message); }
}
assert("cloudpage-context-only", "documented", "documented");
</script>
Automation Studio (Script Activities)
Script Activities let you run SSJS as a step in an Automation. This is how SSJS is used for scheduled batch processing.
Capabilities:
- Full SOAP API access via WSProxy
- Data Extension operations
- No request/response (not a web context)
- Hard 30-minute timeout per execution
Practical patterns:
- Batch-process rows in chunks to stay under the timeout
- Log progress to a Data Extension
- Use
Platform.Function.Now()and date math to track elapsed time
Platform.Load("core", "1.1.5");
var startTime = new Date();
var maxMinutes = 25; // Leave 5-minute buffer
var proxy = new Script.Util.WSProxy();
var results = proxy.retrieve("DataExtension", ["CustomerKey", "Name"]);
var processed = 0;
for (var i = 0; i < results.Results.length; i++) {
// Check elapsed time
var elapsed = (new Date() - startTime) / 60000;
if (elapsed > maxMinutes) { break; }
// Process each item...
processed++;
}
Write("Processed: " + processed + " items");
Show test script
<script runat="server">
/*
* Chapter: Automation Studio
* Proves:
* 1. NON-ASSERTABLE on CloudPage: automation context.
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function typeOfThunk(fn) {
try { return "" + fn(); } catch (ex) { return "THREW:" + ("" + ex.message); }
}
assert("cloudpage-context-only", "documented", "documented");
</script>
Triggered Send (Email)
Similar to email precompile. SSJS runs when a triggered send fires for a subscriber.
Note: Platform.Request.* is not available in triggered send context.
Show test script
<script runat="server">
/*
* Chapter: Triggered Send
* Proves:
* 1. NON-ASSERTABLE on CloudPage.
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function typeOfThunk(fn) {
try { return "" + fn(); } catch (ex) { return "THREW:" + ("" + ex.message); }
}
assert("cloudpage-context-only", "documented", "documented");
</script>
MobileConnect (SMS)
SSJS can run in MobileConnect context for SMS personalization, with significant limitations. Most data operations work, but HTTP and some response functions do not.
Show test script
<script runat="server">
/*
* Chapter: MobileConnect
* Proves:
* 1. NON-ASSERTABLE on CloudPage.
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function typeOfThunk(fn) {
try { return "" + fn(); } catch (ex) { return "THREW:" + ("" + ex.message); }
}
assert("cloudpage-context-only", "documented", "documented");
</script>
Summary Table
| Context | Request/Response | HTTP Calls | Platform.Load | WSProxy | Rows.Retrieve |
|---|---|---|---|---|---|
| CloudPage | ✅ Full | ✅ | ✅ | ✅ | ✅ |
| JSON Code Resource | ✅ | ✅ | ✅ | ✅ | ✅ |
| Email (precompile) | ❌ | ✅ | ✅ | ✅ (slow) | ✅ |
| Automation Studio | ❌ | ✅ | ✅ | ✅ | ✅ |
| Triggered Send | ❌ | ✅ | ✅ | ✅ | ✅ |
| MobileConnect | Partial | ❌ | ✅ | ✅ | ✅ |
→ Next: Embedding SSJS
Show test script
<script runat="server">
/*
* Chapter: Summary Table
* Proves:
* 1. Platform.Request available here (CloudPage row of the table).
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function typeOfThunk(fn) {
try { return "" + fn(); } catch (ex) { return "THREW:" + ("" + ex.message); }
}
assert("Request typeof", typeof Platform.Request, "clr");
</script>