GuidesAPI Reference
DocumentationLog In

WebSocket Overview

๐Ÿšง

Coinbase Advanced Trade API is in Beta. We welcome your feedback in the forums!

The WebSocket feed is publicly available and provides real-time market data updates for orders and trades.

๐Ÿ“˜

Endpoint: wss://advanced-trade-ws.coinbase.com

Protocol

The WebSocket feed uses a bidirectional protocol that encodes all messages as JSON objects. All messages have a type attribute that can be used to handle the message appropriately.

๐Ÿ‘

New message types can be added at any time. Clients are expected to ignore messages they do not support.

Subscribe

To begin receiving feed messages, you must send a subscribe message to the server indicating which channel and products to receive. This message is mandatory and you are disconnected if no subscribe has been received within 5 seconds.

๐Ÿšง

To receive feed messages, you must send a subscribe message or you are disconnected in 5 seconds.

// Request
// Subscribe to ETH-USD and ETH-EUR with the level2 channel
{
    "type": "subscribe",
    "product_ids": [
        "ETH-USD",
        "ETH-EUR"
    ],
    "channel": "level2",
    "api_key": "exampleApiKey123",
    "timestamp": "1660838876",
    "signature": "jd83jdhsus83krkfjf883jkjnsjdu84j3nd8dj3",
}

To subscribe to any channel, users must provide a channel name, api_key, timestamp, and signature:

  • channel name as a string. You can only subscribe to one channel at a time.

  • timestamp should be in UNIX format.

  • signature should be created by:

    1. Concatenating and comma-seprating the UNIX timestamp, channel name, and product Ids, for example: 1660838876level2ETH-USD,ETH-EUR.

    2. Hashing this phrase with your secret key: CryptoJS.HmacSHA256(str, secret).toString().

Subscribe Code Sample

This JavaScript example is for subscribing to one Advanced Trade WebSocket channel.

// JS Example for subscribing to a channel
/* eslint-disable */
const WebSocket = require('ws');
const CryptoJS = require('crypto-js');
const fs = require('fs');
 
// Derived from your Coinbase Retail API Key
//  SIGNING_KEY: the signing key provided as a part of your API key. Also called the "SECRET KEY"
//  API_KEY: the api key provided as a part of your API key. also called the "PUBLIC KEY"
const SIGNING_KEY = '';
const API_KEY = '';
 
if (!SIGNING_KEY.length || !API_KEY.length) {
 throw new Error('missing mandatory environment variable(s)');
}
 
// the various websocket channels you can subscribe to
// add to this as we go
const CHANNEL_NAMES = {
 level2: 'level2',
 user: 'user',
 tickers: 'ticker',
 ticker_batch: 'ticker_batch',
 status: 'status',
};
 
// The base URL of the API
const WS_API_URL = 'wss://advanced-trade-ws.coinbase.com';
 
// Function to generate a signature using CryptoJS
function sign(str, secret) {
 const hash = CryptoJS.HmacSHA256(str, secret);
 return hash.toString();
}
 
function timestampAndSign(message, channel, products = []) {
 const timestamp = Math.floor(Date.now() / 1000).toString();
 const strToSign = `${timestamp}${channel}${products.join(',')}`;
 const sig = sign(strToSign, SIGNING_KEY);
 return { ...message, signature: sig, timestamp: timestamp };
}
 
const ws = new WebSocket(WS_API_URL);
 
function subscribeToProducts(products, channelName, ws) {
 console.log('products: %s', products.join(','));
 const message = {
   type: 'subscribe',
   channel: channelName,
   api_key: API_KEY,
   product_ids: products,
   user_id: '',
 };
 const subscribeMsg = timestampAndSign(message, channelName, products);
 ws.send(JSON.stringify(subscribeMsg));
}
 
function unsubscribeToProducts(products, channelName, ws) {
 const message = {
   type: 'unsubscribe',
   channel: channelName,
   api_key: API_KEY,
   product_ids: products,
 };
 const subscribeMsg = timestampAndSign(message, channelName, products);
 ws.send(JSON.stringify(subscribeMsg));
}
 
function onMessage(data) {
 const parsedData = JSON.parse(data);
 fs.appendFile('Output1.txt', data, (err) => {
   // In case of a error throw err.
   if (err) throw err;
 });
}
 
// change the number of iterations to stress the system with more connections
const connections = [];
let sentUnsub = false;
for (let i = 0; i < 1; i++) {
 const date1 = new Date(new Date().toUTCString());
 const ws = new WebSocket(WS_API_URL);
 
 ws.on('message', function (data) {
   const date2 = new Date(new Date().toUTCString());
   const diffTime = Math.abs(date2 - date1);
   if (diffTime > 5000 && !sentUnsub) {
     unsubscribeToProducts(['BTC-USD'], CHANNEL_NAMES.user, ws);
     sentUnsub = true;
   }
 
   const parsedData = JSON.parse(data);
   fs.appendFile('Output1.txt', data, (err) => {
      // In case of a error throw err.
      if (err) throw err;
   });
 
 });
 
 ws.on('open', function () {
   console.log('OPENING');
   const products = ['BTC-USD'];
   subscribeToProducts(products, CHANNEL_NAMES.user, ws);
 });
 
 connections.push(ws);
}

Unsubscribe

To unsubscribe from a channel/product pair, send an unsubscribe message. The structure is the same as subscribe message. You can only unsubscribe from one channel at a time.

:::tip
You can also unsubscribe from a channel entirely by providing no product IDs.
:::
--->

// Request
{
    "type": "unsubscribe",
    "channel": "level2"
}

You receive a subscriptions message as a response to an unsubscribe message.

Authentication

You can authenticate yourself when subscribing to the WebSocket Feed. One benefit of authenticating is that you can subscribe to channels with private order information, such as the users channel.

// Authenticated feed messages add user_id 
{
    "type": "users",
    "user_id": "5844eceecf7e803e259d0365",
    /* โ€ฆ api_key, timestamp, etc... */
}

Sequence Numbers

Most feed messages contain a sequence number. Sequence numbers are increasing integer values for each product, with each new message being exactly one sequence number greater than the one before it.

Sequence numbers that are greater than one integer value from the previous number indicate that a message has been dropped. Sequence numbers that are less than the previous number can be ignored or represent a message that has arrived out of order.

In either situation you may need to perform logic to make sure your system is in the correct state.

๐Ÿšง

Even though a WebSocket connection is over TCP, the WebSocket servers receive market data in a manner that can result in dropped messages. Your feed consumer should be designed to handle sequence gaps and out of order messages, or should use channels that guarantee delivery of messages.

๐Ÿ‘

To guarantee that messages are delivered and your order book is in sync, consider using the level2 channel.


See Also: