# How the Xray-core Router Webhook Works and When to Use It

> Learn how the Xray-core router webhook feature works. Send real-time JSON POST requests on rule matches for external monitoring and automated responses without blocking traffic.

- Repository: [Project X Community, Not Porn-jet X Hub/Xray-core](https://github.com/XTLS/Xray-core)
- Tags: deep-dive
- Published: 2026-04-21

---

**Xray-core’s router webhook asynchronously sends a JSON POST request to a configured URL whenever a connection matches a specific routing rule, enabling real-time external monitoring and automated responses without blocking traffic flow.**

The Xray-core router webhook feature allows operators to attach HTTP callbacks to routing rules for real-time event notification. When a connection matches a rule configured with a webhook, Xray-core immediately dispatches a JSON payload containing connection metadata to the specified endpoint. This capability, implemented in the `app/router` package of the XTLS/Xray-core repository, enables integration with external monitoring systems, SIEM tools, and automated response workflows.

## Architecture and Implementation

The webhook functionality spans three distinct layers in the codebase:

### Configuration Layer

**`WebhookConfig`** in [`app/router/config.proto`](https://github.com/XTLS/Xray-core/blob/main/app/router/config.proto) and the generated struct in [[`app/router/config.pb.go`](https://github.com/XTLS/Xray-core/blob/main/app/router/config.pb.go)](https://github.com/XTLS/Xray-core/blob/main/app/router/config.pb.go) declare the webhook URL, optional deduplication interval, and custom HTTP headers. The JSON/YAML parsing occurs in [[`infra/conf/router.go`](https://github.com/XTLS/Xray-core/blob/main/infra/conf/router.go)](https://github.com/XTLS/Xray-core/blob/main/infra/conf/router.go) via `WebhookRuleConfig`.

### Rule Handling Layer

During router startup, [[`app/router/router.go`](https://github.com/XTLS/Xray-core/blob/main/app/router/router.go)](https://github.com/XTLS/Xray-core/blob/main/app/router/router.go) (lines 68‑82 and 175‑182) parses the configuration and creates a **`WebhookNotifier`** for each rule that defines a webhook. The notifier stores an `http.Client`, a deduplication map, and a `done` channel for graceful shutdown.

### Notifier Execution Layer

The [[`app/router/webhook.go`](https://github.com/XTLS/Xray-core/blob/main/app/router/webhook.go)](https://github.com/XTLS/Xray-core/blob/main/app/router/webhook.go) file contains the core **`WebhookNotifier`** implementation. This component builds event payloads, manages optional deduplication logic, and executes HTTP POST requests. It supports both standard TCP endpoints and Unix domain sockets through custom URL parsing.

## How the Webhook Triggering Process Works

When a connection traverses the Xray-core router, the webhook fires through a precise seven-stage pipeline:

1. **Rule Definition** – The `RoutingRule` protobuf includes a `webhook` field (see `WebhookConfig`). In JSON configuration, this appears under the `"webhook"` key within a routing rule object.

2. **Router Initialization** – While loading rules, [`router.go`](https://github.com/XTLS/Xray-core/blob/main/router.go) invokes `NewWebhookNotifier(cfg)` for each rule containing webhook configuration. This initializes the HTTP client and internal state.

3. **Connection Matching** – When `PickRoute` selects a rule for an incoming connection, it checks `rule.Webhook != nil` and calls `rule.Webhook.Fire(originalCtx, tag)`.

4. **Event Construction** – The `buildEvent` function (lines 67‑81 in [`webhook.go`](https://github.com/XTLS/Xray-core/blob/main/webhook.go)) extracts data from the routing context, including source IP/port, destination, protocol, inbound/outbound tags, user email, and timestamps, populating an `event` struct.

5. **Deduplication Check** – If `deduplication > 0` is configured, the notifier stores the user email and discards subsequent events from the same identity within the configured TTL window.

6. **HTTP Dispatch** – The `post` method marshals the event to JSON, constructs an HTTP request with `Content-Type: application/json`, injects custom headers, and transmits the payload. For Unix sockets, `parseURL` and `resolveSocketPath` configure the transport to dial the socket path (e.g., `/tmp/socket.sock:/path`) instead of TCP.

7. **Resource Cleanup** – When a rule reloads or the router shuts down, the `Close` method stops background cleanup goroutines, waits for pending posts to complete, and closes idle connections.

## When to Use the Xray-core Router Webhook

Deploy webhooks when you require real-time external visibility into routing decisions without modifying core proxy behavior:

- **External Monitoring and Alerting** – Forward connection metadata to Prometheus pushgateway, Grafana Loki, or custom SIEM platforms for real-time visibility into traffic patterns.

- **Automated Security Responses** – Trigger scripts that update blocklists or modify firewall rules when specific patterns emerge, such as connections from particular users, destinations, or protocols.

- **Audit Logging** – Stream every permitted or denied connection to an immutable log store, Elasticsearch cluster, or SIEM without relying on Xray’s internal logging facilities.

- **Third-Party Service Integration** – Notify Discord or Slack channels, trigger webhook-compatible CI/CD pipelines, or invoke cloud functions for additional processing when specific routes activate.

- **Load Balancer Health Checks** – Send lightweight pings to health-check endpoints whenever traffic passes through critical routing rules to validate upstream availability.

The webhook executes **asynchronously** and never blocks the routing decision, ensuring safe deployment in high-throughput environments. The optional deduplication mechanism prevents event flooding when individual users generate many concurrent connections.

## Configuration Examples

### Standard HTTP Webhook

Configure a routing rule with a webhook that posts to an HTTP endpoint with deduplication enabled:

```json
{
  "type": "field",
  "outboundTag": "proxy",
  "domain": ["example.com"],
  "webhook": {
    "url": "http://192.168.1.100:8080/xray/webhook",
    "deduplication": 30,
    "headers": {
      "X-Auth-Token": "my-secret-token"
    }
  }
}

```

When connections to `example.com` route through the `proxy` outbound, Xray-core POSTs a JSON event to the specified URL. Duplicate events from the same email address within 30 seconds are suppressed.

### Unix Socket Webhook

For local integration with services like HAProxy, use Unix domain sockets with the `socketPath:/http/path` syntax:

```json
{
  "type": "field",
  "outboundTag": "proxy",
  "sourceIP": ["10.0.0.0/8"],
  "webhook": {
    "url": "/var/run/haproxy.sock:/v2/events",
    "deduplication": 0
  }
}

```

The `parseURL` function in [`webhook.go`](https://github.com/XTLS/Xray-core/blob/main/webhook.go) detects the Unix socket prefix and configures the HTTP transport to dial `/var/run/haproxy.sock` while posting to the `/v2/events` path.

### Go Webhook Receiver

Implement a minimal HTTP server to receive and process Xray-core webhook events:

```go
package main

import (
	"encoding/json"
	"log"
	"net/http"
)

type XrayEvent struct {
	Email          *string `json:"email"`
	Level          *uint32 `json:"level"`
	Protocol       *string `json:"protocol"`
	Network        *string `json:"network"`
	Source         *string `json:"source"`
	Destination    *string `json:"destination"`
	InboundTag     *string `json:"inboundTag"`
	OutboundTag    *string `json:"outboundTag"`
	Timestamp      int64   `json:"ts"`
}

func handler(w http.ResponseWriter, r *http.Request) {
	var ev XrayEvent
	if err := json.NewDecoder(r.Body).Decode(&ev); err != nil {
		http.Error(w, "bad request", http.StatusBadRequest)
		return
	}
	log.Printf("Xray event: %+v\n", ev)
	w.WriteHeader(http.StatusOK)
}

func main() {
	http.HandleFunc("/xray/webhook", handler)
	log.Fatal(http.ListenAndServe(":8080", nil))
}

```

This handler decodes the same JSON structure constructed in [`webhook.go`](https://github.com/XTLS/Xray-core/blob/main/webhook.go) (lines 67‑81), allowing you to extract connection metadata for logging or further processing.

## Summary

- **Xray-core router webhooks** provide asynchronous HTTP callbacks triggered by routing rule matches, implemented in [`app/router/webhook.go`](https://github.com/XTLS/Xray-core/blob/main/app/router/webhook.go) and integrated via [`app/router/router.go`](https://github.com/XTLS/Xray-core/blob/main/app/router/router.go).
- The feature supports **custom HTTP headers**, **deduplication intervals**, and **Unix domain sockets** for flexible deployment scenarios.
- Webhooks execute **non-blocking** POST requests containing JSON payloads with source, destination, protocol, user, and tag information.
- Ideal use cases include **real-time monitoring**, **automated security responses**, **audit logging**, and **third-party service integration**.
- Configuration requires defining a `webhook` object within routing rules in [`infra/conf/router.go`](https://github.com/XTLS/Xray-core/blob/main/infra/conf/router.go) compatible JSON/YAML syntax.

## Frequently Asked Questions

### What happens if the webhook endpoint is unavailable?

Xray-core executes webhooks asynchronously and does not retry failed requests. If the HTTP POST fails or the endpoint is unreachable, the error is logged internally but the routing decision proceeds normally. For reliable delivery, implement a queuing mechanism on the receiver side or use a local Unix socket with a persistent listener.

### Can I use HTTPS endpoints with custom certificates?

Yes. The `WebhookNotifier` uses a standard Go `http.Client`. For custom TLS configurations, you would need to modify the transport configuration in [`app/router/webhook.go`](https://github.com/XTLS/Xray-core/blob/main/app/router/webhook.go) or ensure the Xray-core process trusts the certificate authority through the system certificate pool.

### How does deduplication work with multiple users?

The deduplication mechanism keys events by **user email** (specifically the `email` field in the connection context). When `deduplication` is set to a positive integer (seconds), the notifier stores a timestamp for each email and discards subsequent events from that same email until the TTL expires. This prevents flooding from high-connection-count users while still capturing distinct user activity.

### Does the webhook feature impact proxy performance?

No. The webhook fires **asynchronously** in a separate goroutine and never blocks the main routing path in `PickRoute`. The HTTP POST operation occurs after the routing decision is complete, ensuring zero latency impact on connection processing. However, high event volumes may increase memory usage due to goroutine creation and JSON marshaling overhead.