This plugin adds the ability to manage “webhooks” in Craft CMS, which will send GET or POST requests when certain events occur.
It can be used to integrate your Craft project with task automation tools like Zapier or Netlify build hooks.
This plugin requires Craft CMS 4.0.0+ or 5.0.0+.
You can install this plugin from the Plugin Store or with Composer.
Go to the Plugin Store in your project’s Control Panel and search for “Webhooks”. Then press Install in its modal window.
Open your terminal and run the following commands:
# go to the project directory
cd /path/to/my-project.test
# tell Composer to load the plugin
composer require craftcms/webhooks
# tell Craft to install the plugin
./craft install/plugin webhooks
To configure Webhooks, go to Settings → Webhooks, or create a config/webhooks.php
file, which returns an array.
<?php
return [
'disableAllWebhooks' => false,
'maxDepth' => 10,
'maxAttempts' => 3,
'initialDelay' => null,
'retryDelay' => 120,
'purgeDuration' => 604800, // 7 days
];
The array can define the following keys:
disableAllWebhooks
– Whether all webhooks should be disabled.maxDepth
– The maximum depth that the plugin should go into objects/arrays when converting them to arrays for event payloads. (Default is 5
.)maxAttempts
– The maximum number of attempts each webhook should have before giving up, if the requests are coming back with non 2xx responses. (Default is 1
.)initialDelay
– The delay (in seconds) that initial webhook request attempts should have.retryDelay
– The delay (in seconds) between webhook attempts. (Default is 60
.)purgeDuration
– The time (in seconds) that request history should be saved in the database before being deletable via garbage collection.To manage your webhooks, go to Settings → Webhooks in your project’s Control Panel.
Webhooks can optionally be organized into groups. You can create a new group by clicking the “New group” button in the sidebar.
If a group is deleted, any webhooks in it will become ungrouped. (They will not be deleted along with the group.)
To create a new webhook, click the “New webhook” button.
Webhooks listen to events triggered by system classes. So you must determine the name of the class that will be triggering the event (the “Sender Class”), as well as the event name (either an EVENT_*
constant name, or its value).
The Sender Class can be a subclass of the class that triggers the event. For example, all elements fire an afterSave event after they’ve been saved, courtesy of their base class, craft\base\Element. However if you’re only interested in sending a webhook when an entry gets saved, you can set the Sender Class to craft\elements\Entry.
Webhook URLs can be set to an environment variable ($VARIABLE_NAME
) or Twig code. If you set it to Twig code, you can reference the triggered event via an event
variable.
See Integrating with Task Automation Tools for examples on how to get a Webhook URL from various task automation tools.
Webhooks can either send a GET request, or a POST request with a JSON body containing the following keys:
time
– an ISO-8601-formatted timestamp of the exact moment the event was triggered. (Webhooks are sent via the queue so there will be a slight delay between the time the event was triggered and the webhook was sent.)user
– an object representing the logged-in user at the time the event was triggered.name
– the name of the event.senderClass
– the class name of the event sender.sender
– an object representing the event sender.eventClass
– the class name of the event.event
– an object with keys representing any event class properties that aren’t declared by yii\base\Event. (For example, if a craft\events\ElementEvent is triggered, this will contain element and isNew keys.)Some events can have filters applied to them, which prevent webhooks from being executed under certain conditions.
Ignored filters (○
) will not have any impact. Positive filters (✓
) will be required for a webhook to execute, and a negative filter (×
) will prevent it.
Only element class events and certain craft\services\Elements
events have any filters out of the box, but modules and plugins can register additional filters using the craft\webhooks\Plugin::EVENT_REGISTER_FILTER_TYPES
event.
use yii\base\Event;
use craft\webhooks\Plugin as Webhooks;
use craft\events\RegisterComponentTypesEvent;
Event::on(
Webhooks::class,
Webhooks::EVENT_REGISTER_FILTER_TYPES,
function(RegisterComponentTypesEvent $event) {
$event->types[] = ArticleFilter::class;
}
);
Filter type classes must implement craft\webhooks\filters\FilterInterface
:
use craft\webhooks\filters\FilterInterface;
use craft\elements\Entry;
use yii\base\Event;
class ArticleFilter implements FilterInterface
{
public static function displayName(): string
{
return 'Entry has an “Article” type';
}
public static function show(string $class, string $event): bool
{
// Only show this filter if the Sender Class is set to 'craft\elements\Entry'
return $class === Entry::class;
}
public static function check(Event $event, bool $value): bool
{
// Filter based on whether the entry's type is 'article':
/** @var Entry $entry */
$entry = $event->sender;
return ($entry->type->handle === 'article') === $value;
}
}
You can prevent multiple similar webhooks from being sent by setting a “Debounce Key Format” on your webhook. This is a Twig template that defines a “debounce key” for the webhook. If two webhooks generate the same debounce key, only the second one will actually be sent.
An event
variable will be available to it that references the event that was triggered.
For example, if your webhook is for an entry (craft\elements\Entry
), then you could set the Debounce Key Format to {{ event.sender.id }}
to prevent multiple webhook requests from being queued up at the same time.
You can send custom headers along with webhook requests using the Custom Headers setting.
Header values can be set to an environment variable using the $VARIABLE_NAME
syntax, or a Twig template.
An event
variable will be available to the Twig template, set to the event that triggered the webhook.
You can have multiple headers that have the same name, and if a header value takes up multiple lines (after any empty lines have been discarded), each line will be sent as its own header, all using the same header name.
If you need more data than what’s in the default POST request payload, you can fill in the “Extra User Attributes”, “Extra Sender Attributes”, and “Extra Event Attributes” fields.
The attributes listed here (separated by newlines) will be passed to the $extraFields
argument of the user/sender/event-property’s [toArray()](https://www.yiiframework.com/doc/api/2.0/yii-base-arrayabletrait#toArray()-detail) method (if it has one).
For “Extra Event Attributes”, each attribute should be prefixed with the name of the property and a dot (e.g. element.author
will include the author
attribute of an $element
property).
You can completely customize the webhook payload by ticking the “Send a custom payload” checkbox. That will reveal the “Payload Template” field, where you can enter the desired body contents.
That field supports Twig, so you can make this dynamic. An event
variable will be available to it that references the event that was triggered.
{% set entry = event.sender %}
{{
{
time: now|atom,
user: currentUser.username ?? null,
name: event.name,
entry: {
class: className(entry),
id: entry.id,
title: entry.title,
slug: entry.slug,
isNew: event.isNew
}
}|json_encode|raw
}}
If the output is valid JSON, then webhook requests will be sent with an application/json
content type.
Webhooks can be enabled or disabled from both the Webhooks index page and within their Edit Webhook pages.
Only enabled webhooks will send webhook requests when their corresponding events are triggered.
You can disable all webhooks by setting disableAllWebhooks
to true
in your config/webhooks.php
file.
return [
'disableAllWebhooks' => true,
// ...
];
To trigger a Netlify build using Webhooks, follow these steps:
To integrate Webhooks with Zapier, follow these steps:
To integrate Webhooks with IFTTT, follow these steps:
snake_case
.{event}
text box.https://maker.ifttt.com/trigger/
.Note: Unfortunately IFTTT’s webhooks API is pretty limited, so no webhook data will be available to your applet action.