String functions — Marketing Cloud SSJS reference
The string operations available in MC SSJS — native JavaScript methods (the ES5 subset SpiderMonkey 1.7 supports) plus the Platform.Function helpers for formatting and stringification. What's safe, what's missing, and what you have to polyfill.
String handling in SSJS is mostly plain JavaScript, but only the ES5-era subset that SpiderMonkey 1.7 understands. There's no String.prototype.trim reliably, no template literals, no String.prototype.padStart / padEnd, no String.prototype.includes. The + operator concatenates the way you'd expect (with implicit String() coercion, including for null and undefined), and Platform.Function.Format covers the formatting cases the language doesn't.
Official syntax
The supported native String methods (SpiderMonkey 1.7):
Platform.Load("Core", "1.1.5");
var email = " German.Medina@Example.COM ";
// Length, character access
email.length; // → 31
email.charAt(2); // → "G" (after the leading spaces)
email.charCodeAt(0); // → 32 (space character code)
// Search
email.indexOf("@"); // → 16 (or -1 if not found, NOT 0)
email.lastIndexOf("."); // → 28
// Note: no .includes() — use indexOf() > -1 instead
// Slice / substring (3 different ways with subtle differences)
email.slice(2, 16); // → "German.Medina@" (start, end-exclusive)
email.substring(2, 16); // → "German.Medina@" (same; negatives become 0)
email.substr(2, 14); // → "German.Medina@" (start, length — deprecated but supported)
// Case
email.toLowerCase(); // → " german.medina@example.com "
email.toUpperCase(); // → " GERMAN.MEDINA@EXAMPLE.COM "
// Replace
email.replace("@", "[at]"); // first occurrence only
email.replace(/\./g, "_"); // regex, /g flag for all
email.replace(/^\s+|\s+$/g, ""); // poor-man's trim
// Split, concat
"a,b,c".split(","); // → ["a", "b", "c"]
"hello".concat(" ", "world"); // → "hello world" (rarely used; prefer +)
// Pattern matching
email.match(/(\w+)@(\w+)/); // → match array with groups
email.search(/\d+/); // → -1 (no digits in this email)The Platform helpers for formatting:
// Format — printf-like with positional args ({0}, {1}, ...)
Platform.Function.Format("Hello, {0} ({1})", ["German", "AR"]);
// → "Hello, German (AR)"
// FormatNumber — locale-aware number formatting
Platform.Function.FormatNumber(1234567.89, "N2", "en-US");
// → "1,234,567.89"
Platform.Function.FormatNumber(1234567.89, "C", "es-AR");
// → "$ 1.234.567,89"
// FormatDate — locale-aware date formatting (returns string)
Platform.Function.FormatDate(Now(), "yyyy-MM-dd", "en-US");
// → "2026-05-08"
// String() and (''+x) — explicit stringification
String(42); // → "42"
String(null); // → "null"
String(undefined); // → "undefined"
('' + null); // → "null"
('' + undefined); // → "undefined"The supported set:
| Operation | What it does | Notes |
|---|---|---|
| s.length | Character count | Not byte count — Unicode-safe |
| s.charAt(n) / s.charCodeAt(n) | Character / code at index | 0-indexed |
| s.indexOf(needle) | Position of first match, or -1 | NOT 0 when not found |
| s.lastIndexOf(needle) | Position of last match, or -1 | |
| s.slice(start, end) | Substring [start, end) | Negative indices supported |
| s.substring(start, end) | Substring [start, end) | Negatives become 0 |
| s.substr(start, len) | Substring of len chars | Deprecated; works in SSJS |
| s.toLowerCase() / s.toUpperCase() | Case fold | Locale-aware in newer engines |
| s.replace(target, repl) | Replace first match (string) or all (regex /g) | |
| s.split(sep) | Array of substrings | |
| s.match(regex) / s.search(regex) | Regex match info / position | |
| s + s2 | Concatenation | NULL/undefined coerced to "null"/"undefined" |
| Platform.Function.Format(template, args) | Printf-style with {0} placeholders | Args as array |
| Platform.Function.FormatNumber(n, fmt, loc) | Locale number formatting | "N2", "C", "P", "F", etc. |
| Platform.Function.FormatDate(d, fmt, loc) | Locale date formatting | Returns string |
| String(x) / ('' + x) | Explicit stringification | |
Reference:
- Salesforce Developer — Platform Functions reference (Format / FormatNumber / FormatDate) ↗
- MDN — String.prototype methods (filter to ES5 / pre-2010 for SSJS) ↗
What survives in production
indexOf returns -1 when not found, not 0
Same trap as SQL's CHARINDEX (which returns 0), but inverted: in SSJS String.indexOf returns -1 for "not found" and 0 for "found at the start." Conditional logic that checks > 0 will silently miss matches at position 0.
// AT RISK — misses matches at position 0 (e.g., "@example.com")
if (email.indexOf("@") > 0) {
// Treats "@example.com" as "no @ found"
}
// CORRECT — checks for actual not-found sentinel
if (email.indexOf("@") > -1) { /* found */ }
if (email.indexOf("@") !== -1) { /* found, equivalent */ }No reliable String.prototype.trim — polyfill with regex
SpiderMonkey 1.7 doesn't ship .trim() consistently. Don't depend on it.
// AT RISK — may throw "trim is not a function" on older tenants
var clean = email.trim();
// PORTABLE — always works
var clean = email.replace(/^\s+|\s+$/g, "");
// Or wrap once and reuse
function trim(s) {
return s == null ? s : String(s).replace(/^\s+|\s+$/g, "");
}The same applies to padStart, padEnd, includes, startsWith, endsWith — none of them are reliably present. Polyfill or substitute.
+ coerces null and undefined to literal strings
JavaScript stringifies eagerly: "hello " + null is "hello null", not "hello ". This sneaks into log messages and email content where you expected an empty string.
// AT RISK — log message becomes "Got null rows" instead of "Got 0 rows"
var count = null; // because LookupRows returned nothing and you forgot to default
Write("Got " + count + " rows");
// → "Got null rows"
// SAFE — coalesce nulls to a sensible default before string-concat
var count = rows ? rows.length : 0;
Write("Got " + count + " rows");
// → "Got 0 rows"
// Helper for log writes
function safeStr(v) {
return (v === null || v === undefined) ? "" : String(v);
}
Write("Email: " + safeStr(emailMaybe));The bug is invisible in dev because dev data is rarely null. It surfaces in production logs that read like garbled apologies.
replace only replaces the first match unless you use a regex with /g
A common mistake: passing a string as the search argument to replace and expecting all matches to be replaced.
// AT RISK — only replaces the first comma
"a,b,c,d".replace(",", ";");
// → "a;b,c,d" (not "a;b;c;d" as you might expect)
// CORRECT — regex with /g flag
"a,b,c,d".replace(/,/g, ";");
// → "a;b;c;d"
// Or use split + join for simple delimiter swaps
"a,b,c,d".split(",").join(";");
// → "a;b;c;d"For dynamic search strings, you have to construct a RegExp object:
var needle = ",";
var re = new RegExp(needle, "g");
"a,b,c,d".replace(re, ";");Platform.Function.Format is the SSJS replacement for template literals
Template literals (backticks + ${...}) don't exist. For multi-arg interpolated strings, Platform.Function.Format is cleaner than a chain of + concatenations.
// VERBOSE — many concatenations get hard to read
var msg = "Subscriber " + subKey + " (" + email + ") moved to tier " + tier
+ " at " + Now();
// CLEANER
var msg = Platform.Function.Format(
"Subscriber {0} ({1}) moved to tier {2} at {3}",
[subKey, email, tier, Now()]
);The args array can contain numbers, strings, dates — they're coerced to strings during the format. The placeholder syntax {0}, {1} matches array index.
Quick decision
Use Platform.Function.Format when:
- Building strings with 2+ interpolated values.
- The string is a log message, error message, or user-facing copy.
Use + concatenation when:
- 1–2 simple interpolations and the operands are guaranteed non-null.
- Inside a tight loop where every function call counts.
Use a regex /g with .replace when:
- Replacing all occurrences of a substring.
- The search pattern is dynamic — construct via
new RegExp(pattern, "g").
Polyfill instead of using ES2015+ string methods when:
- The script has to work across older SFMC tenants. Always assume the older tenant exists.
Use Platform.Function.FormatNumber / FormatDate when:
- Output goes to a user (CloudPage, email body) and locale matters.
Related
- Basics — supported language surface
- Platform.Function — the namespace where Format / FormatNumber / FormatDate live
- MC SSJS gotchas — see #1 (no modern JS — many string idioms missing)
- MC SQL — String functions — sibling for the SQL surface; many of the same NULL / index / case-fold considerations apply
More SSJS reference pages incoming: Date · Encoding · Hashing · Util function categories · Style Guide.
Plus how-to snippets for common production patterns — DE add/update/upsert, error handling, callout pagination, etc.