> ## Documentation Index
> Fetch the complete documentation index at: https://www.nexrender.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Scripting examples

> Tested scripts for common tasks: logging, setting text, reading and writing files, replacing footage, and stopping a job with a clear error

Each example shows the script asset to add to your job's `assets` and the script itself. Every example was tested on Nexrender Cloud, in the [sandbox](https://www.nexrender.com/docs/cloud/scripting/sandbox.md).

The examples use the compositions and layers of a product promo template: the job renders `main_single_products`, which contains a `single_product` composition with text layers such as `var_product_name_1`. Replace those names with your template's own. To list them, use [`GET /v3/templates/{id}/layers`](https://www.nexrender.com/docs/cloud/templates/inspecting) or `nexrender template layers TEMPLATE_ID`.

## Log what your script does

`nexrender.log` writes to the job's render log. Use it to trace what your script did, and to debug it.

```json Script asset theme={null}
{
  "type": "script",
  "src": "https://example.com/scripts/log.jsx"
}
```

```javascript log.jsx theme={null}
nexrender.log("Rendering " + nexrender.renderCompositionName);
```

Read the log with `nexrender job logs JOB_ID` or `GET /jobs/{id}/logs`:

```text Render log theme={null}
NX: Rendering main_single_products
```

## Set text from a parameter

```json Script asset theme={null}
{
  "type": "script",
  "src": "https://example.com/scripts/set-text.jsx",
  "parameters": [
    { "key": "title", "value": "Hello from a script" }
  ]
}
```

```javascript set-text.jsx theme={null}
var title = NX.get("title") || "Default title";

nexrender.selectLayersByName("main_single_products->single_product", "var_product_name_1", function (layer) {
    layer.property("Source Text").setValue(title);
    nexrender.log("Set " + layer.name + " to: " + layer.property("Source Text").value.text);
});
```

```text Render log theme={null}
NX: Set var_product_name_1 to: Hello from a script
```

