Getting Started

Cryptowatch offers a real-time WebSocket API for streaming normalized cryptocurrency market data. The API offers trades, order books, candlesticks, and more across 26 supported exchanges.

You need a Cryptowatch Account to access the WebSocket API. Click here to create an account.

Once you have an account, you can generate an API key in the My Account > API Access section. You only need your public key for this API.

Connect with your api key:

wss://stream.cryptowat.ch/connect?apikey=YOUR-API-KEY

Basic Code Examples

Below are bare minimum examples using no outside packages except for a WebSocket library. These examples connect to the API and print a live feed of all BTC/USD trades. The resource for that is instruments:9:trades. You can read more about resources here.

JavaScript
Go
Bash
const WebSocket = require('ws');
// Initialize a connection using your API key
// You can generate an API key here: https://cryptowat.ch/account/api-access
// Paste your API key here:
const API_KEY = 'XT11G0PE8VX02ZZ49RUR';
var conn = new WebSocket('wss://stream.cryptowat.ch/connect?apikey='+API_KEY);
conn.on('message', function (msg) {
const d = JSON.parse(msg.toString());
// The server will always send an AUTHENTICATED signal when you establish a valid connection
// At this point you can subscribe to resources
if (d.authenticationResult && d.authenticationResult.status === 'AUTHENTICATED') {
subscribeTo(conn, ['instruments:9:trades']);
}
// Market data comes in a marketUpdate
// In this case, we're expecting trades so we look for marketUpdate.tradesUpdate
if (d.marketUpdate && d.marketUpdate.tradesUpdate) {
for (let trade of d.marketUpdate.tradesUpdate.trades) {
console.log(`BTC/USD trade on market ${d.marketUpdate.market.marketId}: ${trade.timestampNano} ${trade.priceStr} ${trade.amountStr}`);
// That's it! It's that easy to tap in to the global crypto market pipeline.
}
}
});
// Helper method for subscribing to resources
function subscribeTo(conn, resources) {
conn.send(JSON.stringify({
subscribe: {
subscriptions: resources.map((resource) => { return { streamSubscription: { resource: resource } } })
}
}));
}
package main
import (
"encoding/json"
"log"
"github.com/gorilla/websocket"
)
// Initialize a connection using your API key
// You can generate an API key here: https://cryptowat.ch/account/api-access
// Paste your API key here:
const (
APIKEY = "NZAP2FY3HMEC5T1BOYA3"
)
func main() {
c, _, err := websocket.DefaultDialer.Dial("wss://stream.cryptowat.ch/connect?apikey="+APIKEY, nil)
if err != nil {
panic(err)
}
defer c.Close()
// Read first message, which should be an authentication response
_, message, err := c.ReadMessage()
var authResult struct {
AuthenticationResult struct {
Status string `json:"status"`
} `json:"authenticationResult"`
}
err = json.Unmarshal(message, &authResult)
if err != nil {
panic(err)
}
// Send a JSON payload to subscribe to a list of resources
// Read more about resources here: https://developer.cryptowat.ch/docs/websockets-subscriptions
resources := []string{
"instruments:9:trades",
}
subMessage := struct {
Subscribe SubscribeRequest `json:"subscribe"`
}{}
// No map function in golang :-(
for _, resource := range resources {
subMessage.Subscribe.Subscriptions = append(subMessage.Subscribe.Subscriptions, Subscription{StreamSubscription: StreamSubscription{Resource: resource}})
}
msg, err := json.Marshal(subMessage)
err = c.WriteMessage(websocket.TextMessage, msg)
if err != nil {
panic(err)
}
// Process incoming BTC/USD trades
for {
_, message, err := c.ReadMessage()
if err != nil {
log.Fatal("Error reading from connection", err)
return
}
var update Update
err = json.Unmarshal(message, &update)
if err != nil {
panic(err)
}
for _, trade := range update.MarketUpdate.TradesUpdate.Trades {
log.Printf(
"BTC/USD trade on market %d: %s %s",
update.MarketUpdate.Market.MarketId,
trade.Price,
trade.Amount,
)
}
}
}
// Helper types for JSON serialization
type Subscription struct {
StreamSubscription `json:"streamSubscription"`
}
type StreamSubscription struct {
Resource string `json:"resource"`
}
type SubscribeRequest struct {
Subscriptions []Subscription `json:"subscriptions"`
}
type Update struct {
MarketUpdate struct {
Market struct {
MarketId int `json:"marketId,string"`
} `json:"market"`
TradesUpdate struct {
Trades []Trade `json:"trades"`
} `json:"tradesUpdate"`
} `json:"marketUpdate"`
}
type Trade struct {
Timestamp int `json:"timestamp,string"`
TimestampNano int `json:"timestampNano,string"`
Price string `json:"priceStr"`
Amount string `json:"amountStr"`
}
wscat --connect "wss://stream.cryptowat.ch/connect?apikey=XT11G0PE8VX02ZZ49RUR"
connected (press CTRL+C to quit)
< {"authenticationResult":{"status":"AUTHENTICATED"}}
> {"subscribe":{"subscriptions":[{"streamSubscription":{"resource":"pairs:9:trades"}}]}}
< {"marketUpdate":{"market":{"exchangeId":"2","currencyPairId":"9","marketId":"65"},"tradesUpdate":{"trades":[{"timestamp":"1569879489","timestampNano":"1569879489454000000","priceStr":"8200","amountStr":"0.0106711","price":8200,"amount":0.0106711}]}}}
< {"marketUpdate":{"market":{"exchangeId":"3","currencyPairId":"9","marketId":"74"},"tradesUpdate":{"trades":[{"externalId":"97996223","timestamp":"1569879480","timestampNano":"1569879480000000000","priceStr":"8206.51","amountStr":"0.00728105","price":8206.51,"amount":0.00728105}]}}}

