Webhooks — Real-Time Alerts on Bot Spikes
Get a Slack message (or any JSON webhook) the moment Turnstile block rate crosses your threshold. No dashboard watching required.
Settings: Notifications tab → Webhooks
Option key: wkcft_notifications
What Gets Sent
A JSON payload with:
{
"timestamp": 1703030400,
"blocks_per_hour": 75,
"threshold": 50,
"top_forms": [
{"form": "checkout", "blocks": 45},
{"form": "login", "blocks": 30}
],
"top_ips": [
{"ip": "192.0.2.10", "blocks": 25},
{"ip": "198.51.100.5", "blocks": 20}
]
}
For Slack, the plugin also formats a human-readable attachment with the same data.
Configuration
Enabled
- Key:
enabled(insidewkcft_notifications) - Default:
no
Tick to start sending webhooks.
Webhook URL (generic)
- Key:
webhook_url - Default: empty
Any https:// endpoint that accepts POST with a JSON body.
Use cases:
- Trigger a PagerDuty alert
- Post to your own monitoring API
- Feed a Splunk / Datadog integration
- Log to a simple Zapier webhook
Slack Webhook URL
- Key:
slack_webhook_url - Default: empty
A Slack incoming webhook URL (e.g., https://hooks.slack.com/services/T00/B00/XXX). The plugin formats the message for Slack's native attachment style.
You can fill both fields — the plugin posts to both simultaneously.
Threshold Per Hour
- Key:
threshold_per_hour - Range: 1 - 100000
- Default:
50
Minimum blocks per hour that trigger an alert. Set based on your baseline bot traffic:
| Site Type | Good Starting Threshold |
|---|---|
| Low-traffic shop | 10 |
| Medium shop | 50 (default) |
| High-traffic marketplace | 200 |
| Under active attack | 5 (tighter alerting) |
Throttle (Minutes)
- Key:
throttle_minutes - Range: 1 - 1440
- Default:
30
Minimum minutes between alerts. Prevents spam when an attack keeps the block rate high for hours.
Example: with threshold = 50 and throttle = 30, if the block rate stays above 50/hr, you get:
- 00:00 — alert fires
- 00:15 — still over threshold, NO alert (throttled)
- 00:30 — still over, alert fires again
- 00:40 — block rate drops below 50, no alert
- 01:05 — block rate spikes again, alert fires (throttle reset)
Last Fired Timestamp
- Key:
last_fired_ts - Type: Unix timestamp
Read-only — shows "Last alert: N minutes ago".
Send Test Webhook
Click Send Test Webhook on the Notifications tab.
- Posts a sample payload to both configured URLs
- Returns HTTP response code + body for debugging
- Does not update
last_fired_ts
Use to verify your endpoint accepts the payload before real alerts fire.
Cron Schedule
Evaluation runs on WP-Cron.
| Hook | Recurrence |
|---|---|
wkcft_check_notifications | hourly |
Each hour:
- Plugin counts blocks in last 60 minutes
- Compares to
threshold_per_hour - If over AND throttle window has passed → fire webhook(s)
- Update
last_fired_ts
WP-Cron needs traffic
Same as Email Digest — on low-traffic sites, set up a server cron. See Troubleshooting.
Setting Up Slack
- In Slack, go to your workspace's Apps page
- Click Add to Slack
- Pick a channel (e.g.,
#security-alerts) - Click Allow
- Copy the webhook URL (looks like
https://hooks.slack.com/services/T00/B00/XXX) - Paste into plugin → Notifications → Slack Webhook URL
- Save, click Send Test Webhook
- Message should appear in your Slack channel
Sample Slack Message
🚫 Turnstile Alert — yourstore.com
Blocks per hour: 75 (threshold: 50)
Top forms under attack:
• Checkout — 45 blocks
• Login — 30 blocks
Top blocked IPs:
• 192.0.2.10 — 25 blocks
• 198.51.100.5 — 20 blocks
View analytics → https://yoursite.com/wp-admin/admin.php?page=wkcft-analytics
Setting Up a Generic Webhook Endpoint
If you have your own service:
// In your receiver (example PHP)
$payload = json_decode(file_get_contents('php://input'), true);
if ($payload['blocks_per_hour'] > 100) {
// Alert pager / send SMS / email the on-call dev
trigger_my_pagerduty_alert($payload);
}
http_response_code(200);
Secure your webhook URL
The plugin does not sign outgoing webhooks. Anyone who learns your webhook URL can POST spoof payloads to it. Keep the URL secret and, if your endpoint is public, validate expected fields (e.g., site, threshold) before acting.
Response Handling
The plugin expects a 2xx response from your webhook. On failure:
- Logs a warning in the WordPress debug log
- Retries on the next hourly cron run
- Does not update
last_fired_tsso the alert condition remains active
Integrations
Zapier
Use Zapier's Webhook → Catch Hook step. Then build any action:
- Gmail — email the on-call
- SMS (Twilio) — text the security team
- Trello — create a card
- Google Sheets — log the alert
PagerDuty
Create a PagerDuty service with a webhook integration. Paste their webhook URL into the plugin. Every alert becomes an incident.
Datadog / Grafana
Use the events API endpoint. Alerts show up on your monitoring dashboards.
Filter Reference
The Notifications class does not expose custom filters for payload tampering. If you need to modify the payload, fork the class via a MU-plugin and extend WKCFT_Notifications. See Filters & Hooks for the full list of real filters.
Recipes
"Only Page Me on Serious Attacks"
- Threshold:
200 - Throttle:
120minutes - Webhook: PagerDuty high-urgency service
Baseline bot noise won't wake you, but a real attack will.
"Daily Trend for Dev Team"
Better suited to the email digest — webhooks are for real-time.
"Multi-Site Alerting"
Run multiple stores? Use different Slack channels per site:
- Site A:
#alerts-storeA - Site B:
#alerts-storeB
Each store points at its own Slack webhook URL.
Troubleshooting
| Problem | Fix |
|---|---|
| Test webhook fails | Check the URL is reachable from your server. Try curl -X POST https://your-url from SSH |
| Slack alerts arrive but look weird | Not actually a Slack URL — use the Slack format URL only for the Slack field |
| Alerts never fire even during an attack | WP-Cron not running. Set up server cron |
| Alerts fire constantly (spam) | Raise threshold or throttle_minutes |
| Webhook URL leaked or exposed | Generate a new webhook URL at your receiver (Zapier / Slack / etc.), paste into plugin, save |
Related Pages
- Notifications — Parent tab
- Email Digest — Non-real-time version
- Analytics — Same data
- Conditional Rules — Add attacking IPs to blacklist from alerts
