Aug 16, 2019 - By Braxton Lancial

Fireworks! A Sample Extension Using Bits

It’s always a good time for fireworks! And fireworks are even better when they’re digital and in a Twitch Extension. Recently we published a new sample Extension on the GitHub, which allows viewers to exchange Bits for an immaculate fireworks display in a video overlay. It leverages several of our Bits-in-Extension APIs, the Extension Configuration Service, and a lightweight Extension Backend Service. If you’re interested in how we built this Extension, and want to learn more about what tools Twitch offers to enable you to build a similar Extension yourself, you’re in the right place.

Bits in Extensions

Bits in Extensions enable you to build and manage a catalog of items and experiences in which viewers can exchange Bits. We provide a helper function to prompt the Bits transaction flow, and our callbacks allow your Extension to react accordingly to a transaction. The first step to manage your catalog of offerings for viewers is setting up the SKUs that will be included in your catalog. SKUs can be setup using the Developer Rig. After creating a new project or opening an existing project in the Developer Rig, you can navigate to the “Monetization” section on the left, and then click the “Live Products” tab. Here you can add new products as well as manage items after they’ve been created. In this example we’ve created two items — a Small Fireworks item at an amount of 10 Bits, and a Large Fireworks item at an amount of 100 Bits.

Configuration Service

Another useful feature utilized in this sample is the Configuration Service. This service enables developers to store Extension-specific and channel-specific data. In our fireworks example, we allow broadcasters to select one of two items they would like to be available to exchange for Bits — either Small Fireworks, or Large Fireworks. Upon selection, the configuration page saves that selection into the broadcaster configuration service segment. This choice ultimately determines what SKU will be presented to viewers. The Extension retrieves this broadcaster configuration and displays a button allowing viewers to exchange Bits for the selected SKU. While simple, this is an example of how easy it can be to empower broadcasters to tailor the Extension experience to their liking within your predetermined boundaries.

{% raw %}
function saveSettings() {
  var radioBtns = document.getElementsByName('firework');
{% endraw %}
{% raw %}
  for (var i = 0, length = radioBtns.length; i < length; i++) {
    if (radioBtns[i].checked) {
      twitch.configuration.set("broadcaster", "", radioBtns[i].id);
      log("saveSettings() fired, broadcaster-selected sku set to: " + radioBtns[i].id);
      break;
    }
  }
}
{% endraw %}

The Extension Helper and Transaction Flow

We’ve set up our SKUs, we’ve implemented the Configuration Service to manage our catalog per broadcaster, now we’re ready for viewers to actually exchange their Bits for some digital fireworks. There are a variety of APIs and callbacks available through the Extension Helper relevant to the Bits transaction flow. In our sample, our overlay presents a very simple interface which presents a button to the viewer that reads “Launch Fireworks!”. When a viewer clicks this button, we call the useBits(SKU) method from the Twitch helper. This method kicks off the Bits transaction flow for the specified SKU from your catalog. If the viewer does not have enough Bits in their account, they’ll be led to the Bits purchasing interface, giving the viewer an opportunity to purchase more Bits and move forward with the transaction. Assuming the viewer already does have enough Bits or has just purchased enough, they’ll be prompted with a confirmation dialog box.

{% raw %}
useBits = function () {
  if (sku == "") {
    log("no sku received from the configuration svc");
    return;
  }
  twitch.bits.useBits(sku);
}
{% endraw %}

In our example, if the viewer selected Small Fireworks, they will be asked to confirm exchanging 10 of their Bits. If the viewer selected Large Fireworks, they will be asked to confirm exchanging 100 of their Bits. At this point the user will either confirm or cancel the transaction. Both options invoke callbacks from the Twitch helper so you can handle their decision accordingly. We only care about handling the scenario where the user has successfully confirmed exchanging their Bits for (digital) fireworks. When the user completes this transaction, the onTransactionComplete(transaction) callback function is invoked.

