Skip to content

Custom events

The Custom event source is the general-purpose trigger. Instead of a fixed list of things to react to, you name a class and an event, and the rule fires the moment that event happens - much like Craft's first-party Webhook plugin. It's how you forward anything Craft or another plugin does to a webhook.

How it works

A Custom event rule has two extra fields:

  • Sender Class - the class that fires the event, e.g. craft\elements\Entry.
  • Event Name - the event constant's value, e.g. afterSave.

When that class fires that event, the rule runs. There's no polling and no cron - it's immediate. The triggering event object is handed to your payload as {{ event }}, so you can reach anything on it:

twig
{{ event.sender.id }}
{{ event.sender.title }}
{{ event.isNew }}

{{ sender }} is provided as a shortcut for {{ event.sender }}.

Finding the class and event name

The class is the fully-qualified PHP class name of whatever you want to watch. The event name is the string value of the event constant, which is usually the constant's name with the EVENT_ prefix removed and camel-cased. Some common examples:

You want to react to…Sender ClassEvent Name
An entry being savedcraft\elements\EntryafterSave
An entry being deletedcraft\elements\EntryafterDelete
Any element being savedcraft\services\ElementsafterSaveElement
A user being activatedcraft\services\UsersafterActivateUser
An order being completed (Commerce)craft\commerce\elements\OrderafterCompleteOrder

If you're not sure of an event name, look it up in the class's source or its Craft/plugin documentation.

It's the constant's value, not its name

Event Name takes the string value of the EVENT_* constant - afterSave - not the constant itself, EVENT_AFTER_SAVE. Getting this the wrong way round is the usual reason a Custom event rule never fires.

Sending to Slack, Zapier, Make or your own endpoint

Custom events pair naturally with the Raw payload card mode, because you usually don't want a Microsoft Teams card wrapper around a generic webhook body. A raw payload is just a Twig template whose output is POSTed as-is. For a Zapier/Make catch hook you might send:

twig
{{ {
    id: event.sender.id,
    title: event.sender.title,
    section: event.sender.section.handle,
    url: event.sender.url,
    site: event.sender.site.handle
}|json_encode|raw }}

That forwards a clean JSON object the automation tool can pick apart. See Payloads and cards for more on the raw payload mode.

A note on conditions

The Custom event source doesn't expose named condition fields (it can't know in advance what your chosen event carries), so its condition Field picker is empty. Do your filtering inside the payload template instead - for example, wrap the body in {% if event.sender.section.handle == 'news' %}…{% endif %} - or use one of the built-in sources when one fits, since those come with ready-made condition fields.

Performance note

Listeners are only attached for class/event pairs that an enabled Custom event rule actually uses, and one listener is shared across every rule on the same pair. A disabled rule attaches nothing. So you can keep as many Custom event rules as you like without every page load paying for events nobody's watching.

Digital help you can trust.