Process Triggers

Process triggers allow CompleteFTP to automatically execute programs or scripts in response to server events such as file uploads, downloads, user logins, and more. This makes it possible to build automated workflows — for example, moving files after upload, sending notifications, or synchronizing data with external systems.

Overview

Process triggers provide:

  • Event-driven automation - Execute actions when files are uploaded, downloaded, moved, or deleted
  • Multiple trigger types - Run external programs, shell scripts, or JSS (JavaScript Server-Side) scripts
  • Flexible filtering - Restrict triggers by file path, user, or site
  • Scheduled execution - Run triggers on a schedule using cron expressions or specific times
  • Macro substitution - Use macros to pass event details (file paths, usernames, etc.) to programs and scripts
  • Concurrency control - Configure maximum concurrent processes and execution timeouts

All trigger operations use the completeftp trigger command group, with global process control settings available via completeftp trigger processcontrol.

Viewing Trigger Information

List Triggers

# List all triggers
completeftp trigger list

# List with specific properties
completeftp trigger list events type enabled

Show Trigger Details

# Show all properties of a trigger
completeftp trigger show MyTrigger

# Show specific properties
completeftp trigger show MyTrigger events type arguments

Creating Triggers

Adding a Trigger

# Basic syntax
completeftp trigger add <name> <events> <type> <process> [args]

# Add a program trigger that runs on file upload
completeftp trigger add "CopyOnUpload" UploadFile Program /usr/bin/cp \
  '"%OSPath%" /var/ftp/archive/'

# Add a trigger for multiple events
completeftp trigger add "LogActivity" UploadFile,DownloadFile,DeleteFile Program \
  /usr/local/bin/log-activity.sh '"%LoginUserName%" "%Event%" "%FilePath%"'

# Add a JSS script trigger
completeftp trigger add "MoveOnUpload" UploadFile JSS \
  'var file = system.getFile(event.virtualPath); file.moveTo("/Incoming");'

Trigger Types

CompleteFTP supports two trigger types on Linux:

Type Description Use Cases
Program Execute an external program or shell script File operations, system commands, custom scripts
JSS Run JavaScript Server-Side code within CompleteFTP File system operations, FTP transfers, database access, HTTP requests

Note: Batch and PowerShell trigger types are available on Windows only. On Linux, use Program triggers with shell scripts for equivalent functionality.

Events

Available Events

Triggers can respond to any combination of the following events:

Event Description Macros Available
UploadFile A file has been uploaded All
DownloadFile A file has been downloaded All
MoveFile A file has been renamed or moved All
DeleteFile A file has been deleted All
CreateFolder A folder has been created by a user All
MoveFolder A folder has been renamed or moved All
DeleteFolder A folder has been deleted by a user All
LogIn A user has logged in All
LogOut A user has logged out All
ChangeDirectory A user has changed directory All
Timer Scheduled time-based trigger Limited (no user/file macros)
StartServer The CompleteFTP service has started Limited
StopServer The CompleteFTP service has stopped Limited
StartSite A site has started Limited
StopSite A site has stopped Limited
AutoBan An IP address has been auto-banned Limited
CertificateExpiring SSL/TLS certificate expiring within 30 days Limited
CertificateExpired SSL/TLS certificate has expired Limited
ClusterSyncFailed Cluster synchronization failed Limited

Note: CertificateExpiring and CertificateExpired events fire at most once every 24 hours.

Success and Error Triggers

By default, triggers fire only when an operation succeeds. This can be changed:

# Trigger on both success and error
completeftp trigger set MyTrigger onSuccess=true onError=true

# Trigger only on error (e.g., to log failed uploads)
completeftp trigger set MyTrigger onSuccess=false onError=true

Specifying Multiple Events

# Trigger on upload and download
completeftp trigger add "TransferLog" UploadFile,DownloadFile Program \
  /usr/local/bin/log-transfer.sh '"%Event%" "%FilePath%" "%LoginUserName%"'

