Hot Folder Integration
Prepress departments live in hot folders — drop a file in, get the result out. Our reference watcher script turns the v1 REST API into exactly that workflow. ~300 lines of Node, runs as a launchd / systemd / Windows service, handles every edge case we've seen.
How it works
You designate a base folder on a prepress workstation or shared server. Underneath, four IN/{profile} subfolders map to our four print profiles. Anyone on your team drops artwork into the matching subfolder; the watcher detects it, submits to /v1/preflight, polls until complete, then writes the rendered PDF report plus structured JSON findings into OUT/{verdict}/. The original artwork moves to processed/ on success or failed/ on error so you can see at a glance what's pending vs. done.
HotFolder/
IN/
digital-labels/ ← drops here run with profile=digital-labels
flexo-labels/ ← …flexo-labels
flexpack/ ← …flexpack
cartons-folding/ ← …cartons-folding
OUT/
PASS/ ← {name}.{jobid}.preflight.pdf + .preflight.json
CONDITIONAL_PASS/
FAIL/ ← + {name}.error.txt when analysis errored
processed/ ← source artwork moved here after analysis
failed/ ← source artwork moved here if analysis errored
state/ ← internal — crash-recovery queue
All subfolders are auto-created on startup. You don't pre-build the tree — just point the watcher at a base path.
Install in two minutes
mkdir preflight-hotfolder && cd preflight-hotfolder
curl -O https://preflight.art/v1/hotfolder/watch.js
curl -O https://preflight.art/v1/hotfolder/package.json
curl -O https://preflight.art/v1/hotfolder/README.md
npm install
# Run it
node watch.js \
--base /Users/you/HotFolder \
--api-key pf_yourkeygoeshere
Or set env vars instead of CLI flags:
export PREFLIGHT_BASE=/Users/you/HotFolder
export PREFLIGHT_API_KEY=pf_yourkeygoeshere
node watch.js
Run as a service
You almost certainly want this running unattended so files dropped overnight get processed. The full README at /v1/hotfolder/README.md has copy-paste configs for:
- macOS — launchd plist at
~/Library/LaunchAgents/art.preflight.hotfolder.plist - Linux — systemd unit at
/etc/systemd/system/preflight-hotfolder.service - Windows — NSSM (Non-Sucking Service Manager) command sequence
What the watcher handles correctly
Edge cases we've found bite real prepress shops:
- File still being written. Designer drops a 200 MB
.aiover a slow VPN. We wait until file size has been stable for--stable-timeseconds (default 3) before submitting. Belt-and-braces with chokidar's ownawaitWriteFinish. - Locked files on Windows. Adobe Illustrator holds an open handle for ~100ms after Save.
readFileretries on EBUSY with backoff (0.25s, 0.5s, 0.75s, 1s, 1.25s). - Crash recovery. In-flight jobs are journaled to
state/in-flight.json. On restart the script resumes polling without losing work. - Naming collisions. Outputs include the first 8 chars of the job id, so two files named
label.pdfdropped seconds apart don't overwrite each other. - Automatic retry on transient failures. A network blip,
5xx,429, poll timeout, or a job interrupted by a server restart is retried up to--retry-attemptstimes (default 3) with backoff before giving up. Validation failures (a4xx, or a corrupt / password-protected file) are not retried — they would just fail again. - Failed analysis. After retries are exhausted (or immediately for a validation failure) the source routes to
failed/+ writes{name}.error.txtunderOUT/FAIL/. Never silently swallowed. - Bounded concurrency. Default 4 simultaneous in-flight jobs against the API. Tune via
--max-concurrent. - Graceful shutdown. SIGINT/SIGTERM stops accepting new files but waits up to 30s for in-flight jobs to finish their current poll cycle before exiting.
- Cross-device renames. Falls back to copy + unlink when source and destination live on different filesystems (network shares).
- Recursion safety. Ignores any file matching
*.preflight.*so accidentally dropping an output back into IN doesn't loop.
--max-concurrent 4 and ~90-second jobs you'll sustain about ~160 files/hr without issue. If your shop runs more than that, email hello@preflight.art and we'll raise your cap.Common deployment patterns
| Pattern | Setup |
|---|---|
| Designer drops to network share, prepress reviews the results | Watcher runs on a shared file server. SMB share mounted to designers' workstations. They drop into \\prepress\HotFolder\IN\{profile}. Prepress reviews OUT/. |
| One watcher per print line | Three separate watcher instances (each its own base + key), one per pressroom. Independent rate limits + audit logs per line. |
| Cloud-attached storage | Mount S3 / Backblaze / Wasabi via rclone or s3fs at the base path. The watcher doesn't care that it's not local. |
| Designer self-service | Wrap the IN folder in a Dropbox / OneDrive / Google Drive shared folder. Designers drag files in from anywhere; the watcher (running anywhere) processes them. |
Configuration reference
| Flag | Default | Env var | Notes |
|---|---|---|---|
--base <path> | required | PREFLIGHT_BASE | Root of your hot folder. |
--api-key pf_… | required | PREFLIGHT_API_KEY | Issued via /account/api-keys. |
--api-base <url> | https://preflight.art | PREFLIGHT_API_BASE | Override for staging. |
--poll-interval <sec> | 5 | PREFLIGHT_POLL_SECONDS | Status-check cadence. |
--stable-time <sec> | 3 | PREFLIGHT_STABLE_SECONDS | How long file size must hold steady before we submit. |
--max-concurrent <n> | 4 | PREFLIGHT_MAX_CONCURRENT | Simultaneous in-flight jobs. |
--job-description "…" | (empty) | PREFLIGHT_JOB_DESCRIPTION | Free-text passed as job notes to every analysis. |
Customising
The script is plain Node — no compile step, no exotic deps (one: chokidar). Fork it into your internal tooling repo, add your own output routing (email designer on FAIL, push to your ERP, etc.), and run that instead. Common customisations we've seen:
- Email the designer on any
FAILverdict with the PDF report attached - POST the JSON findings to your job-management system as a webhook
- Move
FAILoutputs to a separate "needs review" Dropbox folder visible to the prepress lead - Tag the output PDF with the press operator who picked up the job, by reading a sibling metadata file dropped alongside the artwork
Source
Inspect or download:
/v1/hotfolder/watch.js— the script (~300 lines, well-commented)/v1/hotfolder/package.json/v1/hotfolder/config.example.json/v1/hotfolder/README.md— full deployment guide
License: MIT. Fork it, ship it inside your own tooling. If you build something nice on top, we'd love to see it — hello@preflight.art.