Run Chainhook as a service

Deploy Chainhook as a service for real-time blockchain event streaming with Bitcoin and Stacks nodes.

This guide shows you how to run Chainhook as a service for continuous monitoring of blockchain events. You'll learn how to configure Chainhook with both Bitcoin and Stacks nodes, manage predicates dynamically, and optimize for production deployments.

Basic service setup

Start Chainhook as a service using a configuration file:

Terminal
$
chainhook service start --config-path=./Chainhook.toml

The service connects to your blockchain nodes and begins monitoring for events that match your registered predicates.

Minimal configuration

Chainhook.toml
[storage]
working_dir = "/var/chainhook"
[network]
mode = "mainnet"
[limits]
max_number_of_bitcoin_predicates = 100
max_number_of_stacks_predicates = 10

Bitcoin node configuration

Configure Chainhook to work with a Bitcoin node for monitoring Bitcoin events:

Chainhook.toml
[network]
mode = "mainnet"
bitcoind_rpc_url = "http://localhost:8332"
bitcoind_rpc_username = "devnet"
bitcoind_rpc_password = "devnet"
# Option 1: Receive events via ZeroMQ (recommended for Bitcoin-only)
bitcoind_zmq_url = "tcp://0.0.0.0:18543"
# Option 2: Receive events via Stacks node (if running both chains)
# stacks_node_rpc_url = "http://localhost:20443"

Bitcoin configuration mapping

bitcoin.confChainhook.toml
rpcuserbitcoind_rpc_username
rpcpasswordbitcoind_rpc_password
rpcportbitcoind_rpc_url
zmqpubhashblockbitcoind_zmq_url

Stacks node configuration

For monitoring Stacks events, configure both the Stacks node and Chainhook:

Stacks node setup

Stacks.toml
[node]
working_dir = "/stacks-blockchain"
rpc_bind = "0.0.0.0:20443"
p2p_bind = "0.0.0.0:20444"
[burnchain]
chain = "bitcoin"
mode = "mainnet"
peer_host = "localhost"
username = "devnet" # Must match bitcoin.conf rpcuser
password = "devnet" # Must match bitcoin.conf rpcpassword
rpc_port = 8332 # Must match bitcoin.conf rpcport
[[events_observer]]
endpoint = "localhost:20455"
retry_count = 255
events_keys = ["*"]

Chainhook configuration for Stacks

Chainhook.toml
[network]
mode = "mainnet"
bitcoind_rpc_url = "http://localhost:8332"
bitcoind_rpc_username = "devnet"
bitcoind_rpc_password = "devnet"
stacks_node_rpc_url = "http://localhost:20443"
stacks_events_ingestion_port = 20455

Predicate management

Register predicates with the service to start monitoring for specific events.

Start with predicates

Terminal
$
chainhook service start --predicate-path=my-predicate.json --config-path=Chainhook.toml

Register multiple predicates

Terminal
$
chainhook service start \
--predicate-path=bitcoin-predicate.json \
--predicate-path=stacks-predicate.json \
--config-path=Chainhook.toml

Dynamic registration

Enable the HTTP API to register predicates while the service is running:

Chainhook.toml
[http_api]
http_port = 20456
database_uri = "redis://localhost:6379/"

Register a new predicate via API:

Terminal
$
curl -X POST http://localhost:20456/v1/chainhooks \
-H "Content-Type: application/json" \
-d @predicate.json
{"result":"f8d43129-dba1-4a6c-b368-21426de0f3cd","status":200}

Service monitoring

Monitor the health and status of your Chainhook service.

Health check

Terminal
$
curl http://localhost:20456/health
{
"status": "healthy",
"stacks_node": "connected",
"bitcoin_node": "connected",
"database": "connected",
"predicates_active": 3
}

Service status

Terminal
$
chainhook service status

View logs

Terminal
$
chainhook service logs --tail 50

Predicate examples

Create predicates to monitor specific blockchain events.

Bitcoin predicate

bitcoin-transfers.json
{
"chain": "bitcoin",
"uuid": "1",
"name": "Bitcoin P2WPKH Monitor",
"version": 1,
"networks": {
"mainnet": {
"start_block": 800000,
"if_this": {
"scope": "outputs",
"p2wpkh": {
"equals": "bc1qexampleaddress"
}
},
"then_that": {
"http_post": {
"url": "http://localhost:3000/api/bitcoin-events",
"authorization_header": "Bearer secret-token"
}
}
}
}
}

Stacks predicate

stacks-events.json
{
"chain": "stacks",
"uuid": "2",
"name": "Contract Event Monitor",
"version": 1,
"networks": {
"mainnet": {
"start_block": 100000,
"if_this": {
"scope": "print_event",
"contract_identifier": "SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.arkadiko-dao",
"contains": "liquidation"
},
"then_that": {
"http_post": {
"url": "http://localhost:3000/api/stacks-events",
"authorization_header": "Bearer secret-token"
}
}
}
}
}

Production configuration

Optimize Chainhook for production deployments with enhanced performance and reliability settings.

Performance tuning

Chainhook-production.toml
[storage]
working_dir = "/var/chainhook"
[http_api]
http_port = 20456
database_uri = "redis://redis-cluster:6379/"
[network]
mode = "mainnet"
bitcoind_rpc_url = "http://bitcoin-node:8332"
bitcoind_rpc_username = "${BITCOIN_RPC_USER}"
bitcoind_rpc_password = "${BITCOIN_RPC_PASS}"
stacks_node_rpc_url = "http://stacks-node:20443"
[limits]
max_number_of_bitcoin_predicates = 100
max_number_of_concurrent_bitcoin_scans = 100
max_number_of_stacks_predicates = 50
max_number_of_concurrent_stacks_scans = 50
max_number_of_processing_threads = 16
max_number_of_networking_threads = 16
max_caching_memory_size_mb = 32000
[cache]
block_cache_size = 1000
transaction_cache_size = 10000
[http_api]
webhook_timeout = 10
retry_count = 3

High availability setup

Run multiple instances with shared state:

Chainhook-ha.toml
[http_api]
database_uri = "redis://redis-cluster:6379"
[cluster]
instance_id = "chainhook-1"
lock_timeout = 30

Deploy behind a load balancer for redundancy:

nginx.conf
upstream chainhook_backend {
server chainhook-1:20456;
server chainhook-2:20456;
server chainhook-3:20456;
}
server {
location /v1/chainhooks {
proxy_pass http://chainhook_backend;
}
}

Further reading