Skip to main content
Kodexa uses GoJA, a Go-based JavaScript engine, for server-side scripting across the platform. Scripts can validate uploads, route workflows, react to data changes, and compute dynamic dropdown options.

Runtime Characteristics

GoJA supports ES5 with partial ES6 features including arrow functions, template literals, let/const, and destructuring. However, it is synchronous only — there is no support for async/await, Promises, or event loops.
Key constraints:
  • Sandboxed — no filesystem access, no network access (except via service bridges)
  • No module system — no require() or import
  • Synchronous — all calls are blocking; no callbacks or timers
  • Deterministic — same inputs always produce same outputs

Execution Contexts

Scripts run in different contexts depending on where they are configured. Each context has its own timeout, globals, and intended purpose.
ContextTimeoutUse CaseAvailable Globals
Intake Scripts5 secondsValidate and route uploadsfilename, fileSize, mimeType, metadata, document, log()
Script Steps15 secondsPlan workflow routingtask, families, loadDocument(), serviceBridge, llm, log()
Event Subscriptions2 secondsReact to attribute changescurrentObject, event, bridge.data, serviceBridge, log()
Selection Option Formulas2 secondsCompute dropdown optionsserviceBridgeCall(), attribute references

Core Globals

These functions are available in all scripting contexts.

log()

Write messages to the platform execution log.
log("info", "Processing document");
log("debug", "Current value: " + someValue);
log("warn", "Missing expected attribute");
log("error", "Validation failed for field: " + fieldName);
Supported levels: debug, info, warn, error.

console.log()

A convenience wrapper that joins arguments with a space and writes at debug level.
console.log("Document UUID:", doc.GetUUID());
console.log("Found", results.length, "matches");

Document API — ScriptDocument

The ScriptDocument object represents a loaded Kodexa document (KDDB). It is available as document in intake scripts and returned by loadDocument() in script steps.
MethodReturnsDescription
GetUUID()stringUnique document identifier
GetVersion()stringDocument format version
GetMixins()string[]Active mixins (e.g., "spatial")
GetLabels()string[]All labels on the document
GetMetadata()objectDocument metadata key-value pairs
GetAllTags()string[]All tag names present in the document

Example: Querying a Document

var doc = loadDocument(family.documentVersion);
var invoices = doc.FindDataObjectsByPath("Invoice");

for (var i = 0; i < invoices.length; i++) {
  var inv = invoices[i];
  var total = inv.GetFirstAttributeValue("total_amount");
  log("info", "Invoice total: " + total);
}

doc.Close();

Data Object API — ScriptDataObject

Data objects represent extracted entities (invoices, line items, claims) within a document. They form a tree structure with parent-child relationships.
GetFirstAttributeValue() returns the current typed value, not the original extracted text. The value precedence is: StringValue > DecimalValue > BooleanValue > DateValue (RFC 3339) > raw Value.

Example: Reading and Writing Attributes

var obj = currentObject;
if (!obj) return;

// Read an attribute
var status = obj.GetFirstAttributeValue("claim_status");
log("info", "Current status: " + status);

// Add a computed attribute
var amount = obj.GetFirstAttributeValue("line_amount") || 0;
var tax = obj.GetFirstAttributeValue("tax_rate") || 0;
var total = amount * (1 + tax / 100);

obj.AddAttribute({
  tag: "total_with_tax",
  decimalValue: total
});

Data Attribute API — ScriptDataAttribute

Data attributes store individual typed values on a data object. Each attribute has a tag name, optional typed values, and audit trail tracking.
MethodReturnsDescription
GetValue()stringRaw/audit-trail value
GetStringValue()string or nullTyped string value
GetDecimalValue()number or nullTyped decimal value
GetBooleanValue()boolean or nullTyped boolean value
GetDateValue()string or nullRFC 3339 date string
No-op suppression: Writes that do not actually change the value are automatically suppressed and will not trigger downstream recalculation. This uses epsilon comparison for decimals (1e-9) and time.Equal() for dates. You do not need to guard against redundant writes.

Example: Updating an Attribute

var attr = currentObject.GetAttributeByName("invoice_total");
if (attr) {
  var current = attr.GetDecimalValue();
  if (current !== null && current > 10000) {
    attr.SetStringValue("HIGH VALUE");
    log("info", "Flagged high-value invoice: " + current);
  }
}

Content Node API — ScriptContentNode

Content nodes represent the structural elements of a document’s content tree: pages, lines, words, tables, and cells.

Example: Searching Content Nodes

var doc = loadDocument(family.documentVersion);
var root = doc.GetContentNode();

// Find all lines on page 1
var lines = root.Select("//line[hasTag('kodexa-spatial')]", {});
for (var i = 0; i < lines.length; i++) {
  if (lines[i].GetPage() === 1) {
    log("info", "Page 1 line: " + lines[i].GetContent());
  }
}