Macros

Macros are placeholders that are replaced with event-specific values at runtime. They are used in Program trigger arguments. For JSS scripts, use the event object instead (see JSS Triggers).

Important: If a macro value could contain spaces, enclose the macro in double quotes (e.g., "%OSPath%").

Available Macros

File Macros

Macro Description
%FilePath% Full path of file in the virtual file system
%FileName% Name of the file
%FolderPath% Path to the folder in the virtual file system
%OSPath% Full path of the file on the local file system
%OSFolder% Path to the folder on the local file system
%OSFileName% File name on the local file system
%FileSize% File size in bytes

Note: The legacy macros %WindowsPath%, %WindowsFolder%, and %WindowsFileName% are also supported as aliases for %OSPath%, %OSFolder%, and %OSFileName% respectively.

User Macros

Macro Description
%LoginUserName% Username of the logged-in user
%LoginEmail% Email address of the logged-in user
%LoginFullName% Full name of the logged-in user
%OwnerUserName% Username of the folder owner
%OwnerEmail% Email address of the folder owner
%OwnerFullName% Full name of the folder owner

System Macros

Macro Description
%ClientIP% IP address of the client
%SiteName% Name of the site
%ServerName% Name of the server
%Protocol% Protocol used (FTP, SFTP, HTTP, etc.)
%Event% Event that triggered the process
%TransferStatus% success or failure
%ProcessRule% Name of this trigger

Date/Time Macros

Macro Description
%Date% Date of the event
%Time% Time of the event
%DateAndTime% Date and time of the event
%Timestamp:format% Custom formatted timestamp using .NET format strings

The %Timestamp:format% macro supports .NET date/time format strings. For example:

  • %Timestamp:yyyy-MM-dd% produces 2026-03-16
  • %Timestamp:HH:mm:ss% produces 14:30:00
  • %Timestamp:yyyy/MM/dd HH:mm:ss% produces 2026/03/16 14:30:00

Macro Sanitization

Many macro values are supplied by remote users — for example, %FileName% comes from an uploaded file's name and %LoginFullName% comes from a user-editable profile field. To prevent a maliciously-crafted value from breaking out of the surrounding script and executing arbitrary commands, CompleteFTP replaces characters that are special to the target interpreter with an underscore (_) before substitution. The exact set depends on the trigger type:

Trigger type Characters stripped from each macro value
Program (arguments) None — each argument is passed to the program as a discrete element (never re-parsed by a shell), so the value is delivered verbatim and cannot break out
Batch script All control characters (incl. CR, LF) and any of: ", %, !, &, |, <, >, ^, (, )
PowerShell script All control characters (incl. CR, LF) and any of: ', ", ` (backtick), $, %, ;, |, &, <, >, (, ), {, }, [, ], #, ,, = (and the “smart” quote variants)
FTP script All control characters (incl. CR, LF) and any of: ", ` (backtick), %, =
JSS script None — values are exposed via the event object and are not interpreted as code

As a result, file names or profile fields containing the characters listed above will appear with underscores when substituted into a Batch, PowerShell or FTP script via the old %Macro% form. To use the original, un-altered value in a Batch or PowerShell script, reference it through the environment instead (see Using macro values safely below); in a JSS trigger, read it from the event object.

Using macro values safely (Batch and PowerShell)

For Batch and PowerShell triggers, CompleteFTP also exposes every macro value as an environment variable. This is the recommended way to use macro values: the value is passed to the script through the environment rather than substituted into the script text, so it is never altered (no underscore sanitization) and cannot break out of the script. New scripts should use this form; the old %Macro% form is retained only for backward compatibility.

