Skip to main content

Platform.Function — Referencia de SSJS en Marketing Cloud

El namespace API core de SSJS — lecturas y escrituras de Data Extensions (LookupRows, InsertData, UpdateData, UpsertData, DeleteData) más los helpers que usás en cada script (GUID, Now, ParseJSON). Qué funciona como está documentado, qué tiene trampas silenciosas, y los patrones que terminamos usando.

Referencia·Actualizado 2026-05-08·Escrito por Lira · Editado por German Medina

Platform.Function.* es donde pasa el trabajo real en SSJS. JavaScript plano te da control flow; este namespace te da lecturas y escrituras de Data Extension, generación de GUID, parseo de JSON, hora actual, encoding, hashing — las operaciones que interactúan con Marketing Cloud mismo. La mayoría de las líneas en un script SSJS útil son llamadas a este namespace.

Esta página cubre las operaciones que vas a usar en el 90% de los scripts. Las llamadas restantes de Platform.Function.* viven en páginas dedicadas de categorías de funciones (string / date / encoding / hashing) que vienen después.

Sintaxis oficial

El namespace queda disponible después de Platform.Load("Core","1.1.5") (ver gotchas — #2). Las llamadas más usadas:

Platform.Load("Core", "1.1.5");

// === LECTURAS DE DATA EXTENSION ===

// Lookup por una sola columna → array de objetos fila (capado a 2500)
var rows = Platform.Function.LookupRows(
  "master_subscribers",   // nombre del DE
  "SubscriberKey",        // columna de filtro
  "12345"                 // valor de filtro
);

// Lookup por múltiples columnas → AND entre todos los filtros
var activeRows = Platform.Function.LookupRows(
  "master_subscribers",
  "Status", "Active",
  "LoyaltyTier", "gold"
);

// Lookup con orden → primeras 2500 filas ordenadas por columna DESC/ASC
var topPurchases = Platform.Function.LookupOrderedRows(
  "purchases",
  100,                    // top N (max 2500)
  "OrderDate desc",       // cláusula de orden
  "SubscriberKey", "12345"
);

// === ESCRITURAS DE DATA EXTENSION ===

// Insert (siempre agrega, sin merge)
Platform.Function.InsertData(
  "de_log_runs",
  ["RunId", "Step"],          // columnas key
  ["abc-123", "lookup"],       // valores key
  ["Ts", "Message"],           // columnas adicionales
  [Now(), "lookup completed"]  // valores adicionales
);

// Update (matchea fila(s) existente(s) por columnas key; cols no-key se actualizan)
Platform.Function.UpdateData(
  "master_subscribers",
  ["SubscriberKey"], ["12345"],
  ["Status", "UpdatedAt"], ["Active", Now()]
);

// Upsert (update si la PK matchea, insert si no — pero ver gotcha #4)
Platform.Function.UpsertData(
  "master_subscribers",
  ["SubscriberKey"], ["12345"],
  ["Status", "UpdatedAt"], ["Active", Now()]
);

// Delete (matchea por columnas key; borra TODAS las filas que matcheen)
Platform.Function.DeleteData(
  "de_log_overrides",
  ["RunId"], ["abc-123"]
);

// === HELPERS ===

Platform.Function.GUID();                  // → "ab1cd234-ef56-7890-..."
Platform.Function.ParseJSON('{"a":1}');    // → { a: 1 }
Platform.Function.Stringify({a:1});        // → '{"a":1}'
Now();                                     // datetime actual (UTC)

Las firmas comparten todas la misma forma: nombre del DE primero, después dos arrays pareados para columnas key + valores key, después opcionalmente dos arrays más pareados para columnas no-key + valores. Confundir el orden de los arrays es la fuente más común de bugs "la función funciona pero escribe basura".

| Función | Devuelve | Usar para | |---|---|---| | LookupRows(de, col, val) | Array de objetos fila, max 2500 | Filtrar por 1 columna | | LookupRows(de, col1, val1, col2, val2) | Array, max 2500 | AND entre múltiples cols | | LookupOrderedRows(de, top, order, ...) | Array, max 2500 | Lecturas Top-N con orden | | RetrieveDEByName(name) | Objeto DE (metadata) | Introspección de schema | | InsertData(de, keys, vals) | Conteo de filas nuevas (1) | Agregar sin dedup | | UpdateData(de, keys, vals, [cols], [vals]) | Conteo de filas actualizadas | Matchear por key, actualizar cols | | UpsertData(de, keys, vals, [cols], [vals]) | Conteo de filas afectadas | Upsert (PK-aware, ver gotcha #4) | | DeleteData(de, keys, vals) | Conteo de filas borradas | Eliminar filas por key | | GUID() | String tipo UUID | RunIDs, claves de idempotencia | | ParseJSON(str) | Objeto / array | Parsear JSON en tenants viejos | | Stringify(obj) | String JSON | Serializar para escrituras a log |

Referencia:

Lo que sobrevive en producción

LookupRows capa silenciosamente a 2500 — codealo defensivamente

La forma de bug SSJS más común: un script funciona en dev con 500 filas, sale a producción con 50.000 filas, y silenciosamente procesa 2500 de ellas. No hay error. La función devuelve un array de 2500 elementos y el caller itera felizmente.

// EN RIESGO — si LookupRows devuelve exactamente 2500, casi seguro
// te perdiste filas. El script no sabe que fue truncado.
var rows = Platform.Function.LookupRows("master_subs", "Status", "Active");
for (var i = 0; i < rows.length; i++) {
  // ... procesar fila
}

// DEFENSIVO — chequeá el cap y surfaceá la truncación
var rows = Platform.Function.LookupRows("master_subs", "Status", "Active");
if (rows.length === 2500) {
  Platform.Function.UpsertData(
    "de_log_errors",
    ["RunId"], [runId],
    ["Step","Msg","Ts"],
    ["lookup-cap-hit", "LookupRows devolvió 2500 — probablemente truncado", Now()]
  );
  // O fallá fuerte, o pivoteá a WSProxy/SQL Activity para el set completo
}

Para semántica real de "todas las filas", bajá a WSProxy con retrieves paginados, o pivoteá a una SQL Query Activity (que está diseñada para lecturas bulk). Ver gotchas SSJS — #5.

UpsertData requiere que la PK del DE de destino esté configurada correctamente

UpsertData funciona solo cuando el DE de destino tiene primary key sobre las columnas que pasás como keys. Sin esa PK, la función silenciosamente inserta duplicados (o, en algunos tenants, no hace nada). Siempre verificá la configuración del DE de destino antes de usar esta función.

// EN RIESGO — asume que el destino tiene SubscriberKey como PK.
// Si no, vas a seguir agregando filas.
Platform.Function.UpsertData(
  "master_subs",
  ["SubscriberKey"], [subKey],
  ["EmailAddress", "Status"], [email, "Active"]
);

// DEFENSIVO — como mínimo, confirmá la PK una vez antes de que esta llamada
// llegue a producción. Si el equipo no puede prometer que la PK está configurada,
// fallback a read-then-write:
var existing = Platform.Function.LookupRows("master_subs", "SubscriberKey", subKey);
if (existing.length > 0) {
  Platform.Function.UpdateData(
    "master_subs",
    ["SubscriberKey"], [subKey],
    ["EmailAddress", "Status"], [email, "Active"]
  );
} else {
  Platform.Function.InsertData(
    "master_subs",
    ["SubscriberKey", "EmailAddress", "Status"], [subKey, email, "Active"]
  );
}

La versión read-then-write cuesta un LookupRows extra pero no depende de configuración de schema fuera de tu control. Ver gotchas SSJS — #4.

DeleteData matchea por columnas key y borra cada match

DeleteData no le importa la unicidad. Si tres filas matchean la key que pasaste, las tres se borran. Si pretendías borrar una fila específica, asegurate que tus columnas + valores key la identifiquen únicamente.

// EN RIESGO — si múltiples filas tienen RunId="abc-123", todas
// se borran, no solo la que vos querías
Platform.Function.DeleteData(
  "de_log_overrides",
  ["RunId"], ["abc-123"]
);

// SEGURO — componé la key con columnas que identifiquen únicamente la fila
Platform.Function.DeleteData(
  "de_log_overrides",
  ["RunId", "Step"], ["abc-123", "lookup"]
);

Para semántica de "borrar una sola fila", las columnas key tienen que matchear la primary key real del DE de destino.

GUID() para run IDs y claves de idempotencia

Platform.Function.GUID() devuelve un string UUID fresco por llamada. Usalo como RunId al tope de cada script y pasalo a cada escritura de log — así cada fila en de_log_* se ata a la corrida de Activity específica que la escribió.

Platform.Load("Core", "1.1.5");
var runId = Platform.Function.GUID();

Platform.Function.InsertData(
  "de_log_runs",
  ["RunId", "Step", "Ts"],
  [runId, "start", Now()]
);

// ... cuerpo del script, todas las escrituras de log llevan el mismo runId

Platform.Function.InsertData(
  "de_log_runs",
  ["RunId", "Step", "Ts"],
  [runId, "end", Now()]
);

Cuando investigás una falla, queryeás WHERE RunId = '...' y obtenés cada fila que ese script escribió, en orden. Sin un RunId, el log es una sopa.

ParseJSON / Stringify sobre el JSON.* nativo por portabilidad

Los tenants modernos de SFMC soportan JSON.parse y JSON.stringify, pero los tenants viejos no. Las versiones de Platform están garantizadas para funcionar entre ediciones. Default a Platform.Function.ParseJSON() y Platform.Function.Stringify() salvo que conozcas la edición de tu tenant.

// PORTÁTIL
var obj = Platform.Function.ParseJSON('{"key":"value"}');
var str = Platform.Function.Stringify(obj);

// Puede no funcionar en tenants viejos
var obj = JSON.parse('{"key":"value"}');
var str = JSON.stringify(obj);

Decisión rápida

Usá LookupRows cuando:

  • Necesitás leer menos de 2500 filas de un DE.
  • El filtro es por 1–2 columnas con igualdad simple.
  • Defensivo: siempre chequeá .length === 2500 para detectar cap-hit.

Usá LookupOrderedRows cuando:

  • Necesitás filas top-N en un orden específico. Aplica el mismo cap de 2500.

Bajá a WSProxy cuando:

  • Necesitás más de 2500 filas.
  • Necesitás recuperar objetos de Salesforce más allá del scope del wrapper (Subscriber, List, etc. con filtros SOAP completos).
  • Necesitás operaciones async / batch.

Usá InsertData cuando:

  • El destino es un log de eventos o tabla append-only. Sin dedup necesario en momento de escritura.

Usá UpdateData cuando:

  • La(s) fila(s) definitivamente existen y solo querés actualizar columnas no-key.
  • El DE de destino no tiene la PK que necesitarías para UpsertData.

Usá UpsertData cuando:

  • El DE de destino tiene primary key sobre las columnas que estás pasando como keys (verificá en la UI antes de deployar).
  • La semántica es "hacé que esta fila se vea como X, exista o no".

Usá el patrón read-then-write en lugar de UpsertData cuando:

  • No estás 100% seguro de la configuración de PK.
  • Necesitás comportamiento distinto para insert vs update (ej. setear CreatedAt solo en insert).

Relacionado

  • Basics — qué es SSJS y dónde corre (empezá acá)
  • MC SSJS gotchas — ver #4 (trampa de PK de UpsertData), #5 (cap de 2500 de LookupRows), #7 (try/catch silencioso)
  • MC SQL — INSERT INTO — mismo modelo mental de target-action en la superficie SQL
  • MC SQL gotchas — #1 — la regla de no-transacciones que compoundea entre escrituras SSJS

Próximas páginas de referencia SSJS: WSProxy · Variable + Util · Categorías de funciones String / Date / Encoding / Hashing · Style Guide.

Más snippets how-to para patrones comunes de producción — secuencias DE add/update/upsert, manejo de errores, paginación de callouts, etc.