goldnead / statamic-automations
A visual automation layer built specifically for Statamic websites. Build automations for Statamic forms, entries, leads and webhooks with a familiar visual flow builder inside the Control Panel.
Package info
github.com/goldnead/statamic-automations
Type:statamic-addon
pkg:composer/goldnead/statamic-automations
Requires
- php: ^8.2
- goldnead/statamic-brand-context: ^1.3
- inertiajs/inertia-laravel: ^1.0|^2.0
- laravel/framework: ^12.0|^13.0
- statamic/cms: ^6.0
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.18
- orchestra/testbench: ^10.0|^11.0
- pestphp/pest: ^2.0|^3.0|^4.0
- pestphp/pest-plugin-laravel: ^2.0|^3.0|^4.0
Suggests
- goldnead/statamic-leadhub: Trigger automations from LeadHub CRM events (contacts, follow-ups, opportunities)
- goldnead/statamic-webhook-manager: Delegate webhook delivery (retries, auth, logging) to Webhook Manager
This package is auto-updated.
Last update: 2026-08-02 06:20:30 UTC
README
Statamic Automations
A visual automation layer built specifically for Statamic websites.
Build automations for Statamic forms, entries, leads and webhooks
โ with a familiar visual flow builder inside the Control Panel.
Statamic Automations gives your site a lightweight visual workflow builder. Create automations from forms, content events, LeadHub contacts and webhooks โ without writing a custom Laravel listener for every small process.
Build flows with Trigger, Filter, Branch and Action nodes, test them with real sample data, and inspect every run with node-by-node logs.
It's not a full n8n replacement. It's the missing automation layer for Statamic websites.
Why this exists
Statamic is wonderful as a CMS and developer framework, but typical website automations still demand:
- custom Laravel events + listeners
- hand-rolled webhooks
- third-party tools like Zapier / Make / n8n
- opaque "what just happened?" lead and form pipelines
For most Statamic projects an external automation tool is overkill, and custom code for every small workflow is expensive to maintain. Statamic Automations sits exactly in that gap.
Features
- ๐จ Visual node-based flow builder inside the Control Panel
- โก Triggers for forms, entries, assets, users, leads and webhooks
- ๐ Filter and Branch nodes for simple logic
- ๐ Actions for emails, webhooks, LeadHub updates and Statamic changes
- ๐ช Token picker for using event data in actions (
{{ form.email }},{{ lead.full_name }}โฆ) - ๐งช Test runs with real sample data โ no real side-effects in test mode
- ๐ Node-by-node execution logs with redacted sensitive payloads
- ๐งฉ Optional Webhook Manager + LeadHub integrations (auto-detected, never required)
- ๐ฆ Templates that copy into user-owned automations
- ๐ค JSON export / import for version control, starter kits and cross-environment moves
- ๐จโ๐ป Public developer API for custom triggers, actions and conditions
Requirements
- PHP 8.2+
- Laravel 12.x or 13.x
- Statamic 6.x
goldnead/statamic-brand-contextโ a hard runtime dependency, not optional. Every automation, run and audit entry is scoped to a brand, and handles are unique per brand rather than per install. Until that package is on Packagist,composer requirecannot resolve it from this package alone: arepositoriesblock declared inside a dependency is ignored by Composer, only the root project's is read.
Installation
composer require goldnead/statamic-automations php artisan migrate
That's it. The addon ships its compiled Control Panel assets (Inertia + Vue 3)
under resources/dist/build/, and Statamic publishes them to your site's
public/vendor/statamic-automations/ automatically on install โ there is no
end-user build step.
Optionally publish the config to customise defaults:
php artisan vendor:publish --tag=statamic-automations-config
Developing the addon? The frontend is built with the official Statamic 6 Vite convention (
@statamic/cms/vite-plugin). From a clone, runcomposer install && npm install && npm run build, or usescripts/setup-playground.shto spin up a full Statamic 6 playground.
Make sure your queue worker is running so automation runs are dispatched off the request thread:
php artisan queue:work --queue=default
Quick start
- Open the Statamic CP and navigate to Automations.
- Click New automation.
- Click the + on the empty canvas, then pick a Trigger (e.g. Form Submitted) from the node library on the left. The canvas lays nodes out for you โ you never drop one onto free space, and you never draw a connection by hand.
- Click the + below the trigger to add Filter or Branch nodes if you need conditions, then Action nodes (e.g. Send Email). Each node is wired to the + you clicked, so the flow connects itself.
- To insert a node between two existing ones, click the + that sits on the edge between them.
- Click Validate then Test with sample data.
- Toggle Enabled when ready โ the automation now runs against real events.
Or skip steps 2โ5 and start from a template: the eight most common patterns ship as one-click installs, each copied into an automation of your own that addon updates never touch.
Built-in nodes
Triggers
| Trigger | Group | Source |
|---|---|---|
| Manual Trigger | Manual | For testing & ad-hoc runs |
| Form Submitted | Statamic | A Statamic form receives a submission |
| Entry Published | Statamic | An entry is published |
| Lead Created (LeadHub) | LeadHub | A new lead is added |
| Lead Status Changed (LeadHub) | LeadHub | A lead transitions between statuses |
| Lead Tag Added (LeadHub) | LeadHub | A tag is added to a lead |
| Lead Note Added (LeadHub) | LeadHub | A note is added to a lead |
| Lead Follow-up Due (LeadHub) | LeadHub | A scheduled follow-up becomes due |
| Webhook Received (Webhook Manager) | Webhook Manager | An inbound endpoint receives a validated request |
| Outbound Webhook Failed (Webhook Manager) | Webhook Manager | A delivery exhausts its retries and fails for good |
Logic
| Node | Purpose |
|---|---|
| Filter | Stop the flow if conditions aren't met |
| Branch | Split into true / false paths |
| Stop | End the flow with status stopped |
| Delay | Wait for minutes / hours / days, then continue |
Actions
| Action | Group | Notes |
|---|---|---|
| Send Email Notification | Notifications | Token-resolved subject + body |
| Send Webhook (Simple) | HTTP | Direct POST/PUT/PATCH |
| Send Webhook (via Webhook Manager) | Webhook Manager | Inherits transport, signing, retry, logs |
| Add Log Entry | Utilities | Writes to your Laravel log channel |
| Create / Update Entry | Statamic | Create or edit an entry from token-resolved data |
| Publish / Unpublish / Delete Entry | Statamic | Change or remove an entry by id |
| Create Term | Statamic | Add a taxonomy term |
| Create / Update User | Statamic | Create or merge field data on a user |
| Assign User Role ยท Add User to Group | Statamic | Add/remove a role or group membership |
| Set Global Value | Statamic | Set a key on a global set (per site) |
| Stop Flow | Logic | Ends the flow intentionally |
| Create or Update Lead (LeadHub) | LeadHub | Email-based upsert |
| Change Lead Status (LeadHub) | LeadHub | |
| Add / Remove Lead Tag (LeadHub) | LeadHub | |
| Add Lead Note (LeadHub) | LeadHub | Token-resolved body |
| Create / Complete Follow-up (LeadHub) | LeadHub |
Templates
Eight curated templates ship with the addon โ each one is copied into a user-owned automation when installed, so updates to the addon never silently change your existing flows.
- New Lead Notification โ email the admin when a LeadHub lead is created
- Form Submission to Webhook โ forward submissions to an external URL
- Qualified Lead to CRM โ push qualified leads + add note + schedule follow-up
- Workshop Inquiry Flow โ capture, tag, notify, schedule follow-up
- Lead Magnet Delivery โ send the file, create a tagged lead, log the delivery
- Follow-up Reminder โ daily reminders for due follow-ups
- Entry Published Notification โ webhook on collection publish (Slack-friendly)
- Webhook Failure Alert โ admin email when a destination keeps failing
Works with
Automations is the orchestration layer in a small family of addons. Each one owns a different concern:
- statamic-automations โ orchestration: multi-step workflows (triggers โ conditions โ actions) built visually in the CP.
- statamic-webhook-manager โ transport: reliable HTTP in and out (delivery, retries, auth, signing, logging). Automations can delegate its webhook delivery to it.
- statamic-leadhub โ CRM: contacts, follow-ups and opportunities whose events become automation triggers.
Note that both Automations and Webhook Manager can react to the same Statamic events (e.g. an entry save). Pick one place per concern: if a save should just fire a webhook, configure it in Webhook Manager; if it should run a multi-step workflow, build it here โ don't wire the same event in both.
Optional integrations
Sister addons are detected automatically through class_exists. The package keeps working without them.
| Integration | Class | Adds |
|---|---|---|
| Webhook Manager | Goldnead\WebhookManager\Facades\WebhookManager |
"Send Webhook (via Webhook Manager)" action with Webhook Manager destinations |
| LeadHub | Goldnead\Leadhub\Facades\LeadHub |
5 LeadHub triggers + 7 LeadHub actions |
Class names are configurable in config/automations.php under integrations, so you can swap implementations or use a fork.
Extending Automations
The addon exposes a full public extensibility API. A third-party addon (or your host app) registers custom nodes and data sources from any service provider's boot() โ the very same surface the built-ins are registered through. Server-registered nodes appear in the CP node library with no frontend build, and their schema() becomes the config form automatically.
use Goldnead\StatamicAutomations\Facades\Automations; public function boot(): void { // Nodes โ handle-less overload reads ::handle() from the class. Automations::registerAction(SendToInternalApiAction::class); Automations::registerTrigger(InvoicePaidTrigger::class); Automations::registerLogicNode(BusinessHoursGate::class); // Populate a custom <select> picker (options_source: 'shop.products'). Automations::registerOptionSource('shop.products', fn ($request) => \App\Models\Product::all()->map(fn ($p) => ['value' => $p->id, 'label' => $p->name])->all() ); // Turn any application event into a trigger โ one call registers the node // AND subscribes a listener that funnels the event into the dispatcher. Automations::registerEventTrigger(\App\Events\OrderShipped::class, [ 'handle' => 'order_shipped', 'label' => 'Order Shipped', 'group' => 'Shop', 'payload' => 'order', // โ {{ order.id }} 'output_schema' => ['order' => ['id' => 'string', 'total' => 'number']], ]); }
Custom actions implement AutomationAction, triggers AutomationTrigger, logic nodes AutomationLogicNode (all extend the shared AutomationNode). Event triggers can also be declared config-only in config/automations.php under event_triggers. A malformed registration throws immediately (Automations::describe()), never silently no-ops.
Full documentation โ interface definitions, the schema-field vocabulary, option-source reference and worked copy-paste examples for every extension point โ lives at https://docs.adriangoldner.dev/automations/extending.
Export & Import
Every automation can be exported to a portable JSON file (schema-versioned), and re-imported in any environment:
- Export:
GET /cp/automations/api/automations/{id}/export(or click Export in the builder topbar) - Import: drop a JSON file on
/cp/automations/import - File sync: optionally store automations in
resources/automations/{handle}.jsonfor Git-based versioning
Imports always create new automations (never silently overwrite), start disabled, and surface warnings for missing integrations or unknown node types.
Configuration
See config/automations.php. Highlights:
queue/queue_connectionโ dedicated queue for automation runsruns.prune_after_daysโ default 30, override or set tonullto disable pruningtest_mode.*โ fine-grained switches for what runs during a test (default: nothing real)security.redact_keysโ patterns redacted in run logsintegrations.*โ class names for sister addon detectionfile_storage.pathโ where exported JSON files are written
Testing
composer test # or: vendor/bin/pest
The package ships with unit + feature tests for the engine, validators, integrations, exporter/importer, registries and the CP API.
Component tests (Vitest)
npm test # or: npx vitest run / npx vitest (watch) npm run test:js # the older node:test suite for pure builder functions
PHPUnit reaches the route, the FormRequest, the controller and the props it
hands to Inertia. tests/js/*.test.mjs reaches the builder's pure functions
(auto-layout, history, validation, icons). Neither could execute a line of the
component logic in between โ a .toLowerCase() on a value the backend also
stores as an array, or a ?? that should have been a ||, throws or renders
wrong at mount time and nowhere else.
- Vitest reads the same
vite.config.js. UnderVITESTthe Statamic Vite plugin is swapped for the plain Vue plugin, because the former rewritesvuetowindow.Vueโ correct for the CP bundle, fatal in a test process. @statamic/cms/uiand@statamic/cms/inertiaare shims that destructure a global__STATAMIC__at import time.tests/js/setup.jsinstalls it before any test module loads and answers every requested name with a stub that mirrors its scalar attributes into the DOM (<div data-stub="Badge" data-attr-variant="success">), so a test can assert what a component was handed without pinning the CP's real markup.- Component tests live in
tests/js/**/*.test.js; the pure-function suite stays intests/js/*.test.mjsand is run bynpm run test:js.
The whole suite against MySQL
mysql -e 'CREATE DATABASE automations_test'
vendor/bin/pest -c phpunit.mysql.xml
The default run is in-memory SQLite, which has no InnoDB key-length limit, no
per-character byte cost and no fixed column widths โ so it cannot see the class
of defect that took statamic-notifications v1.0.3 down on production.
tests/Unit/IndexKeyLengthTest.php closes that gap without a server: it
compiles this package's own migration files through Laravel's MySQL grammar in
pretend mode and measures every index the way InnoDB would, plus asserts
headroom and that no unique covers a nullable column. phpunit.mysql.xml is
for the run that proves the compiled DDL and the real engine agree.
Documentation
The user documentation lives at https://docs.adriangoldner.dev/automations/.
| Document | Topic |
|---|---|
| Installation | Install, requirements, queue setup |
| Building an automation | The builder, step by step |
| Concepts | Triggers, logic, actions, context |
| Nodes | Every built-in node and its config |
| Templates | Catalog of every built-in template |
| Runs | Run logs, retries, partial retries |
| Export / import | JSON moves and automations:sync |
| Configuration | Every config key |
| Integrations | LeadHub, Webhook Manager, Marketing |
| Extending | Custom triggers, actions, conditions |
| Reference | The CP JSON API |
| Troubleshooting | When something does not fire |
| Changelog | Versioned release notes |
Absolute links on purpose: /docs is export-ignored, so a relative docs/*.md link is
dead in the Composer tarball a customer actually installs.
Status
Shipping since v1.0.0; see the changelog for what changed when.
The suite is 408 PHP tests (Pest on orchestra/testbench, booted through Statamic's
AddonTestCase) plus 141 JS tests (node --test for pure composables, Vitest +
@vue/test-utils for mounted components). CI runs Pest across PHP 8.2 / 8.3 / 8.4 ร
Laravel 12 / 13, a --prefer-lowest leg, a MySQL leg, both JS runners, Pint and PHPStan,
and a job that rebuilds the committed CP bundle and fails if it drifted from source.
Out of scope for v1, per the PRD non-goals: code nodes and arbitrary loop detection inside branches.
Editions
Statamic Automations ships in two editions:
- Free โ the full visual builder, triggers, logic and core actions.
- Pro โ premium features (e.g. the AI action and custom node registration), unlocked with a Pro license from the Statamic Marketplace.
The active edition is resolved natively through Statamic's licensing system โ the Control Panel's licensing utility shows your status.
License
Commercial software, licensed (not sold) through the Statamic Marketplace. See LICENSE. ยฉ 2026 Adrian Goldner.