The environment-variable name is the macro name without the surrounding % signs. The date/time macros are the only exception — they are prefixed with Event so they don't collide with cmd's built-in %DATE%/%TIME%: %Date%EventDate, %Time%EventTime, %DateAndTime%EventDateAndTime.

  • Batch (cmd): reference the variable using delayed-expansion syntax, !FileName!. CompleteFTP automatically enables delayed expansion (it prepends @setlocal enabledelayedexpansion) when it sees a macro referenced this way, so no change to the script is needed.
  • PowerShell: reference the variable as ${env:FileName}. No mode change is required.

The environment-variable convention applies to Batch and PowerShell only. Program triggers receive macro values as discrete arguments, and FTP scripts use the %Macro% form (with the sanitization above).

Program Triggers

Program triggers execute an external program or script when an event occurs. Macros in the arguments are expanded before the program is launched.

Basic Examples

# Copy uploaded file to an archive directory
completeftp trigger add "ArchiveUpload" UploadFile Program /usr/bin/cp \
  '"%OSPath%" /var/ftp/archive/'

# Log file transfers to a file
completeftp trigger add "TransferLog" UploadFile,DownloadFile Program /bin/bash \
  '-c "echo \"%DateAndTime% %Event% %LoginUserName% %FilePath%\" >> /var/log/ftp-transfers.log"'

# Run a custom processing script on uploaded files
completeftp trigger add "ProcessUpload" UploadFile Program \
  /usr/local/bin/process-upload.sh '"%OSPath%" "%LoginUserName%"'

# Send a notification when a file is deleted
completeftp trigger add "DeleteNotify" DeleteFile Program /usr/local/bin/notify.sh \
  '"File %FileName% deleted by %LoginUserName% at %DateAndTime%"'

Setting the Working Directory

# Set working directory for a trigger
completeftp trigger set ProcessUpload workingDirectory=/var/ftp/processing

JSS Triggers

JSS (JavaScript Server-Side) triggers run JavaScript code within the CompleteFTP process. They have access to the CompleteFTP virtual file system, FTP/SFTP client libraries, HTTP, email, and database APIs.

The event Object

In JSS triggers, event details are available through the event object rather than macros:

Property Description
event.eventType Event name (e.g., "UploadFile")
event.virtualPath Full virtual path of the file
event.filePath Full virtual path of the file
event.fileName File name
event.folderPath Virtual folder path
event.osPath Local file system path
event.osFolder Local folder path
event.osFileName Local file name
event.loginUserName Logged-in user
event.loginEmail User email
event.loginFullName User full name
event.ownerUserName Folder owner
event.ownerEmail Owner email
event.ownerFullName Owner full name
event.clientIP Client IP address
event.siteName Site name
event.serverName Server name
event.protocol Protocol used
event.transferStatus "success" or "failure"
event.time Event timestamp
event.processRule Trigger name

Basic Examples

# Move uploaded file to another folder
completeftp trigger add "MoveUpload" UploadFile JSS \
  'var file = system.getFile(event.virtualPath); file.moveTo("/Incoming");'

# Forward uploaded file to a remote server
completeftp trigger add "ForwardUpload" UploadFile JSS \
  'var ftp = new Ftp("remote.example.com", "ftpuser", "ftppass"); ftp.connect(); ftp.upload(event.virtualPath, event.fileName); ftp.close();'

# Log events to a file
completeftp trigger add "LogEvent" UploadFile,DownloadFile JSS \
  'System.IO.File.AppendAllText("/var/log/ftp-events.log", event.time + " " + event.eventType + " " + event.loginUserName + " " + event.virtualPath + "\n");'

Error Handling

# JSS trigger with error handling
completeftp trigger add "SafeMove" UploadFile JSS \
  'try { var file = system.getFile(event.virtualPath); file.moveTo("/Processed"); } catch (e) { console.log("Error moving file: " + e); }'

Using .NET Classes

JSS scripts can use .NET classes directly:

# Use .NET XML parsing
completeftp trigger add "ParseXML" UploadFile JSS \
  'var doc = new System.Xml.XmlDocument(); doc.Load(event.osPath); console.log("Root element: " + doc.DocumentElement.Name);'