{% raw %}
twitch.bits.onTransactionComplete(function (transaction) {
  log("onTransactionComplete() fired, received transactionReceipt: " + transaction.transactionReceipt);
  
  fetch("https://localhost:8080/api/fireworks", {
    method: "POST",
    headers: {
      "Authorization": "Bearer " + transaction.transactionReceipt,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ channelId: channelId })
  }).then(function (response) {
    if (response.ok) {
      log("ebs validated transaction")
    }
    else {
      log("ebs was unable to validate transaction")
    }
  });
});
{% endraw %}
{% raw %}
twitch.listen('broadcast', function (topic, contentType, sku) {
  log("listen() fired, received sku via PubSub: " + sku + ". Shooting Fireworks!");
  launchFireworks(sku);
});
{% endraw %}

Here we do a quick validation with our backend (more on that later), which eventually invokes the listen() callback via PubSub. Now we can finally shoot off our beautiful display of pixelated fireworks on the overlay. Bits transaction complete!

Extension Backend Service

While the interface of the Extension and the fireworks themselves are the more exciting parts, the dirty work still has to be done somewhere. This is where our Extension Backend Service comes into play (EBS for short). Most (but not all) Extensions require some sort of backend to operate. In this sample, our EBS verifies the validity of a Bits transaction by verifying its Javascript Web Token (JWT), then sends out the purchased Bits SKU via PubSub.

Verifying a JWT with Go

We chose to write our EBS in Go, as Go is a very lightweight way of quickly spinning up a backend. Our Go server must be running before our frontend can interact with it. Once it is, you can see our frontend routes our request to the API endpoint we’ve configured at https://localhost:8080/api/fireworks. This endpoint requires a Bearer Token as an Authorization Header (which will come from the transaction receipt field), as well as a channelId (the broadcaster’s Twitch user id). Our EBS uses a JWT library to parse the token we received from the transaction to ensure this request is coming from our Extension on Twitch. If it arrives at that confirmation, we respond with a 200 status and continue.

Using PubSub with our own JWT

__We now need to create our own signed JWT, so when we send our PubSub message, Twitch knows it is coming from us. We can do this easily as seen in the [newJWT(channelID string)](https://github.com/twitchdev/extensions-samples/blob/4c6327685228da0371da2326489d1c35760f5908/bits-fireworks/ebs/main.go#L195) function, by again utilizing the JWT library (most languages have solid JWT libraries that will make your life easier). After generating our own token, we can broadcast a message through PubSub by hitting the messages endpoint, and specifying what channel the message should be sent to. Using PubSub allows us to send a message to all Extension client instances in a specified channel all at once. This is what ultimately triggers the listen() method from the Twitch Helper on the frontend, and will shoot off our fireworks.

{% raw %}
// newJWT creates an EBS-signed JWT
func (s *service) newJWT(channelID string) string {
  var expiration = time.Now().Add(time.Minute * 3).Unix()
  
  claims := jwtClaims {
    UserID:    s.ownerID,
    ChannelID: channelID,
    Role:      "external",
    Permissions: jwtPermissions {
      Send: []string{"broadcast"},
    },
    StandardClaims: jwt.StandardClaims {
      ExpiresAt: expiration,
    },
  }
{% endraw %}
{% raw %}
  token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
{% endraw %}
{% raw %}
  tokenString, err := token.SignedString(s.secret)
  if err != nil {
    log.Println(err)
  }
{% endraw %}
{% raw %}
  log.Printf("Generated JWT: %s\n", tokenString)
{% endraw %}
{% raw %}
  return tokenString
}
{% endraw %}

Our Extension Backend Service has now validated the JWT from the incoming request to verify it was coming from our frontend, it has created its own JWT to send back to Twitch, and it has sent a PubSub message to the channel the request originally came from. Our EBS’s work here is done.

Conclusion

Hopefully this Extension sample can help kickstart your Bits-enabled Extension development. Extensions come in many different flavors, so for more examples using other frameworks and languages, check out TwitchDev on GitHub. Visit the Twitch Developer site to begin developing your Twitch Extension. Happy building!

In other news
Aug 21, 2019

Just add Time Travel: Building your Games for Both Streamers and Viewers

The Collaborative is an experimental top-down shooter from Amazon Games that empowers streamers and viewers to play together.
Just add Time Travel: Building your Games for Both Streamers and Viewers Post
Aug 15, 2019

Introducing a Community Resource Page for Twitch Developers

The Twitch Developer community has created some incredible, open source projects that help developers get started on Twitch. These…
Introducing a Community Resource Page for Twitch Developers Post