Official SDKs

We maintain two official SDKs which properly handle authentication and connection logic. They also provide useful abstractions for our messaging layer.

Build Your Own Client

It's easy to get started writing your own client if you're not using a language supported by our official SDKs.

Authentication

Since this is a read-only API we only require the public key and no secret-based HMAC signature. There are two ways you can provide your API key.

URL query param

wss://stream.cryptowat.ch/connect?apikey=CXRJ2EJTOLGUF4RNY4CF

HTTP Header

X-CW-API-Key: CXRJ2EJTOLGUF4RNY4CF

Message Format

Our API uses Protocol Buffer messages, and supports both JSON and binary serialization. By default, messages are serialized using JSON because it's more convenient, but you can use binary instead to reduce your bandwidth usage. Our official SDKs use binary messages by default.

If you're writing your own client and want to use binary messages, supply a URL param when connecting:

wss://stream.cryptowat.ch/connect?format=binary

Our protobuf message definitions are available here: https://github.com/cryptowatch/proto

Binary vs. JSON

Consuming binary-serialized messages is more work, but uses about half of the bandwidth of JSON. If you find yourself hitting your bandwidth limit with JSON, you should consider switching to binary messages. It's more work to parse them, but it can be worth it!

Deprecation warning: Strings vs. Floats

All numeric values are represented as string values. There are also old, deprecated float versions of these fields which should not be used.

Example message with deprecated fields:

{
"externalId": "97996223",
"timestamp": "1569879480",
"timestampNano": "1569879480000000000",
"priceStr": "8206.51",
"amountStr": "0.00728105",
"price": 8206.51, // <- DEPRECATED: DO NOT USE
"amount": 0.00728105 // <- DEPRECATED: DO NOT USE
}

Pricing & Limits

Your API usage is metered on a monthly basis, and has a monthly limit based on your subscription. Your usage resets on the first day of each month. You will stop receiving data if you hit your monthly limit.

You can upgrade after you've hit your limit to resume service.Subscription TierLimitPriceFree trial?

Subscription

Limit

Price

Free Trial?

Basic

5GB / month

$15 / month

2 weeks included

Pro

75GB / month

$75 / month

None

Thanks to the 2 week free trial, you can test out our API for free with no credit card required up-front. Simply Create an Account to get started.

Need more than 75GB? Contact support!