For a plain text change, a [`text` asset](https://www.nexrender.com/docs/cloud/jobs/rendering_basics#supported-asset-types) does the same without a script. Use a script when the text depends on logic, such as formatting or picking from a list.

## Hide a layer based on a parameter

```json Script asset theme={null}
{
  "type": "script",
  "src": "https://example.com/scripts/hide-layer.jsx",
  "parameters": [
    { "key": "hideOldPrice", "value": true }
  ]
}
```

```javascript hide-layer.jsx theme={null}
if (NX.get("hideOldPrice") === true) {
    nexrender.selectLayersByName("main_single_products->single_product", "var_price_was_1", function (layer) {
        layer.enabled = false;
    });
    nexrender.log("Old price hidden");
}
```

## Read data from a JSON file

Download the file with a `static` asset, then read it from the job's folder. Set `name` so the file gets a name you know: Nexrender keeps it as is.

```json Assets theme={null}
[
  {
    "type": "static",
    "src": "https://example.com/data/products.json",
    "name": "products.json"
  },
  {
    "type": "script",
    "src": "https://example.com/scripts/read-json.jsx"
  }
]
```

```json products.json theme={null}
[
  { "name": "CyberPulse Keyboard", "price": "380 EUR" },
  { "name": "Nova Mouse", "price": "79 EUR" }
]
```

```javascript read-json.jsx theme={null}
var file = new File(NX.get("nxWorkpath") + "/products.json");

if (!file.exists) {
    throw new Error("nexrender: products.json was not downloaded");
}

file.encoding = "UTF-8";
file.open("r");
var products = JSON.parse(file.read());
file.close();

nexrender.selectLayersByName("main_single_products->single_product", "var_price_now_1", function (layer) {
    layer.property("Source Text").setValue(products[0].price);
});

nexrender.log("Loaded " + products.length + " products, first price: " + products[0].price);
```

```text Render log theme={null}
NX: Loaded 2 products, first price: 380 EUR
```

The order of `static` assets doesn't matter: every download finishes before any script runs.

> [!NOTE]
>
> With an inline `data:` URL instead of an `https://` one, Nexrender adds an extension based on the media type. Set `name` without the extension, such as `"name": "products"` for `data:application/json;base64,...`, to get `products.json`.

## Write a file in the job folder

Scripts can create files in the job's folder: reports, generated data, or files to import into the project.

```json Script asset theme={null}
{
  "type": "script",
  "src": "https://example.com/scripts/write-file.jsx"
}
```

```javascript write-file.jsx theme={null}
var file = new File(NX.get("nxWorkpath") + "/report.txt");
file.encoding = "UTF-8";

file.open("w");
file.writeln("Composition: " + nexrender.renderCompositionName);
file.writeln("Title: " + (NX.get("title") || "none"));
file.close();

file.open("r");
nexrender.log("report.txt contains: " + file.read().replace(/\n/g, " | "));
file.close();
```

```text Render log theme={null}
NX: report.txt contains: Composition: main_single_products | Title: none |
```

The job's folder is deleted after the render. To keep what a file says, write it to the render log with `nexrender.log`.

## Replace footage with a downloaded image

```json Assets theme={null}
[
  {
    "type": "static",
    "src": "https://example.com/images/photo.png",
    "name": "photo.png"
  },
  {
    "type": "script",
    "src": "https://example.com/scripts/replace-footage.jsx"
  }
]
```

```javascript replace-footage.jsx theme={null}
nexrender.selectLayersByName("main_single_products->single_product", "var_product_photo_1", function (layer) {
    nexrender.replaceFootage(layer, NX.get("nxWorkpath") + "/photo.png");
    nexrender.log("Photo replaced with " + layer.source.name);
});
```

```text Render log theme={null}
NX: Photo replaced with photo.png
```

An [`image` asset](https://www.nexrender.com/docs/cloud/jobs/rendering_basics#supported-asset-types) replaces footage without a script. `replaceFootage` is for cases with logic, such as picking one of several downloaded images.

## List the layers of a type

```json Script asset theme={null}
{
  "type": "script",
  "src": "https://example.com/scripts/list-text-layers.jsx"
}
```

```javascript list-text-layers.jsx theme={null}
var names = [];

nexrender.selectLayersByType("main_single_products->single_product", TextLayer, function (layer) {
    names.push(layer.name);
});

nexrender.log("Text layers: " + names.join(", "));
```

## Format values with a function parameter

```json Script asset theme={null}
{
  "type": "script",
  "src": "https://example.com/scripts/format-price.jsx",
  "keyword": "params",
  "parameters": [
    {
      "key": "formatPrice",
      "type": "function",
      "value": "function (amount) { return amount.toFixed(2) + ' EUR'; }"
    }
  ]
}
```

```javascript format-price.jsx theme={null}
var label = params.get("formatPrice", [380]);
nexrender.log("Formatted price: " + label);
```

```text Render log theme={null}
NX: Formatted price: 380.00 EUR
```

This example also renames the parameters object from `NX` to `params` with `keyword`.

## Change a property or add an expression

```json Script asset theme={null}
{
  "type": "script",
  "src": "https://example.com/scripts/cta-opacity.jsx"
}
```

```javascript cta-opacity.jsx theme={null}
nexrender.selectLayersByName("main_single_products->single_product", "var_cta_text", function (layer) {
    nexrender.changeValueForKeypath(layer, ["Transform", "Opacity"], { value: 50 });
    nexrender.log("CTA opacity is now " + layer.property("Transform").property("Opacity").value);
});
```

```text Render log theme={null}
NX: CTA opacity is now 50
```

## Load shared code from another file

`#include` doesn't work in Nexrender scripts. To share code, download it with a `static` asset and load it with `$.evalFile`. Have the file return what it defines: in the sandbox, functions a loaded file declares aren't visible to the script that loads it.

```json Assets theme={null}
[
  {
    "type": "static",
    "src": "https://example.com/scripts/helpers.jsx",
    "name": "helpers.jsx"
  },
  {
    "type": "script",
    "src": "https://example.com/scripts/use-helpers.jsx"
  }
]
```

```javascript helpers.jsx theme={null}
(function () {
    return {
        greet: function (name) {
            return "Hello, " + name + " (from helpers.jsx)";
        }
    };
})();
```

```javascript use-helpers.jsx theme={null}
var helpers = $.evalFile(NX.get("nxWorkpath") + "/helpers.jsx");
nexrender.log(helpers.greet("docs"));
```

```text Render log theme={null}
NX: Hello, docs (from helpers.jsx)
```

## Stop the job with a clear error

Throw an error to stop the job before it renders. Start the message with `nexrender:`: Nexrender then uses it as the job's error word for word. Without the prefix, the job's error is After Effects' longer error output instead.

```json Script asset theme={null}
{
  "type": "script",
  "src": "https://example.com/scripts/require-title.jsx"
}
```

```javascript require-title.jsx theme={null}
var title = NX.get("title");

if (!title) {
    throw new Error("nexrender: the title parameter is required");
}
```

The job fails with your message as its error:

```text Job error theme={null}
Error: nexrender: the title parameter is required
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.