Opens in a new tab

Using ExtendScript With Templater Events and Job Details

Published October 28, 2026

You can write your own ExtendScript, register it to a Templater event, and have it run at exactly the moment you choose, with access to the job Templater is working on. That is how you fix a data problem, adjust a composition, or log a note without touching the template or the spreadsheet.

You may never need this. Templater does a great deal before any script of yours is involved. But some batches have a job where the data is almost right, the layout is almost right, and the last bit of correction belongs in code. This article covers how event scripts are wired up, what the $D object gives you, two worked examples straight from our documentation, and the timing mistakes that cause trouble. We also say when a script is the wrong answer.

How event scripts work, and where to register them

Templater broadcasts events as it works. It announces that it is about to retrieve data, that it has finished a job, that it is about to render. An event script is an ExtendScript file you register to one of those announcements. When Templater broadcasts the event, your file runs.

Inside the file you get methods that reach Templater’s internal memory. Through them your code can see the batch of jobs, the data for one specific job, and the layers in the project. Dataclay also keeps sample ExtendScripts in its code repository on GitHub, and those are a good place to start before you write anything from scratch.

In our view, this design is useful because it keeps your logic out of the template. A template full of expressions that try to repair bad input can become hard to read and hard to hand to a colleague. A short script registered to the right event does one job and can be switched off by clearing a checkbox. If you have ever opened an old project and found a layer expression nobody could explain, you know why that matters. We wrote about that problem in when an After Effects expression is too fragile to maintain.

Registering in the Preferences dialog

Open the Templater Preferences dialog. In the Bot Settings group, click Setup ExtendScripts. You will see a list of Templater event groups. Pick a group to show the events inside it.

For each event you want to use, tick the checkbox for Before or After. Then enter the absolute path to your script in the text field underneath. If you would rather not type the path, click Choose script, find the file, and click OK. Repeat for any other event. When you are done, click OK to register everything.

Two details are worth knowing. A cleared checkbox disables the script. And the Footage Processing and Footage Download event groups only exist in Templater 3.4 or later. Earlier versions show a Footage Retrieval group instead, so the dialog on an older install will look different from the one described here.

Registering in the command line options file

If you run Templater from the command line, you register scripts in the templater-options.json file. Inside the “bot” object, you set the property for the event to the absolute path of the script file. The event keys come in before and after pairs:

  • pre_jsx_data and post_jsx_data run before and after Templater retrieves data.
  • pre_jsx_batch and post_jsx_batch run before and after Templater’s main iteration loop.
  • pre_jsx_job and post_jsx_job run before and after a single job is processed.
  • pre_jsx_udpate (spelled this way in the support table) and post_jsx_update run before and after Templater updates any layers.
  • pre_jsx_output and post_jsx_output run before and after any output is rendered.
  • enable_jsx runs when the Bot is enabled, and shutdown_jsx runs when it is disabled.

One caution. The table in our documentation spells the before-update key as pre_jsx_udpate, with the letters swapped. Copy the key from the support page itself and confirm that your script fires, for example by logging a message from it.

Choosing the right moment

The names of the events tell you the scope. A job event fires once per row. A batch event fires once for the whole run. A data event fires around the retrieval of the data itself. So the first question for any script is how often it should run. A script that writes a single summary line to a log belongs on a batch event. A script that changes something for each video belongs on a job, update, or output event.

The second question is what the script needs to see. A script that edits a text value has to run before Templater injects that value into the layer, which means a Before Update event. A script that changes the composition after the layers have their new content has to run after the update. The two examples below show both cases.

What the $D object gives you

Every ExtendScript you register talks to Templater through one object, $D. Think of it as a window into the run in progress. Our API reference lists every method. These are the ones you will reach for most.

Reading and changing jobs

$D.job is the current job. Call $D.job.get with no argument and you get one object for the job being processed. When your data source is a spreadsheet, the property names in that object are the column headers. Call it with a key, such as “price”, and you get the value of that property for the current job. $D.job.set takes a key and a value, and it needs both. Pass nothing and it returns null. Pass both and the property on the current job changes.

