Objects & JSON
Object literals, property access, iteration, JSON serialization and parsing in SSJS.
Object Literals
var person = {
firstName: "Jane",
lastName: "Smith",
email: "jane@example.com",
active: true,
score: 95.5
};
Show test script
<script runat="server">
/*
* Chapter: Object Literals
* Proves:
* 1. create/access.
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
var threw = false, msg = "";
try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
var person = { city: "Berlin" }; assert("city", person.city, "Berlin");
</script>
Property Access
// Dot notation (preferred when key is a valid identifier)
var first = person.firstName;
person.city = "New York";
// Bracket notation (required for dynamic keys or reserved words)
var field = "email";
var value = person[field];
person["last-login"] = "2026-01-01";
// Checking for property existence
if (person.hasOwnProperty("city")) {
Write(person.city);
}
if ("email" in person) {
// in checks prototype chain too — use hasOwnProperty for own properties
}
Show test script
<script runat="server">
/*
* Chapter: Property Access
* Proves:
* 1. dot vs bracket.
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
var threw = false, msg = "";
try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
var o = { "full-name": "Ada" }; assert("bracket", o["full-name"], "Ada"); o.age = 1; assert("dot set", o.age, 1);
</script>
Nested Objects
var user = {
profile: {
name: "Jane Smith",
address: {
city: "Chicago",
state: "IL"
}
},
settings: {
theme: "dark",
notifications: true
}
};
// Safe deep access (no optional chaining ?. in SSJS)
var city = user.profile && user.profile.address && user.profile.address.city;
city = city || "Unknown";
Show test script
<script runat="server">
/*
* Chapter: Nested Objects
* Proves:
* 1. deep path.
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
var threw = false, msg = "";
try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
var parsed = { subscriber: { key: "abc" } }; assert("nested", parsed.subscriber.key, "abc");
</script>
Object Iteration
var config = { host: "api.example.com", port: 443, secure: true };
// Always use hasOwnProperty in for...in
for (var key in config) {
if (config.hasOwnProperty(key)) {
Write(key + ": " + config[key] + "<br>");
}
}
Show test script
<script runat="server">
/*
* Chapter: Object Iteration
* Proves:
* 1. for-in + hasOwnProperty.
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
var threw = false, msg = "";
try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
var config = { a: 1, b: 2 }, n = 0;
for (var k in config) { if (config.hasOwnProperty(k)) n++; }
assert("own keys", n, 2);
</script>
Object as a Lookup Map
Use objects as simple hash maps for fast key lookup:
var statusLabels = {
"A": "Active",
"I": "Inactive",
"P": "Pending",
"U": "Unsubscribed"
};
var code = "A";
var label = statusLabels[code] || "Unknown";
Write(label); // "Active"
Show test script
<script runat="server">
/*
* Chapter: Lookup Map
* Proves:
* 1. map label.
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
var threw = false, msg = "";
try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
var labels = { active: "Active", inactive: "Inactive" };
assert("label", labels["active"], "Active");
</script>
Arrays of Objects
Common pattern for working with DE row results:
var rows = Platform.Function.LookupRows("MyDE", "Status", "active");
// rows is an array of row objects
for (var i = 0, len = rows.length; i < len; i++) {
var row = rows[i];
Write(row["Email"] + " - " + row["Name"] + "<br>");
}
// Build a summary array
var emails = [];
for (var i = 0, len = rows.length; i < len; i++) {
emails[emails.length] = rows[i]["Email"];
}
Write("Emails: " + emails.join(", "));
Show test script
<script runat="server">
/*
* Chapter: Arrays of Objects
* Proves:
* 1. collect emails.
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
var threw = false, msg = "";
try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
var rows = [{ Email: "a@x.com" }, { Email: "b@x.com" }], emails = [];
for (var i = 0; i < rows.length; i++) emails.push(rows[i]["Email"]);
assert("join", emails.join(", "), "a@x.com, b@x.com");
</script>
JSON — Serialization and Parsing
SSJS does not have JSON.stringify or JSON.parse. Use the SFMC equivalents:
Stringify (Object → JSON String)
var data = {
subscriberKey: "abc123",
email: "jane@example.com",
score: 95
};
var jsonString = Platform.Function.Stringify(data);
Write(jsonString);
// {"subscriberKey":"abc123","email":"jane@example.com","score":95}
Stringify is a global SSJS function — not JSON.stringify.
ParseJSON (JSON String → Object)
var jsonString = '{"name":"Jane","score":95}';
var obj = Platform.Function.ParseJSON(jsonString + "");
Write(obj.name); // Jane
The + "" coercion is a useful habit, but not for the reason often stated: ParseJSON returns null for null/undefined input rather than erroring (runtime-verified). It throws when handed a non-string object or array, and the coercion turns such a value into a string so the call stays valid. Always test the result for null.
Full Round-Trip Example
<script runat="server">
Platform.Load("core", "1.1.5");
// Build an object
var payload = {
action: "update",
subscriber: {
key: Platform.Request.GetQueryStringParameter("sk"),
status: "active"
}
};
// Serialize to JSON string
var jsonStr = Platform.Function.Stringify(payload);
// Store in DE
Platform.Function.InsertData("AuditLog", "Payload", jsonStr, "Timestamp", Platform.Function.Now());
// Later: retrieve and parse
var storedJson = Platform.Function.Lookup("AuditLog", "Payload", "ID", "1");
var parsed = Platform.Function.ParseJSON(storedJson + "");
Write(parsed.subscriber.key);
</script>
Working with HTTP API Responses
var req = new Script.Util.HttpRequest("https://api.example.com/data");
req.method = "GET";
req.setHeader("Authorization", "Bearer " + accessToken);
var resp = req.send();
// resp.content is a CLR (.NET) object — must use String() to convert
var body = String(resp.content);
// Now parse as JSON
var data = Platform.Function.ParseJSON(body + "");
if (data && data.results) {
for (var i = 0, len = data.results.length; i < len; i++) {
Write(data.results[i].name + "<br>");
}
}
String() is used specifically to convert CLR response objects to JavaScript strings. This is different from Stringify() (which produces JSON).
Show test script
<script runat="server">
/*
* Chapter: JSON
* Proves:
* 1. Stringify/ParseJSON.
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
var threw = false, msg = "";
try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
var data = { name: "Jane" };
var jsonString = Platform.Function.Stringify(data);
var obj = Platform.Function.ParseJSON(jsonString + "");
assert("name", obj.name, "Jane");
</script>
Copying Objects
SSJS has no Object.assign or spread syntax. Copy objects manually:
// Shallow copy
function shallowCopy(obj) {
var copy = {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = obj[key];
}
}
return copy;
}
// Merge two objects (second overwrites first)
function merge(target, source) {
var result = shallowCopy(target);
for (var key in source) {
if (source.hasOwnProperty(key)) {
result[key] = source[key];
}
}
return result;
}
Show test script
<script runat="server">
/*
* Chapter: Copying Objects
* Proves:
* 1. manual shallow copy.
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
var threw = false, msg = "";
try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
var src = { a: 1, b: 2 }, dst = {};
for (var k in src) { if (src.hasOwnProperty(k)) dst[k] = src[k]; }
dst.a = 9;
assert("src unchanged", src.a, 1);
assert("dst changed", dst.a, 9);
</script>