Note: The JSS API includes built-in classes for FTP/SFTP (Ftp), HTTP (http), email (mail), and databases (DatabaseSync). Refer to the JSS API documentation for full details.

Filters

Filters restrict when a trigger fires based on the file path, user, or site involved in the event.

Path Filter

The path filter matches against the virtual file path of the operation. It uses wildcard patterns by default.

# Only trigger for .csv files in /Uploads
completeftp trigger set MyTrigger pathFilter="/Uploads/*.csv"

# Trigger for any .dat file in any directory
completeftp trigger set MyTrigger pathFilter="*/*.dat"

# Use regex for complex patterns
completeftp trigger set MyTrigger 'pathFilter=regex:^/Home/.*\.pdf$'

# Match multiple folders with regex
completeftp trigger set MyTrigger 'pathFilter=regex:^(/Uploads/.*|/Incoming/.*)'

# Inverse filter - trigger for all files EXCEPT .tmp files
completeftp trigger set MyTrigger pathFilter="*.tmp" pathFilterInverse=true

User Filter

# Trigger only for specific users
completeftp trigger set MyTrigger users=alice,bob

# Inverse - trigger for all users EXCEPT the listed ones
completeftp trigger set MyTrigger users=serviceaccount userFilterInverse=true

Site Filter

# Trigger only on a specific site (Enterprise MFT only)
completeftp trigger set MyTrigger sites="External Site"

# Inverse - trigger on all sites except the listed one
completeftp trigger set MyTrigger sites="Admin" siteFilterInverse=true

Scheduled Triggers

Triggers can be configured to fire on a schedule rather than (or in addition to) in response to events. To use scheduling, include Timer in the events list and set the schedule property.

Schedule Formats

CompleteFTP supports two schedule formats:

Cron Expressions

Cron expressions follow the standard cron format with an additional seconds field:

seconds minutes hours day-of-month month day-of-week
# Run every day at midnight
completeftp trigger add "DailyCleanup" Timer Program /usr/local/bin/cleanup.sh
completeftp trigger set DailyCleanup 'schedule=cron: 0 0 0 * * *'

# Run every hour on the hour
completeftp trigger add "HourlySync" Timer JSS \
  'console.log("Hourly sync at " + new Date());'
completeftp trigger set HourlySync 'schedule=cron: 0 0 * * * *'

# Run at 2:30 AM on weekdays (Mon-Fri)
completeftp trigger add "WeekdayReport" Timer Program /usr/local/bin/report.sh
completeftp trigger set WeekdayReport 'schedule=cron: 0 30 2 * * 1-5'

# Run every 15 minutes
completeftp trigger add "FrequentCheck" Timer Program /usr/local/bin/check.sh
completeftp trigger set FrequentCheck 'schedule=cron: 0 */15 * * * *'

Specific Times

# Run at specific dates and times (ISO 8601 format)
completeftp trigger set MyTrigger \
  'schedule=timestamps: 2026-04-01T00:00:00,2026-07-01T00:00:00,2026-10-01T00:00:00'

Note: Specific time schedules only trigger for future times. Past timestamps are ignored.

Process Control

Global process control settings govern how all triggers execute.

Viewing Process Control Settings

completeftp trigger processcontrol show

Configuring Process Control

# Set maximum number of concurrent trigger processes (default: 200)
completeftp trigger processcontrol set maxProcesses=50

# Set maximum run time in milliseconds (0 = no limit, default: 0)
completeftp trigger processcontrol set runTimeoutMs=30000

# Run triggers sequentially instead of concurrently
completeftp trigger processcontrol set runSequentially=true
Setting Default Description
maxProcesses 200 Maximum number of trigger processes that can run at the same time
runTimeoutMs 0 Maximum time a trigger process can run, in milliseconds (0 = unlimited)
runSequentially false When true, triggers execute one at a time rather than concurrently

