Getting Started with WebSockets in Go


Reading Time: 5 minutes

This article was originally published on MeetSpace by Nick Gauthier, and with his kind permission, we are sharing it here for Codeship readers.

WebSockets are one of the core technologies MeetSpace uses to connect people on a call. In this post, we’ll look at how to get started with WebSockets in JavaScript and Go.

WebSockets on the Server

We’ll dive right into the HTTP handler for a WebSocket. If you’re unfamiliar with writing HTTP servers in Go, start with my tutorial on http servers. At this point, we have a handler like this:

func socket(w http.ResponseWriter, r *http.Request) {
  // ok now what?

WebSockets work by sending an Upgrade header back on the response, at which point the browser switches over to processing the server data as a WebSocket connection. We could do this ourselves, but Go provides a package as part of their extended subrepository packages. So, we’ll use

We need to get the WebSocket library to hook into our HTTP requests, and to do that, they provide websocket.Handler which is a type of function that provides ServeHTTP. That means all we have to do is create our own handler function and cast it to that type, and we can use it on our server. Here’s the basics:

func socket(ws *websocket.Conn) {
  // let's do websocket stuff!

// later, in your router initialization:
http.Handle("/socket", websocket.Handler(socket))

This syntax in Go confused me at first, because it totally looks like we’re calling the websocket.Handler() function on socket as a parameter. But, websocket.Handler is a type, so websocket.Handler(socket) is casting socket to the websocket.Handler type. Then, websocket.Handler’s ServeHTTP function means it’s a valid http.Handler interface implementer.

Now that we have our server harness set up, we need to process data. The simplest way to work with WebSockets is by using the websocket.Conn object (our ws) as an io.Reader. We could use Read and Write to write data, as in this simple example:

// make a buffer
var buf = make([]byte, 1024)
n, err := ws.Read(buf)
if err != nil {
fmt.Println("We read", n, "bytes, and they were", string(buf))

However, this has a couple of problems. First, we have to allocate a fixed size buffer. Go won’t overflow the buffer, but it’s possible to receive more than 1024 bytes, and we’ll only get the first 1024. We’d have to loop the read until we got all the data we wanted to process. We’d probably have some kind of delimiter on the data too, to know when we got a whole message. Also, when we get less than 1024 characters, we have to trim up to the delimiter.

This is a very common situation, so the websocket package provides a Codec struct that encapsulates a Marshal and Unmarshal function. If you construct a Codec with those two functions, you can then call Codec.Send and Codec.Receive and the frames will automatically be written and read using websocket’s internal framereader. That means you don’t have to worry about buffer sizes and frame delimiters, yay!

We could send our WebSocket data around as plain old bytes, but our client is going to need to make sense of it too. So we should probably agree upon some kind of cross platform interchangeable format. Like JSON! JSON has the benefit of being native to JavaScript, which is where our client will live. Additionally, Go’s support for JSON is great.

Lucky for us, this is a common plan, so the websocket package provides a JSON Codec. That makes reading and writing JSON data as simple as this:

type message struct {
  // the json tag means this will serialize as a lowercased field
  Message string `json:"message"`

func socket(ws *Conn) {
  for {
    // allocate our container struct
    var m message

    // receive a message using the codec
    if err := websocket.JSON.Receive(ws, &m); err != nil {

    log.Println("Received message:", m.Message)

    // send a response
    m2 := message{"Thanks for the message!"}
    if err := websocket.JSON.Send(ws, m2); err != nil {

Sign up for a free Codeship Account


Now that we have a server that can receive messages and respond, we need a client. I’ll leave the HTML and JavaScript scaffolding to you, and cut right to the JavaScript code that interacts with our server. Here’s a basic example that sends a single message and receives the response:

var ws = new WebSocket("ws://" + + "/socket");

ws.onopen = function() {
  ws.send(JSON.stringify({message: "hello server!"}))

ws.onmessage = function(event) {
  var m = JSON.parse(;
  console.debug("Received message", m.message);

ws.onerror = function(event) {
That should create the following (riveting) conversation:

Go: "Received Message: hello server!"
JS: "Received Message: Thanks for the message!"

Conclusion and Warnings

That’s the basics of WebSockets in Go and JavaScript. However, there are a couple more things we ran into, and I wanted to mention them here with a brief description of the solutions so you wouldn’t get stuck on them right away:

  1. Typing. We found that having a message structure like {type: string, data: string} was very useful. On the server and client we use a switch on type and then send the data to the appropriate function based on type. The data is usually a plain string or JSON depending on how complex it is.
  2. Keepalive. After about a minute many browsers will close the socket if there’s no activity. We added a server-side heartbeat message using Go’s time.Tick in a Goroutine that kept it alive.
  3. Reconnect. If for some reason the socket connection is interrupted, you want to reconnect it. You can bind to onclose in JS to reconnect the socket. There is no actual “reconnect” so you make a new socket and rebind the event handlers. Hopefully that will help with getting started with WebSockets in Go and JavaScript.

Subscribe via Email

Over 60,000 people from companies like Netflix, Apple, Spotify and O'Reilly are reading our articles.
Subscribe to receive a weekly newsletter with articles around Continuous Integration, Docker, and software development best practices.

We promise that we won't spam you. You can unsubscribe any time.

Join the Discussion

Leave us some comments on what you think about this topic or if you like to add something.

  • How about websocket client in Go? Could you give us some examples?

  • dsont

    Interesting, I did not know about Codecs. I wonder how I can combine Codecs with Protobuf3.

    At first you would have the advantage of using jsonpb, which would marshal json even faster, as it knows about the structure of the JSON.

    Also, it would be great if there was a clean way to unpack an ‘inner message’ perhaps, via Codecs.

    Awesome, thanks for a great blog post!

    • You’re welcome! I didn’t notice Codec for a while too, and when I found it I knew I had to share it :)

  • I think of WebSockets as the simpler and more generalized solution that is applicable to many diverse situations, whereas it’s WebRTC that has largely been developed to meet the specific purpose of enabling next-generation VoIP-type systems. Does MeetSpace use WebSockets for real-time signaling, but then use WebRTC to intelligently and efficiently stream the actual audio and video? Thanks.

    • Yes, that’s right. Our sockets negotiate join/leave and signaling for the webrtc connection. Additionally, the websocket communicates mute state, screenshare, and also provides our server with a real-time view of who’s in a room. So when you’re on the dashboard you can see who’s in the room before you join.