ssjs-server-side-javascript

Use this skill when writing, debugging, or reviewing Server-Side JavaScript (SSJS) in Salesforce Marketing Cloud — Script Activities, Cloud Pages, and Landing Pages. Covers WSProxy for SOAP API access, Script.Util.HttpRequest for outbound REST calls, error handling patterns, execution limits, and SSJS/AMPscript interoperability. NOT for AMPscript-only personalization logic inside Email Studio sends, not for standard Apex (Salesforce Platform), and not for client-side JavaScript in Experience Cloud or LWC.

Best use case

ssjs-server-side-javascript is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Use this skill when writing, debugging, or reviewing Server-Side JavaScript (SSJS) in Salesforce Marketing Cloud — Script Activities, Cloud Pages, and Landing Pages. Covers WSProxy for SOAP API access, Script.Util.HttpRequest for outbound REST calls, error handling patterns, execution limits, and SSJS/AMPscript interoperability. NOT for AMPscript-only personalization logic inside Email Studio sends, not for standard Apex (Salesforce Platform), and not for client-side JavaScript in Experience Cloud or LWC.

Teams using ssjs-server-side-javascript should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/ssjs-server-side-javascript/SKILL.md --create-dirs "https://raw.githubusercontent.com/PranavNagrecha/AwesomeSalesforceSkills/main/skills/apex/ssjs-server-side-javascript/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/ssjs-server-side-javascript/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How ssjs-server-side-javascript Compares

Feature / Agentssjs-server-side-javascriptStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Use this skill when writing, debugging, or reviewing Server-Side JavaScript (SSJS) in Salesforce Marketing Cloud — Script Activities, Cloud Pages, and Landing Pages. Covers WSProxy for SOAP API access, Script.Util.HttpRequest for outbound REST calls, error handling patterns, execution limits, and SSJS/AMPscript interoperability. NOT for AMPscript-only personalization logic inside Email Studio sends, not for standard Apex (Salesforce Platform), and not for client-side JavaScript in Experience Cloud or LWC.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# SSJS — Server-Side JavaScript

This skill activates when a practitioner needs to author, debug, or architect Server-Side JavaScript (SSJS) code running inside Salesforce Marketing Cloud. It provides grounded guidance on execution environments, WSProxy for SOAP access, HTTP functions for REST calls, error handling, variable scoping rules, and the SSJS/AMPscript interoperability model.

---

## Before Starting

Gather this context before working on anything in this domain:

- **Execution context:** is this running in a Script Activity (Automation Studio), a Cloud Page, or a Landing Page? The timeout, available functions, and subscriber context differ across contexts.
- **API target:** if calling SOAP APIs (retrieve/upsert Data Extensions, send Email, etc.), WSProxy is preferred over raw HTTP+XML. If calling external REST endpoints, use Script.Util.HttpRequest.
- **Most common wrong assumption:** SSJS is modern JavaScript. It is not. Marketing Cloud runs an ES3-compatible engine — `let`, `const`, arrow functions, template literals, destructuring, and Promises are unavailable.
- **Limits:** Script Activities time out at 30 minutes and have a 6 GB memory limit per execution. Cloud Pages have no documented long-execution window and should be treated as synchronous request/response.

---

## Core Concepts

### Execution Environments and the `<script runat="server">` Tag

SSJS code must be wrapped in `<script runat="server">` tags. Without the `runat="server"` attribute the block is treated as client-side JavaScript and does not execute on the Marketing Cloud server. SSJS can coexist with AMPscript in the same file — the Marketing Cloud rendering engine processes AMPscript substitutions first, then evaluates SSJS blocks. This allows AMPscript variables to be referenced inside SSJS if the AMPscript block is declared before the SSJS block.

### WSProxy — Preferred SOAP API Client

WSProxy (`Script.Util.WSProxy`) is the built-in Marketing Cloud SOAP API client for SSJS. It is the correct and preferred way to interact with Marketing Cloud objects (Data Extensions, Subscribers, Sends, etc.) from SSJS because:

- It handles SOAP envelope construction, authentication token injection, and paging automatically.
- It has significantly lower overhead than constructing raw SOAP XML via `Script.Util.HttpRequest`.
- Common operations: `retrieve`, `createItem`, `updateItem`, `upsertBatch`, `deleteItem`.

The core pattern:
```javascript
var prox = new Script.Util.WSProxy();
var cols = ["SubscriberKey", "EmailAddress", "Status"];
var filter = {
  Property: "Status",
  SimpleOperator: "equals",
  Value: "Active"
};
var result = prox.retrieve("Subscriber", cols, filter);
```

Retrieve results are paged. If `result.HasMoreRows` is true, use `prox.getNextPage()` to iterate.

### Script.Util.HttpRequest — Outbound REST/HTTP

For calls to external REST APIs or non-Marketing Cloud SOAP endpoints, use `Script.Util.HttpRequest`. This is a synchronous HTTP client that supports GET, POST, PUT, PATCH, and DELETE. Set headers and body before calling `request.send()`.

```javascript
var req = new Script.Util.HttpRequest("https://api.example.com/data");
req.emptyContentHandling = 0;
req.retryCount = 2;
req.setHeader("Content-Type", "application/json");
req.setHeader("Authorization", "Bearer " + token);
req.method = "POST";
req.postData = Stringify(payload);
var resp = req.send();
var body = Platform.Function.ParseJSON(resp.content);
```

### Error Handling and the Write() Logging Pattern

SSJS does not surface uncaught exceptions to the user in a useful way in Script Activities — an uncaught exception causes the entire Activity step to fail with a generic error, which makes diagnosis difficult. The mandatory pattern is `try/catch` around all significant operations with `Write()` logging inside the catch block.

`Write()` outputs text to the Script Activity log tab in Automation Studio, making it the primary debugging mechanism. Log the error message, stack if available, and any relevant variable state before re-throwing or gracefully continuing.

### ES3 Dialect Constraints

The SSJS engine is ES3-compatible. This means:
- Use `var` for variable declarations — `let` and `const` cause syntax errors.
- No arrow functions (`=>`); use `function` keyword.
- No template literals (backtick strings); use `+` concatenation.
- No destructuring, spread, or `Promise`.
- `JSON.stringify` / `JSON.parse` are not available — use `Stringify()` and `Platform.Function.ParseJSON()` instead.
- `typeof`, `instanceof`, standard `for` loops, and `try/catch/finally` work normally.

---

## Common Patterns

### WSProxy Upsert to a Data Extension

**When to use:** Bulk insert or update records in a Data Extension from a Script Activity, typically after retrieving data from an external API or another system.

**How it works:**
```javascript
<script runat="server">
Platform.Load("Core", "1.1.1");
try {
  var prox = new Script.Util.WSProxy();
  var rows = [
    { keys: { SubscriberKey: "abc123" }, values: { FirstName: "Ana", Score: "95" } },
    { keys: { SubscriberKey: "def456" }, values: { FirstName: "Ben", Score: "80" } }
  ];
  var result = prox.upsertBatch("DataExtensionObject", rows, { Name: "My_DE_ExternalKey" });
  Write("Upserted: " + result.Status);
} catch(e) {
  Write("ERROR: " + e.message);
}
</script>
```

**Why not the alternative:** Using AMPscript `UpsertDE()` works for small single-record updates inside sends, but it cannot handle batch operations, does not provide programmatic status checking, and is not appropriate for Automation Studio Script Activities.

### Outbound REST Call with Error Logging

**When to use:** Pulling data from an external REST API (CRM, ERP, custom backend) inside a Script Activity and writing results to a Data Extension.

**How it works:**
```javascript
<script runat="server">
Platform.Load("Core", "1.1.1");
try {
  var req = new Script.Util.HttpRequest("https://api.example.com/leads");
  req.emptyContentHandling = 0;
  req.retryCount = 1;
  req.setHeader("Authorization", "Bearer MyToken");
  req.method = "GET";
  var resp = req.send();
  if (resp.statusCode != 200) {
    throw new Error("HTTP error: " + resp.statusCode);
  }
  var data = Platform.Function.ParseJSON(resp.content);
  // process data...
  Write("Retrieved " + data.length + " leads.");
} catch(e) {
  Write("FAILED: " + e.message);
  // log to error DE if needed
}
</script>
```

---

## Decision Guidance

| Situation | Recommended Approach | Reason |
|---|---|---|
| Retrieve/upsert Marketing Cloud objects (Subscribers, DEs, Sends) | WSProxy | Handles auth, paging, SOAP envelope automatically; lower overhead than raw HTTP |
| Call external REST API from Script Activity | Script.Util.HttpRequest | Designed for outbound HTTP; handles headers, methods, retries |
| Per-subscriber email personalization at send time | AMPscript | AMPscript has subscriber context; SSJS does not run per-subscriber during sends |
| Complex data transformation, looping, conditional logic in Automation | SSJS Script Activity | SSJS supports full procedural logic; AMPscript is template-oriented |
| Debugging a failing Script Activity | Write() + try/catch | Write() outputs to Activity log; uncaught exceptions give no diagnostic info |
| Need to call a SOAP API without WSProxy | Script.Util.HttpRequest + raw XML | Last resort only — WSProxy is always preferred for SOAP |

---

## Recommended Workflow

Step-by-step instructions for an AI agent or practitioner working on this task:

1. **Confirm execution context** — identify whether this is a Script Activity, Cloud Page, or Landing Page. Script Activity: check timeout risk (30-min limit). Cloud Page: check whether code needs to be synchronous and handle subscriber context.
2. **Identify the API target** — if interacting with Marketing Cloud objects (Data Extensions, Subscribers, Sends), plan to use WSProxy. If calling external endpoints, plan to use Script.Util.HttpRequest.
3. **Author the SSJS block** — wrap all code in `<script runat="server">` tags. Load the Core library with `Platform.Load("Core", "1.1.1")`. Use only `var` for declarations. Use `Stringify()` and `Platform.Function.ParseJSON()` instead of `JSON.stringify`/`JSON.parse`.
4. **Wrap in try/catch** — every meaningful operation (API call, WSProxy call, data write) must be inside a try/catch block with `Write()` logging in the catch. Never allow uncaught exceptions in Script Activities.
5. **Implement paging if using WSProxy retrieve** — check `result.HasMoreRows` after every `prox.retrieve()` call and loop with `prox.getNextPage()` until false to avoid silently missing records.
6. **Test incrementally** — run the Script Activity manually in Automation Studio, check the Activity log tab for Write() output, verify DE row counts before and after.
7. **Review for ES3 compatibility** — scan for `let`, `const`, arrow functions, template literals, `JSON.stringify`, `JSON.parse`, `Promise`, and `async/await` — all are unsupported and will cause syntax or runtime errors.

---

## Review Checklist

Run through these before marking work in this area complete:

- [ ] All code is inside `<script runat="server">` tags
- [ ] `Platform.Load("Core", "1.1.1")` is present at the top of the block
- [ ] No `let`, `const`, arrow functions, template literals, or modern JS syntax
- [ ] All API calls and data writes are wrapped in try/catch with Write() in the catch block
- [ ] WSProxy retrieve loops check `HasMoreRows` and call `getNextPage()` if paging is possible
- [ ] Script.Util.HttpRequest calls check `resp.statusCode` before consuming `resp.content`
- [ ] Sensitive values (tokens, passwords) are stored in Data Extensions or Content Builder, not hardcoded

---

## Salesforce-Specific Gotchas

Non-obvious platform behaviors that cause real production problems:

1. **Script Activity 30-minute timeout is absolute** — If a Script Activity exceeds 30 minutes of execution time, it terminates without completing and the step is marked as an error. There is no graceful shutdown callback. For large-volume operations, split work across multiple Activities or use Query Activities for set-based data operations instead.

2. **WSProxy retrieve does not return all rows by default** — `prox.retrieve()` returns a paged result set. If you do not check `result.HasMoreRows` and call `prox.getNextPage()`, you silently process only the first page of results (typically 2,500 rows). This causes data processing gaps that are very hard to detect.

3. **AMPscript is evaluated before SSJS** — In a mixed file, AMPscript variable substitution happens before the SSJS engine runs. This means AMPscript `@variables` can inject values into SSJS string literals, but SSJS variables cannot be read by AMPscript in the same file. Relying on SSJS output being available to AMPscript in the same render pass will not work.

---

## Output Artifacts

| Artifact | Description |
|---|---|
| SSJS Script Activity file | Complete `<script runat="server">` block ready to paste into an Automation Studio Script Activity |
| WSProxy retrieve/upsert snippet | Parameterized code block for reading from or writing to a Data Extension via WSProxy |
| HTTP request snippet | Script.Util.HttpRequest pattern for outbound REST calls with header, method, and error handling |
| Error logging pattern | try/catch + Write() template for any Script Activity block |

---

## Related Skills

- `data/marketing-cloud-sql-queries` — Use for set-based data transformation inside Automation Studio; SQL Query Activity is more efficient than SSJS loops for bulk DE-to-DE operations
- `data/marketing-cloud-data-sync` — Use when the goal is syncing data between Marketing Cloud and external systems at the platform configuration level rather than via SSJS scripting
- `admin/consent-management-marketing` — Use when SSJS is being used to read or write subscription/preference data; consent rules affect which DE fields are writable

Related Skills

lwc-server-sent-events

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when building LWCs that must react to live server pushes — Platform Events, Change Data Capture, or streaming updates — via the lightning/empApi (CometD) subscription model. Covers lifecycle, replayId, error handling, reconnection, scale considerations, and multi-tab behavior. Does NOT cover publishing events (see platform-events or apex-platform-events).

health-cloud-data-residency

8
from PranavNagrecha/AwesomeSalesforceSkills

Use this skill when architecting Health Cloud orgs that must satisfy geographic data residency, HIPAA, GDPR, or national health-data regulations on Hyperforce — including scoping the HIPAA BAA, mapping transient processing exceptions, and documenting which features require separate compliance addenda. NOT for generic multi-region Salesforce architecture unrelated to healthcare data, and NOT for non-healthcare data residency requirements (use a general Hyperforce architecture skill for those).

salesforce-mcp-server-setup

8
from PranavNagrecha/AwesomeSalesforceSkills

Use this skill to install and configure the salesforce-mcp-lib Apex package and npm stdio proxy so that an MCP client (Claude Desktop, Cursor, ChatGPT) can call Salesforce org data and logic via the Model Context Protocol. Trigger keywords: MCP server, salesforce-mcp-lib, Claude Desktop Salesforce, MCP proxy setup, Apex JSON-RPC, MCP Connected App. NOT for Salesforce Hosted MCP Servers (Agentforce-native hosted endpoints), NOT for Flow-based tool definitions, NOT for OmniStudio integrations.

xss-and-injection-prevention

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when writing or reviewing Visualforce pages, Apex controllers, or LWC components that output user-supplied data, build dynamic queries, or construct HTTP responses. Triggers: 'XSS in Visualforce', 'SOQL injection vulnerability', 'how to encode output in Apex', 'JSENCODE Visualforce', 'open redirect prevention'. NOT for Apex CRUD/FLS enforcement (use soql-security or apex-crud-and-fls), NOT for Shield encryption (use shield-encryption-key-management), NOT for AppExchange security review process (use secure-coding-review-checklist).