Note: If the maximum number of concurrent processes is reached, new trigger events are dropped until a running process completes.

Modifying and Removing Triggers

Modifying Triggers

# Enable or disable a trigger
completeftp trigger set MyTrigger enabled=false
completeftp trigger set MyTrigger enabled=true

# Change the program path
completeftp trigger set MyTrigger processPath=/usr/local/bin/new-script.sh

# Change the arguments
completeftp trigger set MyTrigger 'arguments="%OSPath%" "%LoginUserName%"'

# Change the script for a JSS trigger
completeftp trigger set MyTrigger \
  'script=var file = system.getFile(event.virtualPath); file.copyTo("/Archive");'

# Change execution order (lower numbers run first)
completeftp trigger set MyTrigger rowOrder=5

# Set which user context the trigger runs as
completeftp trigger set MyTrigger runAsUser=serviceaccount

Removing Triggers

completeftp trigger remove MyTrigger

Workflow Examples

Archive Uploaded Files

Copy every uploaded file to a date-stamped archive directory:

# 1. Create the archive folder
completeftp folder add /Archive OS --mapping=/var/ftp/archive
completeftp folder chmod /Archive owner rwxd

# 2. Create the trigger
completeftp trigger add "ArchiveUploads" UploadFile Program /usr/bin/cp \
  '"%OSPath%" /var/ftp/archive/'

# 3. Restrict to specific users (optional)
completeftp trigger set ArchiveUploads users=alice,bob

Move Files to a Processing Directory

Automatically move uploaded files for downstream processing:

# 1. Create processing folders
completeftp folder add /Incoming OS --mapping=/var/ftp/incoming
completeftp folder add /Processed OS --mapping=/var/ftp/processed
completeftp folder chmod /Incoming all rw
completeftp folder chmod /Processed all r

# 2. Create JSS trigger to move files
completeftp trigger add "MoveToIncoming" UploadFile JSS \
  'var file = system.getFile(event.virtualPath); file.moveTo("/Incoming");'

Forward Files to a Remote Server

Automatically forward uploaded files to a partner's SFTP server:

# Create JSS trigger for forwarding
completeftp trigger add "ForwardToPartner" UploadFile JSS \
  'try { var ftp = new Ftp("partner.example.com", "xferuser", "xferpass", "sftp"); ftp.connect(); ftp.upload(event.virtualPath, event.fileName); ftp.close(); console.log("Forwarded " + event.fileName + " to partner"); } catch (e) { console.log("Forward failed: " + e); }'

# Only forward files from the /Outbound folder
completeftp trigger set ForwardToPartner pathFilter="/Outbound/*"

Daily Cleanup of Old Files

Remove files older than 30 days on a schedule:

# 1. Create the cleanup script
cat > /usr/local/bin/cleanup-old-files.sh << 'SCRIPT'
#!/bin/bash
find /var/ftp/uploads -type f -mtime +30 -delete
SCRIPT
chmod +x /usr/local/bin/cleanup-old-files.sh

# 2. Create a scheduled trigger
completeftp trigger add "DailyCleanup" Timer Program /usr/local/bin/cleanup-old-files.sh

# 3. Set the schedule (daily at 3:00 AM)
completeftp trigger set DailyCleanup 'schedule=cron: 0 0 3 * * *'

Audit Trail Logging

Log all file operations with user and connection details:

# Create a trigger for all file events
completeftp trigger add "AuditLog" \
  UploadFile,DownloadFile,DeleteFile,MoveFile,CreateFolder,DeleteFolder Program \
  /bin/bash \
  '-c "echo \"%Timestamp:yyyy-MM-dd HH:mm:ss% [%Event%] user=%LoginUserName% ip=%ClientIP% protocol=%Protocol% path=%FilePath% status=%TransferStatus%\" >> /var/log/completeftp-audit.log"'