$D.batch is the whole set of jobs. $D.batch.get with no argument returns an array of job objects, one per job Templater will process. With a key, it returns an array holding that property’s value from every job. $D.batch.set takes a function and runs it over each job object, using forEach behind the scenes. You can pass a second argument to control what “this” means inside your function. Our reference gives an example that cuts any “title” value longer than ten characters and adds three periods. One call and every job in the batch is fixed.

You can also reach the files behind these objects. $D.batch.file and $D.job.file each return an ExtendScript File object for the file that holds the batch details or the details of the job being processed.

$D.range tells you the start and end positions Templater pulled from the data source for the current batch. Be careful with it on a Bot. The documentation says that when the Bot is enabled, the start and end values may not represent the range actually processed.

Reading the composition and the layers

$D.target returns the After Effects composition Templater is working on. You can use any property the After Effects scripting guide describes for a composition, such as its frame rate. If no target has been set, the method returns false, so a careful script checks the return value before it uses it.

$D.harvest returns layers grouped by type. Its text, footage, solid, comp, and adj properties are arrays of the layers of each type that have the Templater Settings effect applied.

$D.update has two methods that start Templater’s own intelligence. $D.update.layout runs the algorithm for automatic spatial layout of dynamic layers across all compositions. $D.update.timeline runs the algorithm for automatic temporal arrangement. Our reference says scripts that use these are likely to be registered to Before Update or After Update, which makes sense, since both only mean something around the point where layers are being updated.

Knowing where you are

Three methods tell a script about its own situation. $D.task returns one of three constants, PREVIEW, RENDER, or REPLICATE, so you can behave differently depending on how Templater was invoked. $D.event returns the last broadcast event as a string, such as bot_pre_job, bot_post_rndr, or bot_on_enable. $D.bot_id returns the name of the Bot that ran the script. That is the same value as the Bot Name field in Preferences and the “name” property inside the “bot” object of templater-options.json.

$D.output describes the output Templater devised for the current job. Its properties are name, the output name for that job, loc, the folder holding the file, file, the full path to the file, template, the name of the render settings template, and module, the name of the output module. A script registered after output can use these to know exactly what was just made.

For footage that Templater downloads from a remote source, Templater 3.4 or later adds $D.download, plus $D.footage.layer, $D.footage.source, and $D.footage.item. The download record holds the remote address, the name Templater gave the file, and the folder it was saved to. After the download finishes it also holds the MIME type, the extension, and the full path of the file.

Logging from a script

A script that fails silently is hard to trust, so use the log. $D.log.msg writes a message to templater.log. You pass a label, a message, and optionally a data object to inspect. $D.log.err writes to templater.err, and it takes an integer code, a short description, a message about this specific error, and details that explain how to fix it or why it happened. $D.log.location returns the folder that holds the log and $D.log.file returns the log file itself.

Write the error details for the person who will read them in three months. The details field exists to hold a suggestion, so use it.

Two worked examples, step by step

Both examples come from our support documentation. We walk through them here and add the reasoning, because the reasoning is what lets you adapt them.

Example one: a different work area for every job

Suppose every video in your batch should play a different stretch of the target composition. One version uses frames 0 through 120. Another uses frames 60 through 300. Doing this by hand means reopening the project for every row. With a script, you describe the range in the data and let Templater apply it.

Start in your data source. Add two columns or properties and name them workarea-start and workarea-end. For each job, enter the frame number where the work area should begin and the frame number where it should end.

Next, create a new ExtendScript file and save it as adjust-target-workarea.jsx. Put this code in it:

var targetComp = $D.target(),
    comp_fps = targetComp.frameRate,
    f_start = parseInt($D.job.get("workarea-start")),
    f_end = parseInt($D.job.get("workarea-end"))
targetComp.workAreaStart = (f_start / comp_fps)
targetComp.workAreaDuration = (f_end / comp_fps) - targetComp.workAreaStart

We have left the line-ending semicolons out of these listings, so add them back if you copy the code. Here is what each part does and why. $D.target gets the composition Templater is targeting. Its frameRate is needed because the data holds frame numbers and the script converts them to seconds. $D.job.get reads the two columns for the current job, and parseInt turns the text from the spreadsheet into whole numbers. Then the script divides each frame number by the frame rate to get seconds. The work area start is set directly. The work area duration is the end time minus the start time.

Our documentation registers the file with the After Update event. As we read it, the reason is timing, since by then Templater has finished updating the layers for this job. Run a batch with rows that have different workarea-start and workarea-end values, and each output has its own work area.

Notice what this example does not need. It does not touch the spreadsheet formulas, it does not add expressions to the template, and it does not need a different composition for each version. One short file and two extra columns do the whole job.

Example two: trimming long text before it lands in a layer

The second example fixes a common problem. A headline comes in at sixty characters and your layout was designed for ten. You want to cut it short and add an ellipsis before it goes into the text layer.

Add a column or property named headline to your data source. Map those values to a text layer in your composition using the Templater Settings effect. Fill the column with strings. The documentation points out that you should include some longer than ten characters, because shorter strings are not truncated and you will not see the script do anything.

Create a file named truncate-long-string.jsx with this code:

function truncate(word){
  var truncated_word
  var max_characters = 10
  truncated_word = (word.length > max_characters) ? word.slice(0, max_characters) + '...' : word
  return truncated_word
}
$D.job.set("headline", truncate($D.job.get("headline")))

The function checks the length of the string. If it is over the limit, it keeps the first ten characters and adds three periods. If not, it returns the string untouched. The last line reads the headline for the current job, passes it through the function, and writes the result back with $D.job.set.

Register this one with the Before Update event. As we read it, the reason is the opposite of the first example. The text has to be fixed before Templater pushes it into the layer, so the script must run before the update. If you registered it after, the long headline would already be in the layer and your change would arrive too late to matter.

The lesson across both examples is the same. Pick the event by asking whether the script changes what goes into the composition or changes the composition itself. Data fixes go before the update. Composition changes go after.

If you want to apply a rule to every job at once, the batch method is an alternative. Our API reference shows the same truncation written for $D.batch.set, so that every “title” value in every job is shortened in one pass. Which approach to choose depends on where the script runs. A job event handles one row at a time. A batch-level script sees all of them together, which is better when the rule depends on the whole list.

Where this goes wrong, and when to skip it

The most important warning in our documentation is short. Some $D methods may return unexpected values or errors depending on which event your script is registered to. The example the reference gives is the Bot Enabled event. As we read it, no job is being processed at that moment, so a call like $D.job.get has little to return. The reference also says that After Effects can hang after you register a script that misbehaves, and it points to the Troubleshooting Event Scripts page for help.

So match the method to the event. Job data belongs with events that fire during a job. Batch data belongs with batch events. A script that only logs makes a good first script when you are learning. Register a script that only calls $D.log.msg and $D.event, run a batch, and read templater.log. You will see exactly which events fire and in what order, and that picture is worth more than any description.

Previews run your scripts too

By default Templater runs registered event scripts every time you do a Preview. That surprises people. If your script writes to a file, calls a service, or edits something you do not want edited during design work, a preview will trigger it. The Preferences dialog has a checkbox, Prevent event script execution on Preview, for this reason. If you want a script to fire only on a real render, tick it, or check $D.task inside the script and return early when it reports PREVIEW.

Shell scripts are a different tool

ExtendScript is not the only thing you can attach to events. Templater also lets you register shell scripts, through the Setup Shell Commands button. A shell script suits work outside After Effects, such as moving a file, calling a command line program, or notifying another system. By default, Templater runs shell commands synchronously, so After Effects waits until the script finishes. If the work must run on its own, tick Asynchronous and it executes as a detached process.

There is one timing point to remember when you render through Adobe Media Encoder. Shell scripts run after the target composition is versioned in After Effects. They do not wait for Adobe Media Encoder to finish rendering. A shell script that expects a finished video file may find nothing there. Our documentation states this as a warning, and it is easy to miss.

The simple rule is that ExtendScript is for things that need to touch the After Effects project or Templater’s job data, and a shell script is for everything else.

When not to write a script

Do not reach for ExtendScript if the problem is bad data. A script that patches around a missing value is a script you will maintain forever, and the next missing value will not match the patch. Fix the source, or validate the rows before they reach the batch. We cover that approach in how to handle dirty or incomplete data without producing broken output videos.

Do not use a script if Templater already does the job. Layout and timing have their own built-in algorithms, and the $D.update methods call them. Reach for your own code only for the part Templater does not do.

And be honest about who will maintain it. ExtendScript is code, and code needs an owner. If nobody on your team writes it, think about whether a script is the right thing to depend on. We compare the options in building custom After Effects scripts in-house versus using Templater.

Finally, remember that scripts run inside a batch, and a batch can stop partway. A script that throws an error on row 40 of 400 is a mid-queue failure. Read what happens when a Templater batch fails mid-queue before you put a script into an unattended run, and log liberally so you can see where it stopped.

A sensible way to start

Begin with the smallest script that proves the wiring. Register a file to a single job event, have it call $D.log.msg with the output of $D.event, and run a short batch of three rows. Read the log. Then change the script to read one value with $D.job.get and log that. Then change one value with $D.job.set and watch it arrive in the video. Each step adds one idea, so when something breaks you know which idea caused it.

Once the pattern is clear, the two examples above are close to templates. A work area driven by two columns, and a text rule applied before injection, are two patterns you can adapt. The full list of methods lives in the Templater ExtendScript API reference, and our complete guide to Templater places event scripts in the larger picture of how a project is rigged, fed, and rendered.

The bottom line is this. Event scripts are the right tool when a small correction belongs at a specific moment in a run, and the $D object makes that correction simple to write. Choose the event by asking whether you are changing the input or the composition, check the return values your method gives at that moment, log what you do, and switch scripts off with a checkbox rather than deleting them. If the real problem is the data or the template, fix that first and leave the script out.

We hope that helps you decide. Here are the questions we hear most about event scripts.

Frequently Asked Questions

Where do I register an ExtendScript for a Templater event?

Open the Templater Preferences dialog. In the Bot Settings group, click Setup ExtendScripts, choose an event group, and tick Before or After for the event you want. Type the absolute path to your script or click Choose script to browse. If you run from the command line, set the matching event property inside the “bot” object of templater-options.json to the absolute path instead.

How do I turn a registered ExtendScript off without deleting it?

Clear its Before or After checkbox in the Setup ExtendScripts dialog. A cleared checkbox disables the script. This is the safest way to test whether a script is the cause of a problem, because you change one thing and nothing else.

Which event should I use to change a text value before it appears in the video?

Use Before Update. Templater has not yet put the job’s values into the layers at that point, so a change you make with $D.job.set arrives in the video. Our truncation example registers to Before Update for exactly this reason. If you registered the same script to After Update, the text would already be in the layer and your change would come too late.

How do I give each job a different work area?

Add workarea-start and workarea-end columns to your data source with frame numbers for each job. Write a script that reads them with $D.job.get, divides by the target composition’s frame rate, and sets the work area start and duration. Register it to After Update. Each output then has the work area its row describes.

Why did my script return unexpected values or hang After Effects?

Some $D methods behave differently depending on the event your script is registered to. On the Bot Enabled event, for example, we would not expect a job method to return anything meaningful. Match the method to the event, and see the Troubleshooting Event Scripts page in the Templater help for more. A script that only logs is a gentle way to learn which events fire when.

Do event scripts run when I click Preview?

Yes, by default. Templater runs registered event scripts each time you perform a Preview. If a script writes files or contacts another system, that may not be what you want during design work. Tick Prevent event script execution on Preview in Preferences, or check $D.task inside the script and stop early when it returns PREVIEW.

Should I use an ExtendScript or a shell script?

Use ExtendScript when the code needs to read or change Templater’s job data or the After Effects project. Use a shell script for work outside After Effects, such as moving files or calling a command line tool. Shell scripts run synchronously by default and have an Asynchronous option. When rendering through Adobe Media Encoder, they run after the composition is versioned, not after the encode finishes.

Leave the first comment

Sign up

Stay up to date with Datclay's newsletter. We won't spam your inbox.

Newsletter Signup
Name
Name
First
Last

By submitting your email, you agree to our Terms and Privacy Policy. You can opt out at any time.