visualforce-security-and-modernization

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when hardening or modernizing legacy Visualforce pages — covers the platform CSRF token model and when disabling it is a security regression, view state encryption guarantees and the 170 KB ceiling, FLS/CRUD enforcement gaps on `<apex:outputField>` and on getters that return sObjects, `<apex:includeScript>` interaction with the org Content Security Policy, hosting LWC inside a VF page via `lightning:container` / `lightning-out`, and the retire-vs-harden-vs-leave-alone decision for an inventory of legacy pages. Triggers: 'should I rewrite this Visualforce page in LWC', 'CSRF protection disabled on Visualforce page is that safe', 'community user sees a field they should not on a Visualforce page', 'view state encryption is that enough for sensitive data', 'how do I host an LWC inside a Visualforce page', 'apex:dynamicComponent and apex:actionFunction safe to keep'. NOT for greenfield Visualforce architecture (use apex/visualforce-fundamentals — controller types, view state pattern selection, PDF rendering); NOT for Visualforce email template authoring (use apex/visualforce-email-templates if/when that skill is authored); NOT for general Apex security review across triggers and async (use apex/soql-security and security/secure-coding-review-checklist).

transaction-security-policies

8
from PranavNagrecha/AwesomeSalesforceSkills

Transaction Security policy creation and configuration: condition builder, enhanced policies, enforcement actions (block, MFA, notification, end session), real-time monitoring mode, and policy troubleshooting. NOT for Event Monitoring log analysis or Shield Event Monitoring setup (use event-monitoring). NOT for Apex testing or debug-log analysis.

sso-saml-troubleshooting

8
from PranavNagrecha/AwesomeSalesforceSkills

Diagnosing broken SAML SSO into Salesforce — IdP-initiated vs SP-initiated flows, signing-certificate validity / expiry, NameID format mismatches, RelayState handling, audience / entityId / issuer mismatches, clock skew, the SAML Assertion Validator in Setup, the Login History debug log, and the My Domain prerequisite for SSO. Covers the standard diagnostic loop: read the SAML response, identify which check failed, fix at the IdP or SP. NOT for OAuth / OpenID Connect SSO (see security/oauth-openid-troubleshooting), NOT for setting up SSO from scratch (see security/sso-saml-setup).

shield-kms-byok-setup

8
from PranavNagrecha/AwesomeSalesforceSkills

Configure Shield Platform Encryption with customer-supplied (BYOK) or customer-held (Cache-Only Key Service) tenant secrets, rotate them, and recover. NOT for Classic Encryption or field masking.

shield-event-log-retention-strategy

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when designing Salesforce Shield Event Monitoring retention, SIEM routing, and storage-tier strategy — which event types to keep, for how long, where, and how to answer audit queries across hot/warm/cold tiers. Triggers: 'shield event log retention', 'route event monitoring to splunk', 'how long to keep login history', 'siem salesforce integration', 'event monitoring storage tier'. NOT for enabling Shield (see salesforce-shield-deployment).

session-management-and-timeout

8
from PranavNagrecha/AwesomeSalesforceSkills

Use this skill when configuring session timeout values, concurrent session limits, session IP locking, or logout behavior in Salesforce. Covers org-wide session settings, profile-level overrides, Connected App session policies, and Metadata API SecuritySettings deployment. NOT for OAuth token refresh flows, login IP ranges, or MFA/identity-provider configuration.

session-high-assurance-policies

8
from PranavNagrecha/AwesomeSalesforceSkills

Enforce step-up authentication for sensitive pages/objects using High Assurance session level and login flow policies. NOT for initial MFA enrollment UX.

service-account-credential-rotation

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when designing credential rotation for integration users, connected apps, named credentials, and OAuth client secrets in Salesforce. Covers rotation cadence, zero-downtime handover, secret storage, and detection of stale credentials. Triggers: 'rotate integration user password', 'connected app secret rotation', 'named credential rotation', 'stale service account', 'zero downtime secret rotation'. NOT for end-user password policies.