Opens in a new tab

Using Shell Scripts With Templater Events

Published October 28, 2026

You register a shell script with Templater by choosing the event you want, either Before or After, and giving Templater the path to your script or the full command to run. You can do it in the Templater Preferences dialog or in the templater-options.json file. Then you decide which arguments Templater hands the script, because since version 2.7 it hands over nothing unless you ask.

The registration itself is short. The arguments are what make a script useful, and they are the part to get right. This article walks through both registration routes, the argument macros, how a script reads what it receives in four languages, and the macOS and Media Encoder traps our documentation warns about.

Registering a script, two ways

A shell script is a file or a command that Templater runs when it broadcasts an event. The script can be any command you could run from a terminal. Our help pages show typical uses such as moving files, sending notifications, updating databases, transcoding output and sending email. Before you register anything, know that Dataclay keeps sample shell scripts in its code repository on GitHub. Start from one of those if you can.

In the Preferences dialog

Open the Templater preferences. In the Bot Settings group, click Setup Shell Commands. Choose a Templater event group, and the dialog shows the events in that group. Each event has a checkbox for Before and a checkbox for After. Tick the one you want. If you clear the checkbox, the script is disabled, and a script that you typed directly into the dialog cannot be edited while it is disabled. So re-enable it first if you need to change the text.

In the text box under the checkbox, you enter one of two things. If the script is directly executable by the operating system, such as a Bash script on macOS or a Batch script on Windows, you enter the absolute path to it. You can click Choose script and browse to the file if you would rather not type a path. If the script needs an interpreter, such as NodeJS, Python or PHP, you enter the full command syntax. For a NodeJS script, that looks like node followed by the path to the .js file. Our documentation adds a practical tip. You may need to give the full path to the interpreter itself if the code does not run correctly.

Note the version detail. The Footage Processing and Footage Download event groups exist in Templater 3.4 or later. Earlier versions have a Footage Retrieval group in their place, and the dialog looks different before 3.4.0.

When you finish, click OK to register. Repeat the steps for each event you want to hook.

In templater-options.json

If you drive Templater from the command line, you register scripts in the templater-options.json file instead. Inside the bot object, you set the property for the event to the absolute path of the file you want to run. You can also put in any command as you would type it in a terminal. Our documentation says that is not recommended for complex scripts, and it is right. In our view, a long command inside a JSON string is hard to read.

The property names match the events. Before and after data are pre_cmd_data and post_cmd_data. Before and after batch are pre_cmd_batch and post_cmd_batch. Before and after job are pre_cmd_job and post_cmd_job. Before and after output are pre_cmd_output and post_cmd_output. There are also enable_cmd for when the Bot is enabled and shutdown_cmd for when it is disabled. The update pair deserves a careful look. The help page prints the before-update property as pre_cmd_udpate and the after-update property as post_cmd_update. Copy the names exactly as that table prints them, and confirm in your log that the script fired, rather than assuming the spelling.

On Windows, one JSON detail causes a lot of trouble. In templater-options.json, the backslash and other special characters must be escaped with an additional backslash. A path like C:\Users\dev\event-scripts\setup-folder.bat has to be written with doubled backslashes inside the JSON string. A single backslash gives you a broken path and a script that never starts.

Synchronous or asynchronous

By default, Templater runs a registered script synchronously. After Effects waits until the script finishes. That is the right default for a script whose result the next step needs, such as one that prepares a folder. If the script can run on its own, you can detach it. In the Preferences dialog, tick the Asynchronous checkbox. In the options file, set the matching async property to true, which is the event’s property name with _async on the end, for example post_cmd_job_async. A detached script is a good fit for a slow upload, since the next job does not have to sit and wait for it.

Passing information with argument macros

An argument macro is a word with a dollar sign in front of it. When Templater broadcasts an event, it replaces the macro with real text. You write the macro after the script path, separated by spaces, and the script receives the replaced value.

There are three ways to feed a script. You can pass explicit values, such as the integer 512 and the string 08-24-2018, by typing them after the path. You can pass pre-existing information, which Templater calls predefined macros, by choosing from the Append drop-down in the dialog or typing the macro in the options file. And you can pass values from your own data by putting a dollar sign in front of a column name or property key.

Take the second kind first. Our documentation’s example registers a NodeJS script called update-job.js with three macros: $aep, the path to the After Effects project file being processed, $data_uri, the full URL or absolute path to the connected data source, and $now, a timestamp from the host machine’s clock. The command reads node, then the path to update-job.js, then $aep $data_uri $now. In the options file the same line sits inside the bot object, under the event’s property name.

Now the third kind. If your spreadsheet has columns named album-name and release-date, you register setup-folder.bat followed by $album-name $release-date. Each row that Templater processes passes its own two values to the script. A folder-creating script can then make one folder per row, named from the data.

When the data is available