Troubleshooting

Trigger Not Firing

# Check that the trigger is enabled
completeftp trigger show MyTrigger enabled onSuccess onError

# Verify the events are correct
completeftp trigger show MyTrigger events

# Check if filters are excluding the operation
completeftp trigger show MyTrigger users pathFilter pathFilterInverse userFilterInverse

# Enable debug logging for detailed trigger execution logs
completeftp monitor set logging.level=Debug

Program Not Executing

# Verify the program path is correct and executable
ls -la /path/to/program
completeftp trigger show MyTrigger processPath arguments

# Check process control limits
completeftp trigger processcontrol show

# Test the command manually with sample values
/path/to/program "/var/ftp/users/alice/test.txt" /var/ftp/archive/

JSS Script Errors

# Check server logs for JavaScript errors
# JSS errors are logged with the trigger name

# Test with a simple logging script first
completeftp trigger set MyTrigger \
  'script=console.log("Trigger fired: " + event.eventType + " " + event.virtualPath);'

Macro Values Not Substituted

Ensure you are using the correct macro syntax:

  • Program triggers: Use %MacroName% syntax in the arguments field
  • JSS triggers: Use event.propertyName — macros are not substituted in JSS scripts

Best Practices

Design

  1. Single responsibility - Give each trigger a clear, focused purpose
  2. Descriptive names - Name triggers to describe what they do (e.g., ArchiveInvoices, ForwardToPartner)
  3. Use filters - Restrict triggers to the specific files, users, or paths that need them
  4. Error handling - Add error handling in JSS scripts with try/catch blocks

Performance

  1. Keep processes short - Long-running triggers consume process slots; set timeouts for safety
  2. Use concurrency wisely - Enable sequential execution if trigger order matters
  3. Monitor process limits - Adjust maxProcesses based on expected trigger volume
  4. Prefer JSS for file operations - JSS scripts run in-process and avoid the overhead of launching external programs

Security

  1. Quote macro values - Always quote macros that may contain spaces: "%OSPath%"
  2. Macro sanitization is automatic but not perfect - CompleteFTP strips interpreter metacharacters from macro values (see Macro Sanitization), but this is a defense-in-depth measure. For trigger logic that operates on untrusted file names, prefer JSS triggers, which expose values as data via the event object rather than splicing them into a script.
  3. Limit permissions - Use runAsUser to run triggers with minimum required privileges
  4. Validate paths - In JSS scripts, validate file paths before operations

Maintenance

  1. Test triggers - Test new triggers with a sample upload before relying on them
  2. Monitor logs - Review server logs regularly for trigger errors
  3. Document workflows - Record the purpose and configuration of each trigger
  4. Review periodically - Disable or remove triggers that are no longer needed

Quick Reference

Trigger Management Commands

# List triggers
completeftp trigger list

# Show trigger details
completeftp trigger show [<name>] [properties]

# Add trigger
completeftp trigger add <name> <events> <type> <process> [args]

# Modify trigger
completeftp trigger set <name> property=value [property=value ...]

# Remove trigger
completeftp trigger remove <name>

Process Control Commands

# Show process control settings
completeftp trigger processcontrol show

# Set process control settings
completeftp trigger processcontrol set property=value

Common Macros

%FilePath%        = Virtual file path
%FileName%        = File name
%OSPath%          = Local OS file path
%OSFolder%        = Local OS folder path
%LoginUserName%   = Logged-in user
%ClientIP%        = Client IP address
%Event%           = Event type
%TransferStatus%  = success or failure
%DateAndTime%     = Date and time of event

Event Names

UploadFile, DownloadFile, MoveFile, DeleteFile
CreateFolder, MoveFolder, DeleteFolder
LogIn, LogOut, ChangeDirectory
Timer, StartServer, StopServer, StartSite, StopSite
AutoBan, CertificateExpiring, CertificateExpired, ClusterSyncFailed