How to Use Xray-core Built-in API for Runtime Traffic Statistics and User Management
The Xray-core built-in API is a gRPC-based interface that enables runtime traffic monitoring, user management, and system statistics without restarting the proxy server.
This comprehensive guide walks you through enabling the Xray-core built-in API, using the bundled CLI tools for traffic statistics and user operations, and building custom Go clients. All information is derived directly from the XTLS/Xray-core source code.
Enabling the Xray-core Built-in API
The built-in API is disabled by default. To activate it, add an api configuration section to your Xray JSON or YAML config file.
Minimal API Configuration
{
"api": {
"tag": "api",
"listen": "127.0.0.1:8080",
"services": [
"StatsService",
"HandlerService"
]
}
}
Configuration Parameters
| Field | Type | Default | Description |
|---|---|---|---|
tag |
string | "api" |
Tag used to identify API traffic in routing rules |
listen |
string | "127.0.0.1:8080" |
gRPC listener address (use 0.0.0.0 for remote access) |
services |
array | all | List of service names to register; omit to enable all |
Available API Services
The following services can be enabled in the services array:
- StatsService — Query traffic counters, system stats, and online users
- HandlerService — Manage inbounds, outbounds, and users
- ReflectionService — gRPC reflection for tools like
grpcurl - LogService — Change log levels at runtime
- ObservatoryService — Probe remote nodes
- RouterService — Inspect routing configuration
Source Code Reference
The API configuration parsing is implemented in [infra/conf/api.go](https://github.com/XTLS/Xray-core/blob/main/infra/conf/api.go). The APIConfig struct converts to a commander.Config defined in [app/commander/config.pb.go](https://github.com/XTLS/Xray-core/blob/main/app/commander/config.pb.go).
Using the Bundled CLI for Traffic Statistics
Xray-core includes ready-to-use CLI commands under main/commands/all/api/. These wrap the gRPC API calls and output formatted JSON.
Common CLI Flags
All API commands support these flags defined in [main/commands/all/api/shared.go](https://github.com/XTLS/Xray-core/blob/main/main/commands/all/api/shared.go):
| Flag | Shorthand | Default | Description |
|---|---|---|---|
--server |
-s |
127.0.0.1:8080 |
API server address |
--timeout |
-t |
3s |
RPC timeout |
--json |
(none) | Output raw JSON instead of formatted tables |
System Statistics
# Get CPU, memory, and uptime statistics
xray api statssys
This command calls StatsService.GetSysStats implemented in [main/commands/all/api/stats_sys.go](https://github.com/XTLS/Xray-core/blob/main/main/commands/all/api/stats_sys.go).
Query Traffic Counters
# List all counters containing "uplink"
xray api statsquery -pattern "uplink"
# Query all counters and reset them atomically
xray api statsquery -pattern "" -reset
# Query counters for a specific user
xray api statsquery -pattern "user@example.com"
Traffic counter names follow the pattern inbound>>>TAG>>>traffic>>>uplink or outbound>>>TAG>>>traffic>>>downlink. The implementation is in [main/commands/all/api/stats_query.go](https://github.com/XTLS/Xray-core/blob/main/main/commands/all/api/stats_query.go).
Monitor Online Users
# List all inbound tags with active connections
xray api statsonline
# Show IPs of a specific online user with traffic details
xray api statsonlineiplist -email user@example.com -all -include-traffic
These commands identify active connections without requiring traffic counters to be enabled. Source: [stats_online.go](https://github.com/XTLS/Xray-core/blob/main/main/commands/all/api/stats_online.go) and [stats_online_ip_list.go](https://github.com/XTLS/Xray-core/blob/main/main/commands/all/api/stats_online_ip_list.go).
Using the Bundled CLI for Runtime User Management
The HandlerService enables adding, removing, and querying users without restarting Xray.
Add Users to an Inbound
# Add users from JSON files to their respective inbounds
xray api adi users.json
The adi (add inbound users) command accepts one or more JSON files. Each file contains an array of user objects with tag specifying the target inbound. The implementation in [inbound_user_add.go](https://github.com/XTLS/Xray-core/blob/main/main/commands/all/api/inbound_user_add.go) uses the extractInboundUsers function to parse VMess, VLESS, Trojan, and Shadowsocks user formats.
Example users.json:
[
{
"tag": "vless-in",
"users": [
{
"email": "newuser@example.com",
"id": "a1b2c3d4-1111-2222-3333-444455556666",
"level": 0
}
]
}
]
Remove Users from an Inbound
# Remove specific users by email from a tagged inbound
xray api rmu -tag=vless-in olduser@example.com another@example.com
The rmu (remove inbound users) command calls HandlerService.AlterInbound with RemoveUserOperation. Source: [inbound_user_remove.go](https://github.com/XTLS/Xray-core/blob/main/main/commands/all/api/inbound_user_remove.go).
Query Inbound Users
# List all users attached to an inbound
xray api inbounduser -tag=vless-in
# Query a specific user by email
xray api inbounduser -tag=vless-in -email=user@example.com
Source: [inbound_user.go](https://github.com/XTLS/Xray-core/blob/main/main/commands/all/api/inbound_user.go).
Count Inbound Users
# Get the total number of users for an inbound
xray api inboundusercount -tag=vless-in
Source: [inbound_user_count.go](https://github.com/XTLS/Xray-core/blob/main/main/commands/all/api/inbound_user_count.go).
Building Custom Go Clients for the Xray-core Built-in API
For integration into custom tooling, import the generated protobuf packages and use the gRPC stubs directly.
Required Imports
import (
statspb "github.com/xtls/xray-core/app/stats/command"
handlerpb "github.com/xtls/xray-core/app/proxyman/command"
"github.com/xtls/xray-core/common/protocol"
)
Complete Example: Query Stats and Add Users
package main
import (
"context"
"log"
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
statspb "github.com/xtls/xray-core/app/stats/command"
handlerpb "github.com/xtls/xray-core/app/proxyman/command"
"github.com/xtls/xray-core/common/protocol"
)
func main() {
// -------------------------------------------------
// 1️⃣ Connect to the Xray API (default 127.0.0.1:8080)
// -------------------------------------------------
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
conn, err := grpc.DialContext(
ctx,
"127.0.0.1:8080",
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithBlock(),
)
if err != nil {
log.Fatalf("dial error: %v", err)
}
defer conn.Close()
// -------------------------------------------------
// 2️⃣ Query all stats that start with "counter_"
// -------------------------------------------------
statsClient := statspb.NewStatsServiceClient(conn)
resp, err := statsClient.QueryStats(ctx, &statspb.QueryStatsRequest{
Pattern: "counter_",
Reset_: false,
})
if err != nil {
log.Fatalf("query stats error: %v", err)
}
log.Printf("Stats: %+v", resp)
// -------------------------------------------------
// 3️⃣ Add a new VMess user to inbound tag "vless-in"
// -------------------------------------------------
handlerClient := handlerpb.NewHandlerServiceClient(conn)
newUser := &protocol.User{
Email: "new@example.com",
Level: 0,
// the UUID string is parsed internally by VMess
Id: &protocol.User_Uuid{Uuid: "a1b2c3d4-1111-2222-3333-444455556666"},
}
_, err = handlerClient.AlterInbound(ctx, &handlerpb.AlterInboundRequest{
Tag: "vless-in",
Operation: &handlerpb.AlterInboundRequest_AddUser{
AddUser: &handlerpb.AddUserOperation{User: newUser},
},
})
if err != nil {
log.Fatalf("add user error: %v", err)
}
log.Println("User added successfully")
}
Protocol Buffer Definitions
| Service | Proto File | Generated Go File |
|---|---|---|
| StatsService | app/stats/command/command.proto |
[app/stats/command/command.pb.go](https://github.com/XTLS/Xray-core/blob/main/app/stats/command/command.pb.go) |
| HandlerService | app/proxyman/command/command.proto |
[app/proxyman/command/command.pb.go](https://github.com/XTLS/Xray-core/blob/main/app/proxyman/command/command.pb.go) |
Security Considerations for the Xray-core Built-in API
The API grants full control over proxy configuration and user data. Follow these guidelines:
- Bind to localhost by default — Use
127.0.0.1:8080unless remote access is required - Use TLS for remote access — Configure gRPC TLS credentials when exposing beyond localhost
- Restrict service exposure — Enable only the services you need in the
servicesarray - Monitor access logs — The API tag appears in access logs like any other inbound
Summary
The Xray-core built-in API provides a production-ready gRPC interface for runtime traffic statistics and user management without proxy restarts.
- Enable the API by adding an
apisection to your config with desired services - Use bundled CLI commands under
xray apifor quick operational tasks - Query traffic statistics via
StatsServicewith patterns likecounter_or specific user emails - Manage users dynamically via
HandlerServiceto add, remove, and query VMess, VLESS, Trojan, and Shadowsocks users - Build custom integrations using the generated protobuf stubs in
app/stats/commandandapp/proxyman/command
Frequently Asked Questions
How do I enable traffic statistics in Xray-core?
Traffic statistics require two configuration steps: enable the StatsService in the api section, and add a stats object to your root configuration. Without the stats object, counters exist but remain at zero. The CLI xray api statsquery will return empty results if statistics aren't properly enabled.
What is the difference between statsonline and statsonlineiplist?
xray api statsonline returns inbound tags that have active connections, useful for quick health checks. xray api statsonlineiplist provides granular data including specific IP addresses per user email, with optional traffic counters. Use statsonline for monitoring dashboards and statsonlineiplist for detailed user session tracking.
Can I add users without restarting Xray-core?
Yes, this is a primary benefit of the built-in API. Use xray api adi with a JSON file containing user definitions, or call HandlerService.AlterInbound directly with AddUserOperation. The change takes effect immediately for new connections without dropping existing ones. Removed users via xray api rmu are disconnected at the protocol level.
How do I query statistics for a specific user?
Use xray api statsquery with a pattern matching the user's email. Xray-core creates counter names following the pattern inbound>>>TAG>>>traffic>>>uplink and user>>>EMAIL>>>traffic>>>uplink. For user-specific queries, use patterns like user>>>user@example.com or broader patterns like >>>user@example.com>>>.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →