Gareth Wilson Gareth Wilson

Guide to WordPress Webhooks Features and Best Practices

Published


WordPress.com hosts millions of websites, from personal blogs to business sites and digital publications. For developers who want to integrate WordPress.com sites with external systems (sending a Slack notification when a new post goes live, syncing comments to a CRM, or triggering a build pipeline on publish) webhooks are the built-in mechanism for doing so.

This guide covers everything you need to know about WordPress.com webhooks: their features, how to configure them, best practices for production use, and the common pain points developers face along with solutions to address them.

This guide covers the native webhook system built into WordPress.com hosted sites. If you're running WooCommerce, see our Guide to WooCommerce Webhooks Features and Best Practices. If you're self-hosting WordPress, see the section on self-hosted alternatives below.

What are WordPress.com webhooks?

WordPress.com webhooks are HTTP POST callbacks triggered by specific actions on your WordPress.com site. When one of the supported actions occurs (a post is published, a page goes live, or a comment is submitted) WordPress.com sends an HTTP POST request containing the associated data to a URL you configure. This allows integration with notification services, CI/CD pipelines, analytics platforms, and any system that can receive HTTP requests.

The WordPress.com webhook system is based on HookPress, a plugin originally developed by Michael Yoshitaka Erlewine that exposes WordPress action hooks as outbound webhooks. WordPress.com integrated a version of this system natively, making it available without any plugin installation.

Important: WordPress.com's native webhook settings do not apply to plugin-enabled sites. If your WordPress.com site has plugins enabled (Business or eCommerce plans), you'll need to use a plugin like WP Webhooks instead.

WordPress.com webhook features

FeatureDetails
Webhook configurationWordPress.com admin UI only
Supported actionspublish_post, publish_page, comment_post
Payload formatHTTP POST with form-encoded body
Hashing algorithmNone — payloads are unsigned
TimeoutNot documented
Retry logicNone documented
Manual retryNot available
Browsable logNot available
Custom payload formattingField selection only — no templates
AuthenticationNone built-in

Supported action hooks

WordPress.com webhooks support three action hooks. Each hook fires when a specific event occurs on your site, and you can select which data fields to include in the payload.

publish_post

Fires when a post is published, or when a published post is edited.

Available fields: ID, comment_count, comment_status, guid, menu_order, ping_status, pinged, post_author, post_category, post_content, post_content_filtered, post_date, post_date_gmt, post_excerpt, post_mime_type, post_modified, post_modified_gmt, post_name, post_parent, post_password, post_status, post_title, post_type, post_url, to_ping

publish_page

Fires when a page is published, or when a published page is edited.

Available fields: ID, comment_count, comment_status, guid, menu_order, ping_status, pinged, post_author, post_category, post_content, post_content_filtered, post_date, post_date_gmt, post_excerpt, post_mime_type, post_modified, post_modified_gmt, post_name, post_parent, post_password, post_status, post_title, post_type, post_url, to_ping

comment_post

Fires when a new comment is saved to the database.

Available fields: comment_ID, comment_agent, comment_approved, comment_author, comment_author_IP, comment_author_email, comment_author_url, comment_content, comment_date, comment_date_gmt, comment_karma, comment_parent, comment_post_ID, comment_type, user_id

The comment_post hook provides comment_post_ID (the numeric ID of the parent post) but does not include the post title or post URL. Your receiving endpoint will need to resolve those separately if needed.

Webhook payload structure

When a configured action fires, WordPress.com sends an HTTP POST request to your specified URL. The payload contains whichever fields you selected during configuration, plus one additional field: hook, which contains the name of the action that triggered the delivery.

For example, a publish_post webhook configured to send the post_title, post_url, and post_date fields would deliver a payload like:

hook=publish_post&post_title=My+New+Article&post_url=https%3A%2F%2Fexample.wordpress.com%2F2026%2F02%2Fmy-new-article&post_date=2026-02-13+10%3A30%3A00

Key payload characteristics

CharacteristicDetails
HTTP methodPOST
Content typeapplication/x-www-form-urlencoded
Always-included fieldshook (the action name that triggered the webhook)
User-selected fieldsChosen during webhook configuration
Signature headersNone
Delivery ID headersNone

Unlike modern webhook implementations that send structured JSON with metadata headers (delivery IDs, signatures, timestamps), WordPress.com webhooks deliver a flat set of form-encoded key-value pairs. There is no envelope structure, no pagination, and no batch delivery — each event triggers a single POST with the selected fields.

Setting up WordPress.com webhooks

WordPress.com webhooks can only be configured through the admin UI. There is no API, CLI, or provisioning file support.

