wss://api.viz.cx/ws/ops emits a message for every operation applied to the chain within ~5 blocks of the tip. This makes it easy to react to live awards, transfers, and other events without polling.
Step 1 — Connect and log all operations
Each message is a JSON-encoded operation record. The op field is a [type, data] tuple, e.g. ['award', { initiator: 'alice', receiver: 'bob', energy: 100 }].
const ws = new WebSocket('wss://api.viz.cx/ws/ops')
ws.onopen = () => console.log('connected')
ws.onmessage = (event) => {
const item = JSON.parse(event.data)
// item shape:
// { trx_id, block, trx_in_block, op_in_trx, virtual_op, timestamp, op }
const [opType, opData] = item.op
console.log(item.timestamp, opType, opData)
}
ws.onclose = () => console.log('disconnected')
ws.onerror = (e) => console.error('ws error', e)Step 2 — Filter by operation type
Most apps care about a subset of op types. Filter by checking opType. Common types: award, transfer, account_create, delegate_vesting_shares.
ws.onmessage = (event) => {
const item = JSON.parse(event.data)
const [opType, opData] = item.op
// Only react to award operations
if (opType !== 'award') return
console.log(
`${opData.initiator} awarded ${opData.receiver}`,
`energy: ${opData.energy / 100}%`,
opData.memo ?? ''
)
}Step 3 — Add reconnect logic
WebSocket connections drop. A simple 3-second retry on onclose is sufficient for most use cases.
function connect() {
const ws = new WebSocket('wss://api.viz.cx/ws/ops')
ws.onmessage = (event) => {
const item = JSON.parse(event.data)
const [opType, opData] = item.op
if (opType === 'award') {
console.log(`award: ${opData.initiator} → ${opData.receiver}`)
}
}
ws.onclose = () => {
console.log('reconnecting in 3s…')
setTimeout(connect, 3000)
}
ws.onerror = () => ws.close()
return ws
}
const ws = connect()