There is one timing rule to know. You can only use arguments to pass job-specific data after that data has been read from your data source. In other words, only after the After Data event has been broadcast. Some macros are not available to scripts registered on certain events, and using them can make Templater log an error. The documentation’s own example is $id. If you pass $id to a script registered on Before Data, Templater logs an error.

So match the macro to the event. Job-specific data, such as the job id, is only available after the data has been read, and the documentation says some macros cannot be used on some events.

A worked example

Say you have a post-processing step that compresses each finished video and you want the compression tool to know which video it is working on. The documentation’s pattern is to register C:\compress.bat on the After Job event. With versioning data that contains a title, you register the command as C:\dev\compress.bat $title, and the script receives Create Targeted Video Ads, or whatever the title is for the job being processed. If the script also needs more, you add macros: $title $caption-1 $caption-2 $tint passes four values from the same row.

Predefined macros cover the facts about the job itself. To give a script the job id, the path of the rendered file and the path of the processed project, the command becomes C:\dev\compress.bat $id $out_file $aep. In the same documentation, a NodeJS script called concatenate.js is registered to After Batch with $aep $out_dir $id $title, run through the node interpreter. You can register any command-line line you could type into a terminal.

The predefined macros

As of Templater 2.7, the predefined set covers paths, data, the job and the machine. For paths, $log is the path to the templater.log file and $log_dir is the folder it sits in. $aep is the processed template file and $aep_dir is its folder. $sources is the footage source directory, and $out_dir is the output directory. For data, $data_uri is the path or URL of the versioning data, $data_start and $data_end are the start and end index used in data retrieval, $data_batch is the path to a JSON file with the versioning data for the batch, and $data_job is the same for the job. For spot checks, $spot.label gives the still image export named by its label and $spot[n] gives it by ordinal position. For the job, $id is the value of the id column or property, $idx is the job’s ordinal position in the batch, $out_name is the output’s name, and $out_file is the path to the output file. For the machine, $bot_name, $machine_name and $user_name give the Bot, the host and the user running After Effects. $now is the current time on the machine’s clock, and $event is the string identifier of the most recently broadcast event.

That last macro is quietly useful. If you register one script on several events, passing $event lets the script know which one fired and branch accordingly.

Footage events, reading arguments, and the traps

Templater 3.4 added two event groups for footage, and they bring their own macros. Footage Download fires for every download of a remote footage reference, including remote references that Templater has cached locally. Its macros begin with $dl. Footage Processing fires for all footage assets in your composition, local and remote. Its macros begin with $ftg.

The download macros split by timing. Before the download, you have $dl_file_uri, the path or URL where the footage lives, $dl_file_name, the name Templater assigns to the downloaded file without its extension, and $dl_file_dir, the folder the footage will be saved to. After the download, you have $dl_file_mime, the MIME type, $dl_file_ext, the extension Templater assigned, and $dl_file, the complete path including the file name and extension. The processing macros are available before footage processing. $ftg_layer is the name of the layer the footage will be injected into, $ftg_name is the footage file’s name, and $ftg_file, $ftg_dir and $ftg_ext give the path, the location and the extension. If the footage is itself an After Effects composition, the last three show as undefined.

Count the calls before you write the script

Our documentation includes a small example that is worth working through, because it shows how fast scripts multiply. Dorian is working on a comp with ten footage assets. Five are downloaded from a remote source, and he has configured Templater for unique downloads. Three are on his local machine, and two are other compositions in After Effects.

For every version of his comp, the Footage Download event fires 5 times, once for each remote asset. The Footage Processing event fires 10 times, once for each asset of any kind. If Dorian writes scripts to run both before and after Footage Download, those scripts are called 10 times per version. If he writes scripts for both before and after Footage Processing, they run 20 times per version. Now multiply by the number of rows in the batch. A script that looks cheap on its own becomes a real cost when it runs twenty times for every row of a large batch. That is one argument for the asynchronous setting, and for hooking Before Job or After Job when one call per video is enough. Our pieces on managing linked footage across machines and smart URL processing for remote footage cover the footage side.

How a script reads its arguments

Whatever language you write in, the rule is the same. A script reads each argument by its ordinal position, so the first argument you appended is the first one it receives. The syntax differs by language.

In Bash on macOS, suppose you registered /Users/me/Dev/upload.sh followed by $aep $data_uri $now $out_file. Inside the script, the first positional variable holds the project file, the second the data source, the third the timestamp and the fourth the output file. If you have more than nine arguments, you write the number in braces, as in ${10}, ${11} and ${12}.

In a Windows Batch script, the same four arguments arrive as %1, %2, %3 and %4. Past nine, the job gets more involved, and our documentation points you to the standard guidance on passing arguments to Batch scripts. It also says that using Batch scripts for complex scripting tasks is not recommended. If your script is more than a few lines, write it in something else.