Step-by-step configuration

  1. Navigate to your site's webhook settings by visiting: https://yoursite.wordpress.com/wp-admin/options-general.php?page=webhooks
  2. Click Add webhook.
  3. Select an Action from the dropdown (publish_post, publish_page, or comment_post).
  4. Select the Fields you want included in the payload.
  5. Enter the URL that will receive the HTTP POST requests.
  6. Save the webhook.

Once created, you can edit, delete, activate, or deactivate the webhook using the options in its row.

Requirements

  • You must have Administrator role access on the site.
  • The site must not be a plugin-enabled site (Business/eCommerce plans with plugins active use plugin-based webhook solutions instead).
  • The receiving URL must be publicly accessible and accept HTTP POST requests.

Best practices when working with WordPress.com webhooks

Implement your own endpoint authentication

Since WordPress.com webhooks include no HMAC signature, secret key, or authentication header, you need to verify requests yourself. There are several approaches:

Secret token in the URL

Include a secret token as a query parameter in your webhook URL. This is the simplest approach, though it relies on the secrecy of the URL itself:

Node.js

const express = require('express');
const app = express();

app.use(express.urlencoded({ extended: true }));

const WEBHOOK_SECRET = process.env.WP_WEBHOOK_SECRET;

app.post('/webhooks/wordpress', (req, res) => {
  const token = req.query.token;

  if (token !== WEBHOOK_SECRET) {
    return res.status(401).send('Unauthorized');
  }

  // Process webhook
  const { hook, post_title, post_url } = req.body;
  console.log(`Action: ${hook}, Title: ${post_title}`);

  res.status(200).send('OK');
});

Configure your webhook URL as: https://your-endpoint.com/webhooks/wordpress?token=your-secret-token

Python

import os
from flask import Flask, request, abort

app = Flask(__name__)

WEBHOOK_SECRET = os.environ['WP_WEBHOOK_SECRET']

@app.route('/webhooks/wordpress', methods=['POST'])
def handle_wordpress_webhook():
    token = request.args.get('token')

    if token != WEBHOOK_SECRET:
        abort(401)

    hook = request.form.get('hook')
    post_title = request.form.get('post_title')

    print(f"Action: {hook}, Title: {post_title}")

    return 'OK', 200

IP allowlisting

If WordPress.com publishes IP ranges for their infrastructure, restrict your endpoint to only accept requests from those IPs. However, IP ranges can change, so this approach requires maintenance.

Respond quickly to avoid timeouts

WordPress.com's webhook delivery is based on HookPress, which originally made requests synchronously. This means slow responses from your endpoint could impact the user experience on the WordPress.com site itself (for example, delaying post publication while the webhook delivery completes).

Always acknowledge the webhook immediately and process the data asynchronously.

Build idempotent handlers

Since WordPress.com doesn't provide delivery IDs or deduplication, your endpoint may receive duplicate webhooks, particularly for publish_post and publish_page, which fire both on initial publication and on subsequent edits to published content. Use the post or comment ID to implement idempotency:

async function handleNewPost(fields) {
  const idempotencyKey = `publish_post:${fields.ID}:${fields.post_modified_gmt}`;

  const exists = await redis.get(`processed:${idempotencyKey}`);
  if (exists) {
    console.log(`Post ${fields.ID} already processed at this version, skipping`);
    return;
  }

  await processPost(fields);
  await redis.setex(`processed:${idempotencyKey}`, 86400, '1'); // 24-hour TTL
}

Enrich sparse payloads where needed

The comment_post hook only provides the parent post's numeric ID (comment_post_ID), not its title or URL. If your integration needs the full post context, you'll need to enrich the data by calling the WordPress.com REST API.

WordPress.com webhook limitations and pain points

No payload signing or authentication

The Problem: WordPress.com webhooks include no HMAC signature, no secret key, and no authentication headers. Payloads are sent completely unsigned, meaning your endpoint has no built-in way to verify that a request genuinely originated from your WordPress.com site.

Why It Happens: The WordPress.com webhook system is based on HookPress, which was developed in 2009 before HMAC webhook signing became a standard practice. The system has not been updated to include modern security features.

