Chain Sink
An open-source binary that reads Event Streaming over WebSocket and writes it into storage you control.
Chain Sink is a single Go binary. It consumes Event Streaming data over a WebSocket connection and forwards it, unmodified, to a storage adapter. Use it when events need to land in infrastructure Blockdaemon doesn't have access to, instead of being delivered to a webhook endpoint or consumed directly in application code.
graph LR
A[Event Streaming - WebSocket] --> B[Chain Sink]
B --> C[Storage Adapter]
C --> D[stdout]
C --> E[Kafka]
Installing and running
Chain Sink is built with make build-linux or make build-darwin. This produces a chain_sink_linux_amd64 or chain_sink_darwin_arm64 binary. Release builds are packaged and published automatically on each release. No container image is provided. It runs as a standalone binary.
Configuration
Configuration is a YAML file. Values can be overridden by environment variables prefixed BD_. The config file path is set with the BD_CONFIG_FILES environment variable.
stream:
url: "wss://svc.blockdaemon.com/streaming/v2/targets/<target_id>/websocket"
api_key: "<API_KEY>"
mode: "noack"
headers:
BD-Org-ID: "<org_id>"
adapter:
type: "kafka"
kafka:
producer:
brokers: ["localhost:9092"]
topic: "chain-events"stream.url must match the same target WebSocket path used elsewhere, .../streaming/v2/targets/{target_id}/websocket. stream.api_key is required when connecting to svc.blockdaemon.com. It's sent as an x-api-key header, not Authorization: Bearer. This differs from how the API key is passed on a direct WebSocket connection made without Chain Sink. stream.mode is ack or noack, matching the same target setting described in WebSocket Streaming. Custom headers, for example BD-Org-ID, can also be set under stream.headers.
Supported storage adapters
Two adapters exist. stdout prints each message to the console. kafka produces each message to a configured topic. There's no Postgres, S3, or file adapter.
Message handling
Each message is forwarded to the adapter as the raw, unmodified bytes received over the WebSocket connection. The same envelope and templates (ALL_DATA, UNIFIED_V1, UNIFIED_V1_RAW) documented for WebSocket Streaming reach the adapter untouched. In ack mode, Chain Sink parses just enough of the message to read its id field for acknowledgment purposes. The payload delivered to the adapter isn't affected by this.
Failure handling
On a WebSocket read or write error, Chain Sink reestablishes the connection automatically for closed-connection and EOF errors. There's no configurable backoff or retry limit, reconnection happens immediately. There's no local buffering or dead-letter mechanism. If the Kafka adapter fails to deliver a message, the failure is logged and Kafka's own client-level retry behavior applies. In ack mode, a failed handoff to the adapter means no acknowledgment is sent for that message.
👋 Need Help?
Contact us through email or our support page for any issues, bugs, or assistance you may need.
Updated about 19 hours ago