doc.Close();

Context-Specific Details

Intake Scripts

Intake scripts run when a file is uploaded to a document store. Use them to validate, classify, or route incoming files.
// Available globals
log("info", "File: " + filename);
log("info", "Size: " + fileSize + " bytes");
log("info", "Type: " + mimeType);

// Access upload metadata
var source = metadata["source"] || "unknown";

// Reject files that are too large
if (fileSize > 50 * 1024 * 1024) {
  log("error", "File exceeds 50MB limit");
  throw new Error("File too large");
}

Script Steps

Script steps run within assistant workflows and can load documents, call service bridges, and invoke LLMs.
// Iterate over document families in the task
for (var i = 0; i < families.length; i++) {
  var family = families[i];
  var doc = loadDocument(family.documentVersion);

  var dataObjects = doc.GetAllDataObjects();
  log("info", "Found " + dataObjects.length + " data objects");

  doc.Close();
}

Event Subscriptions

Event subscriptions run in response to attribute changes on data objects within a taxonomy. They are configured on the Event Subscriptions tab of the taxonomy editor.
// Always guard against null
if (!currentObject) return;

var obj = currentObject; // the data object that changed

// Read the changed attribute
var amount = obj.GetFirstAttributeValue("invoice_amount");

// Call an external service via bridge
var result = serviceBridge.call("myorg/validation-api", "validate", {
  amount: amount
});

if (result && result.valid) {
  bridge.data.setAttribute(obj.GetID(), "status", "Validated");
}

Selection Option Formulas

Selection option formulas compute dynamic dropdown values for data form fields. They can call service bridges and reference attributes.
// Call a service bridge to fetch options
var response = serviceBridgeCall("lookup-bridge", "/api/options");
var items = JSON.parse(response);

// Return an array of {label, value} objects
var options = [];
for (var i = 0; i < items.length; i++) {
  options.push({
    label: items[i].name,
    value: items[i].code
  });
}
return options;

Best Practices

Guard against null values. In event subscriptions, always check that currentObject exists before accessing it. In any context, attribute lookups may return null or undefined.
if (!currentObject) return;
var val = obj.GetFirstAttributeValue("field") || "default";
Use typed setters. Prefer SetStringValue(), SetDecimalValue(), SetBooleanValue(), and SetDateValue() over SetValue(). Typed setters ensure proper type coalescing and no-op suppression.
Keep scripts focused. Each script should have a single, clear purpose. Complex logic is better split across multiple steps or event subscriptions.
Be aware of timeouts. Intake scripts have 5 seconds, script steps have 15 seconds, and event subscriptions and option formulas have only 2 seconds. Avoid unnecessary loops or redundant document loads.
No async operations. GoJA does not support Promises, async/await, setTimeout, or setInterval. All code runs synchronously. If you need to call an external API, use the serviceBridge global.
Debugging tip: Use log("debug", ...) liberally during development. Debug-level messages appear in the execution log but do not affect production behavior. Remove or reduce logging once the script is stable.

Common Patterns

Null-safe Attribute Access

var attr = obj.GetAttributeByName("optional_field");
var value = attr ? attr.GetStringValue() : null;
var safeValue = value || "N/A";

Iterating Children

var lineItems = parentObj.GetChildrenByPath("LineItem");
var total = 0;
for (var i = 0; i < lineItems.length; i++) {
  var amount = lineItems[i].GetFirstAttributeValue("amount") || 0;
  total += amount;
}
log("info", "Computed total: " + total);

Conditional Attribute Creation

var existing = obj.GetAttributeByName("computed_flag");
if (!existing) {
  obj.AddAttribute({
    tag: "computed_flag",
    booleanValue: true
  });
}

Date Comparisons

var dateStr = obj.GetFirstAttributeValue("due_date");
if (dateStr) {
  var due = new Date(dateStr);
  var now = new Date();
  if (due < now) {
    log("warn", "Past due: " + dateStr);
    obj.AddAttribute({ tag: "overdue", booleanValue: true });
  }
}

Troubleshooting

Script timeout exceeded — Your script is taking too long. Reduce iterations, avoid loading large documents unnecessarily, and move complex logic to module-based processing.
undefined is not a function — You are calling a method that does not exist in the GoJA runtime. Check for typos and verify the method is available in the API tables above. Remember: no Array.map(), Array.filter(), or other ES6+ array methods.
null reference errors — Always check return values before calling methods on them. GetAttributeByName(), GetParent(), SelectFirst(), and similar methods can return null.
Writes not taking effect — If you are using SetValue() but downstream formulas are not recalculating, switch to a typed setter (SetStringValue(), SetDecimalValue(), etc.). The no-op suppression logic only applies to typed values.