Workarounds:

  • Include a secret token as a query parameter in the webhook URL.
  • Implement IP allowlisting on your endpoint if WordPress.com IP ranges are known.
  • Place your webhook endpoint behind an API gateway that handles authentication.
  • Use HTTPS to ensure payloads are encrypted in transit (though this doesn't verify the sender).

How Hookdeck Can Help: Route your WordPress.com webhooks through Hookdeck, which acts as a secure intermediary. Hookdeck receives the unsigned payload from WordPress.com, and your server only needs to verify Hookdeck's signature (which uses standard HMAC-SHA256 signing) rather than dealing with the absence of verification from WordPress.com directly.

Only three supported action hooks

The Problem: WordPress.com's native webhook system only supports three actions: publish_post, publish_page, and comment_post. Common events like user registration, post deletion, category changes, media uploads, and post status transitions (draft → pending → published) are not available as webhook triggers.

Why It Happens: WordPress.com integrated a stripped-down version of HookPress rather than exposing the full WordPress action hook system. The self-hosted HookPress plugin supported dozens of WordPress actions, but WordPress.com limited the implementation to three.

Workarounds:

  • For plugin-enabled sites, install the WP Webhooks plugin, which supports 100+ triggers.
  • Use the WordPress.com REST API to poll for changes that aren't covered by webhooks.
  • Use Zapier or IFTTT integrations, which connect to WordPress.com through the REST API rather than webhooks.
  • For WooCommerce stores, use WooCommerce's built-in webhook system which supports 15+ topics.

How Hookdeck Can Help: While Hookdeck can't add new event types to WordPress.com, it can help you maximise the value of the three available hooks. Use Hookdeck's filtering to route events to different destinations based on payload content, and use transformations to reshape payloads for downstream systems.

No retry logic

The Problem: If your endpoint is temporarily unavailable (due to a deployment, infrastructure issue, or transient error) the webhook delivery fails silently. WordPress.com does not retry failed deliveries, and there is no mechanism to recover lost events.

Why It Happens: The underlying HookPress system makes synchronous HTTP requests during the WordPress action lifecycle. There is no background queue, no delivery tracking, and no retry scheduler.

Workarounds:

  • Ensure your receiving endpoint has high availability and redundancy.
  • Implement a reconciliation process that periodically checks the WordPress.com REST API for events your webhook endpoint may have missed.
  • Use an intermediary service with queuing capabilities to receive webhooks before forwarding to your application.

How Hookdeck Can Help: Hookdeck queues every incoming webhook persistently, then delivers to your endpoint with automatic retries and configurable backoff strategies. If your endpoint is down, Hookdeck holds the events and delivers them when it comes back online. Failed deliveries are preserved in a dead-letter queue for manual inspection and replay.

No delivery logs or monitoring

The Problem: WordPress.com provides no visibility into webhook delivery status. There is no log of sent webhooks, no record of success or failure, no response codes, and no timestamps. If a webhook stops working, you'll only find out when the downstream integration breaks.

Why It Happens: The WordPress.com webhook UI is minimal — it provides a configuration interface but no operational visibility. Unlike WooCommerce, which stores delivery logs, the native WordPress.com system has no logging layer.

Workarounds:

  • Implement logging on your receiving endpoint to track all incoming webhook deliveries.
  • Set up uptime monitoring on your webhook endpoint.
  • Build a reconciliation check that compares received webhooks against known site activity.
  • Use a request inspection tool during development to verify payloads are being sent.

How Hookdeck Can Help: Hookdeck's dashboard provides full visibility into every webhook delivery, including request and response payloads, HTTP status codes, latency, retry attempts, and error details. Set up alerts to be notified immediately when deliveries fail, giving you the observability that WordPress.com's native system lacks entirely.

Synchronous delivery impacts site performance

The Problem: WordPress.com's webhook system makes HTTP requests synchronously during the WordPress action lifecycle. This means that when a post is published, the webhook HTTP request is made before the publish action completes. A slow or unresponsive endpoint can delay the user experience on the WordPress.com site itself.

Why It Happens: HookPress hooks into WordPress actions and fires HTTP requests inline. Unlike WooCommerce's webhooks (which use Action Scheduler for asynchronous delivery), there is no background processing layer.

Workarounds:

  • Ensure your endpoint responds within milliseconds — acknowledge receipt immediately and process asynchronously.
  • Never perform slow operations (database writes, API calls, file processing) before returning a response.
  • Use a lightweight intermediary that accepts the webhook instantly and queues processing.

How Hookdeck Can Help: Pointing your WordPress.com webhooks at Hookdeck means the HTTP request resolves almost instantly (Hookdeck's ingestion endpoint is optimised for fast acknowledgment). The webhook data is then delivered asynchronously to your actual endpoint, decoupling WordPress.com's publish action from your processing time.

Sparse comment_post payload

The Problem: The comment_post action provides comment_post_ID (the numeric ID of the parent post) but not the post title, URL, or any other post metadata. Most comment notification integrations need to know which post received the comment, forcing developers to make additional API calls.

Why It Happens: The webhook exposes the raw fields from WordPress's wp_comments database table. The parent post's ID is stored in the comments table, but its title and URL are not — those live in the wp_posts table.

Workarounds:

  • Call the WordPress.com REST API (/rest/v1.1/sites/{site}/posts/{id}) to fetch post details when processing comment webhooks.
  • Maintain a local cache of post ID-to-title/URL mappings to reduce API calls.
  • Use a transformation layer that enriches the payload before it reaches your application.

How Hookdeck Can Help: Use Hookdeck's transformation feature to enrich the webhook payload in-flight. A transformation can call the WordPress.com REST API to fetch the parent post's title and URL, then include those fields in the payload before delivering it to your endpoint, eliminating the need for your application to handle the enrichment.

No API or infrastructure-as-code support

The Problem: WordPress.com webhooks can only be configured through the admin UI. There is no REST API, CLI tool, or provisioning file for managing webhooks programmatically. This makes it impossible to version-control webhook configurations, automate setup across multiple sites, or manage webhooks as part of a CI/CD pipeline.

Why It Happens: The webhook feature is a lightweight addition to the WordPress.com admin, not a full-featured platform integration. It predates modern infrastructure-as-code practices.

Workarounds:

  • Document webhook configurations manually and include setup steps in your deployment runbooks.
  • For multi-site management, consider switching to self-hosted WordPress where plugins like WP Webhooks offer API-based configuration.
  • Use screenshots or exports of webhook settings as part of your configuration documentation.

How Hookdeck Can Help: While WordPress.com's webhook creation remains manual, the receiving side can be fully managed through Hookdeck's API and Terraform provider. Define your connections, transformations, filters, and destinations as code, even if the source webhook configuration is manual.

Testing WordPress.com webhooks

Use a request inspector

Before building your handler, inspect actual WordPress.com webhook payloads to understand their structure:

  1. Create a temporary inspection URL using Hookdeck Console or a similar tool.
  2. Configure a WordPress.com webhook pointing to that URL.
  3. Trigger the action (publish a test post, submit a test comment).
  4. Inspect the payload format, fields, and headers.

This is especially important because WordPress.com's documentation doesn't include example payloads, so the only way to see exactly what your endpoint will receive is to trigger a real delivery.

Trigger real events

WordPress.com does not include a "Test" button for webhooks. You must trigger real events to test delivery:

  • publish_post: Create and publish a test post, or edit an already-published post.
  • publish_page: Create and publish a test page.
  • comment_post: Submit a comment on any post (you may want to do this from a separate browser/account to simulate a real commenter).

Validate end-to-end

Test the full chain, not just payload receipt:

  1. Trigger the event on WordPress.com.
  2. Verify your endpoint received the webhook (check your request inspector or application logs).
  3. Confirm the downstream action completed (Slack notification sent, database updated, pipeline triggered).
  4. Test failure scenarios — what happens if your endpoint is down? What happens if you return a 500?

Since WordPress.com has no retry logic, any delivery failure during testing reveals exactly what will happen in production: the event is lost.

Self-hosted WordPress alternatives

If WordPress.com's three action hooks and lack of security don't meet your needs, self-hosted WordPress offers significantly more webhook capability:

WP Webhooks plugin — Supports 100+ triggers, multiple payload formats (JSON, XML, form-encoded), API key and Bearer token authentication, and extensive logging. Available as a free plugin with a Pro tier for advanced features.

WooCommerce webhooks — Built into WooCommerce with 15+ pre-defined topics, HMAC-SHA256 signing via the X-WC-Webhook-Signature header, Action Scheduler-based asynchronous delivery, and delivery logs. See our Guide to WooCommerce Webhooks for full details.

Custom webhook implementations — Self-hosted WordPress allows you to hook into any WordPress action or filter and send custom HTTP requests using wp_remote_post(), giving you complete control over payload format, headers, authentication, and delivery logic.

Conclusion

WordPress.com webhooks provide a basic mechanism for integrating your WordPress.com site with external systems. For simple use cases (notifying a Slack channel when a new post goes live, or logging comments to an external system) the native webhook system can work with appropriate safeguards in place.

However, the limitations are significant. The absence of payload signing means you can't verify webhook authenticity without workarounds. Only three action hooks are available, covering a fraction of the events developers typically need. There are no retries, no delivery logs, and no programmatic configuration. The synchronous delivery model means slow endpoints can impact your site's performance.

For simple sites with straightforward notification needs and reliable endpoints, WordPress.com's built-in webhooks combined with proper endpoint authentication and fast response handling may be sufficient. For production integrations where reliability, security, and observability matter, webhook infrastructure like Hookdeck can address WordPress.com's limitations by providing HMAC-signed delivery, automatic retries with configurable backoff, payload transformation, dead-letter queues, and comprehensive delivery monitoring without requiring changes to your WordPress.com configuration.


Gareth Wilson

Gareth Wilson

Product Marketing

Multi-time founding marketer, Gareth is PMM at Hookdeck and author of the newsletter, Community Inc.