> ## 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.

# Helper functions

> Reference for the nexrender object available to every script: find compositions and layers, replace footage, change properties, and write to the render log

Every script that runs in a job can use the `nexrender` object. Its helpers cover the things most scripts start with: finding compositions and layers by name, replacing footage, and logging.

The helpers only exist while Nexrender runs your script. To run the same file in After Effects by hand, see [Run the same script in After Effects](https://www.nexrender.com/docs/cloud/scripting/script-assets.md#run-the-same-script-in-after-effects).

## Properties

| Property | Value |
| - | - |
| `nexrender.renderCompositionName` | The name of the composition the job renders, from `template.composition`. |
| `nexrender.defaultCompositionName` | `"*"`, the name the layer helpers use when you pass `null` as the composition. It matches every composition. |
| `nexrender.types` | The After Effects classes the helpers work with: `CompItem`, `FolderItem`, `FootageItem`, `AVLayer`, `ShapeLayer`, `TextLayer`, `CameraLayer`, `LightLayer`, `Property`, and `PropertyGroup`. |

## Composition names and paths

Every helper that takes a composition name accepts:

* An exact composition name, such as `"intro"`. Names are case-sensitive.
* `"*"` for every composition in the project. The `selectLayersBy...` helpers also take `null` for this.
* A path of nested compositions joined with `->`, such as `"main->intro"`. It picks the `intro` composition only if `main` uses it. Paths can go deeper: `"main->intro->lower_third"`.

> [!NOTE]
>
> A path picks which composition to work on, not one use of it. If `intro` is also used in another composition, your changes show up there too.

> [!TIP]
>
> Without a composition name, a helper searches every composition. If the same layer name appears in several compositions, the callback runs for each of them.

## nexrender.log

```javascript theme={null}
nexrender.log(message)
```

Writes a line to the job's render log, prefixed with `NX:`. Read the log with `GET /jobs/{id}/logs` or `nexrender job logs JOB_ID`.

```javascript theme={null}
nexrender.log("Rendering " + nexrender.renderCompositionName);
nexrender.log(JSON.stringify({ layers: 12, missing: [] }));
```

```text Render log theme={null}
NX: Rendering main
NX: {"layers":12,"missing":[]}
```

`message` is converted to a string. Use `JSON.stringify` to log arrays and objects.

> [!NOTE]
>
> The render log hides some values: IDs like the job's show as `[render id]`, paths on the render node as `[local path]`, the query string of a URL as `?[parameters]`, and email addresses as `[email]`. Characters outside ASCII, such as `€`, may show as `?`, even though your script handles them correctly.

## nexrender.selectCompositionsByName

```javascript theme={null}
nexrender.selectCompositionsByName(name, callback)
```

Calls `callback(comp)` for every composition that matches `name`.

**name** `string` *required*

A composition name, `"*"`, or a `->` path. See [Composition names and paths](#composition-names-and-paths). It can't be `null`.

**callback** `function` *required*

Called with each matching `CompItem`.

Throws `nexrender: Couldn't find any compositions by provided name (NAME)` when nothing matches.

```javascript theme={null}
nexrender.selectCompositionsByName("*", function (comp) {
    comp.duration = 10;
});
```

## nexrender.selectLayersByName

```javascript theme={null}
nexrender.selectLayersByName(compositionName, layerName, callback, types, continueOnMissing)
```

Calls `callback(layer, layerName)` for every layer named `layerName` in the matching compositions.

**compositionName** `string | null` *required*

A composition name, `"*"`, or a `->` path. `null` searches every composition.

**layerName** `string` *required*

The exact layer name. It's case-sensitive.

**callback** `function` *required*

Called with each matching layer and the name you searched for.

**types** `array`

Accepted for compatibility, but layers of every type match. To act on one kind of layer only, check it in your callback: `if (layer instanceof TextLayer)`. Pass `null` here when you need `continueOnMissing`.

**continueOnMissing** `boolean` (default: false)

Set to `true` to skip the error when no layer matches. A composition that doesn't exist still throws.

Throws `nexrender: Couldn't find any layers by provided name (NAME) inside a composition: COMPOSITION` when no layer matches, unless `continueOnMissing` is `true`.

```javascript theme={null}
nexrender.selectLayersByName("main->single_product", "var_product_name_1", function (layer) {
    if (layer instanceof TextLayer) {
        layer.property("Source Text").setValue("CyberPulse Keyboard");
    }
});
```

## nexrender.selectLayersByType

```javascript theme={null}
nexrender.selectLayersByType(compositionName, type, callback, types, continueOnMissing)
```

Calls `callback(layer)` for every layer of class `type` in the matching compositions.

**compositionName** `string | null` *required*

A composition name, `"*"`, or a `->` path. `null` searches every composition.

**type** `class` *required*

A layer class: `TextLayer`, `ShapeLayer`, `AVLayer`, `CameraLayer`, or `LightLayer`.

**callback** `function` *required*

Called with each matching layer.

**types** `array`

Accepted for compatibility, but not applied. Pass `null` here when you need `continueOnMissing`.

**continueOnMissing** `boolean` (default: false)

Set to `true` to skip the error when no layer matches. A composition that doesn't exist still throws.

Throws `nexrender: Couldn't find any layers by provided type (TYPE) inside a composition: COMPOSITION` when no layer matches, unless `continueOnMissing` is `true`.

```javascript theme={null}
var names = [];
nexrender.selectLayersByType("intro", TextLayer, function (layer) {
    names.push(layer.name);
});
nexrender.log("Text layers in intro: " + names.join(", "));
```

## nexrender.selectLayersByIndex

```javascript theme={null}
nexrender.selectLayersByIndex(compositionName, index, callback, types, continueOnMissing)
```

Calls `callback(layer, index)` with the layer at `index` in each matching composition.

**compositionName** `string | null` *required*

A composition name, `"*"`, or a `->` path. `null` searches every composition.

**index** `number` *required*

The layer's index. It starts at 1, as in After Effects.

**callback** `function` *required*

Called with the layer and its index.

**types** `array`

Not used by this helper. Check `layer instanceof TextLayer` in your callback instead.

**continueOnMissing** `boolean` (default: false)

Set to `true` to skip Nexrender's error when no layer is found. Check the layer count with `comp.numLayers` first: After Effects itself can raise an error for an index past the last layer.

```javascript theme={null}
nexrender.selectLayersByIndex("main", 1, function (layer, index) {
    nexrender.log("Layer " + index + " is " + layer.name);
});
```

## nexrender.replaceFootage

```javascript theme={null}
nexrender.replaceFootage(layer, filePath, sequence, removeOldFootage)
```

Imports a file into the project and makes it the layer's source. Returns `true`, or `false` when `layer` is empty.

**layer** `AVLayer` *required*

A layer with a footage source, such as an image or video layer.

**filePath** `string` *required*

The absolute path of the file to import. Files you download with a [`static`](https://www.nexrender.com/docs/cloud/jobs/rendering_basics#supported-asset-types) asset are in the job folder: `NX.get("nxWorkpath") + "/photo.png"`.

**sequence** `boolean` (default: false)

Set to `true` to import the file as the first frame of an image sequence.

**removeOldFootage** `boolean` (default: false)

Set to `true` to delete the previous footage item from the project. After Effects also deletes every other layer that uses it.

Throws `nexrender: Trying to create a file replacement for an unknown file: PATH` when the file doesn't exist.

```javascript theme={null}
nexrender.selectLayersByName("main->single_product", "var_product_photo_1", function (layer) {
    nexrender.replaceFootage(layer, NX.get("nxWorkpath") + "/photo.png");
});
```

## nexrender.changeValueForKeypath

```javascript theme={null}
nexrender.changeValueForKeypath(layer, keys, change)
```

Sets a value or an expression on a property found by a path of property names. This is how [`data`](https://www.nexrender.com/docs/cloud/jobs/rendering_basics#supported-asset-types) assets change layers.

**layer** `Layer` *required*

The layer to change.

**keys** `array` *required*

Property names from the layer down to the property, such as `["Transform", "Opacity"]` or `["Effects", "Glow", "Glow Radius"]`.

**change** `object` *required*

`{ "value": VALUE }` to set the property's value, or `{ "expression": "EXPRESSION" }` to set its expression.

Throws `nexrender: Can't find a property sequence ...` when a name in `keys` doesn't exist on the layer.

```javascript theme={null}
nexrender.selectLayersByName("main->single_product", "var_cta_text", function (layer) {
    nexrender.changeValueForKeypath(layer, ["Transform", "Opacity"], { value: 50 });
    nexrender.changeValueForKeypath(layer, ["Transform", "Rotation"], { expression: "time * 30" });
});
```

## Other members

`nexrender.typesMatch(types, layer)` and `nexrender.evaluate(layer, expression)` are used inside Nexrender, by the helpers and by `data` assets. Your scripts don't need them.

## Errors

Every helper error starts with `nexrender:`. An error you don't catch stops the script and fails the job with that message, before the render starts. To carry on when a layer is missing, pass `continueOnMissing`. For a missing composition, or anything else, wrap the call in `try`/`catch`:

```javascript theme={null}
try {
    nexrender.selectLayersByName("main", "Optional badge", function (layer) {
        layer.enabled = NX.get("showBadge") === true;
    });
} catch (error) {
    nexrender.log("No badge layer, skipping: " + error.message);
}
```


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