Skip to content

Template (ctx.template) ​

ctx.template.render renders a template stored in CoCoCo, looked up by its handle. Templates are tenant resources, so wording can change without touching the script.

text
ctx.template.render(handle: string, variables: table?) -> (ok, output)

The first argument is always the handle of a stored template. Passing template source text does not work: it is looked up as a handle and fails.

Template kinds ​

Each stored template has a kind, and the kind decides what output is:

KindSyntaxoutput
STENCILStencil text templates (example below)the rendered text
XMLXML with DataXML directivesthe expanded XML text
XMLPDFan XML layout document rendered to PDFthe PDF, base64-encoded

For STENCIL templates, {% include %} and {% extends %} are disabled: a template cannot load other templates. A STENCIL template looks like this:

text
Hello {{ customer }},

{% if total %}Your order total is {{ total }}.{% endif %}

Example ​

lua
local ok, text = ctx.template.render("order-confirmation", {
  customer = "Acme Corp",
  total = 1240.5,
})
if not ok then error(text) end

return { output = text, length = string.len(text) }

Variables are passed to the template as JSON-compatible data: tables, strings, numbers and booleans.

Errors ​

An unknown handle, a non-table variables argument, or an error while rendering raises instead of returning false. Wrap the call in pcall if the handle comes from input:

lua
local input = ...
local handle = "order-confirmation"
if type(input) == "table" and type(input.template) == "string" then
  handle = input.template
end

local rendered, result = pcall(function()
  local ok, text = ctx.template.render(handle, { customer = "Acme Corp" })
  if not ok then error(text) end
  return text
end)

if not rendered then
  ctx.log.warn("template render failed", { handle = handle, reason = tostring(result) })
  return { ok = false }
end
return { ok = true, output = result }

In integrations ​

Integration scripts can only render templates declared as template resources in the integration manifest and bound on the instance. Pass the manifest resource ID instead of a handle.

Connect machines, automate workflows, and build custom apps for print production.