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%produces2026-03-16%Timestamp:HH:mm:ss%produces14:30:00%Timestamp:yyyy/MM/dd HH:mm:ss%produces2026/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 (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
- Single responsibility - Give each trigger a clear, focused purpose
- Descriptive names - Name triggers to describe what they do (e.g.,
ArchiveInvoices,ForwardToPartner) - Use filters - Restrict triggers to the specific files, users, or paths that need them
- Error handling - Add error handling in JSS scripts with try/catch blocks
Performance
- Keep processes short - Long-running triggers consume process slots; set timeouts for safety
- Use concurrency wisely - Enable sequential execution if trigger order matters
- Monitor process limits - Adjust
maxProcessesbased on expected trigger volume - Prefer JSS for file operations - JSS scripts run in-process and avoid the overhead of launching external programs
Security
- Quote macro values - Always quote macros that may contain spaces:
"%OSPath%" - 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
eventobject rather than splicing them into a script. - Limit permissions - Use
runAsUserto run triggers with minimum required privileges - Validate paths - In JSS scripts, validate file paths before operations
Maintenance
- Test triggers - Test new triggers with a sample upload before relying on them
- Monitor logs - Review server logs regularly for trigger errors
- Document workflows - Record the purpose and configuration of each trigger
- 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