In NodeJS, the arguments live in the process.argv array. The array holds the word node in position zero and the script name in position one, so your first appended argument comes after those two. Our documentation recommends the minimist package for reading arguments in your own scripts, and that is good advice. It saves you from counting positions at all. In PHP, the arguments are in the $argv array, and $argv[1] is the first one.

Three traps to know before you ship

The first is the 2.7 change. The preference called “For all commands, use job details as arguments” is deprecated as of Templater 2.7. If your application depended on it, your registered event scripts fail. You must append arguments explicitly, and in templater-options.json you can no longer use the “job_detail_args” property inside the “bot” object within “prefs”. After an upgrade, this is the first thing to check.

The second is macOS. Since Mojave 10.14, macOS security changes can stop event shell scripts from running through Terminal, and you may see an “Operation not permitted” message. The documented step to try is to give Terminal Full Disk Access. Open System Preferences, choose the Security and Privacy panel, select the Privacy tab, choose Full Disk Access from the list, click the lock and sign in with an administrator login, click the plus button, and add Terminal from the Applications Utilities folder. If you see that message when running an event script, this is the step our documentation suggests.

The third is Adobe Media Encoder. If Templater sends your compositions to Media Encoder for rendering, shell scripts run after the target composition is versioned in After Effects. They do not wait for Media Encoder to finish rendering. A script that expects a finished video file on After Output may therefore find nothing there. If you need the finished file, plan for that gap.

If it still will not run

Open templater.log and look for EVENT SCRIPT ERROR or EXEC SHELL SCRIPT. Copy the line that starts with Full command line and paste it into a terminal to see whether it works outside Templater. Check that the script is executable by the user running After Effects. Our piece on batch failures mid-queue covers what to expect when a batch stops, and the article on webhook callbacks shows one way to tell another system a render is finished. For a destination such as a content system, see getting automated video output into a CMS or DAM. The Templater page shows how event scripts fit with the rest of the product, and the Templater help pages on using shell scripts have the full reference.

The bottom line

Register the script on the event that matches the work: a job event for per-video tasks, a batch event for whole-batch tasks. Pass every value it needs as an explicit argument, and match each macro to an event where it exists. Use the Asynchronous setting for slow tasks, count how many times a footage event will fire before you hook it, and write anything longer than a few lines in a language that handles arguments well. If you are not moving files or telling other systems about your output, you probably do not need a shell script at all. If you are, this is how you make Templater part of the rest of your pipeline.

These are the questions we hear most often about getting a first script to run.

Frequently Asked Questions

Here are the answers to the things people trip over most.

Where do I register a shell script in Templater?

You have two options. In the Templater Preferences dialog, go to the Bot Settings group and click Setup Shell Commands, then pick an event group and tick Before or After for the event you want. If you use the command line interface, set the event’s property in the bot object of the templater-options.json file instead. Both routes take either an absolute path to a script or a full command.

How do I pass a column from my spreadsheet to a script?

Put a dollar sign in front of the column name or property key and append that macro to the script path or command. For example, if your data has columns named album-name and release-date, you register your script followed by $album-name $release-date. Each job passes its own values. The data is only available once the After Data event has been broadcast, so register the script on a later event.

Why is my script not getting the arguments I expected?

Since Templater 2.7, the preference “For all commands, use job details as arguments” is deprecated, and Templater passes no arguments unless you append them yourself. Check that the macros are written after the script path, separated by spaces, and that the macro exists for the event you chose. Passing $id to a script registered on Before Data, for example, makes Templater log an error.

Should my script run synchronously or asynchronously?

By default Templater runs scripts synchronously, so After Effects waits until the script finishes. Keep that when the next step needs the script’s result. Tick the Asynchronous checkbox, or set the matching property ending in _async to true in the options file, when the script can run as a detached process, such as a slow upload that nothing downstream depends on.

Why do I get an “Operation not permitted” error on macOS?

Security changes in macOS Mojave 10.14 and later can stop event shell scripts from running through Terminal. The documented step to try is to grant Terminal Full Disk Access. In System Preferences, open Security and Privacy, choose the Privacy tab, select Full Disk Access, authenticate with an administrator login, click the plus button and add Terminal from the Applications Utilities folder.

When does my script run if I render through Adobe Media Encoder?

Shell scripts run after the target composition is versioned in After Effects. They do not run after Media Encoder finishes rendering. If your script needs the finished video, a script on an output event may start before the file exists. Plan for that gap, for example by checking for the file inside the script before it does its work.

How many times will a footage event run my script?

The count depends on your assets. In our documentation’s example, a comp has ten footage assets, five of them remote. For each version, the Footage Download event fires five times and the Footage Processing event fires ten times. Scripts registered both before and after those events run ten and twenty times per version. Multiply by the rows in your batch before you decide where to hook.

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.