[SOLVED] Extension Review Process, Released

Any tips on passing the review process are helpful.

I’ve added detailed review details and made a guideline video.

So far here are some things that I’ve implemented and fixed plus this might help others.

  1. First Include: In my viewer.html make sure the extension helper is the first script included.
<script src="https://extension-files.twitch.tv/helper/v1/twitch-ext.min.js"></script>
  1. Status Messages: I’ve added a ton of status messages in the extension. Previously I had a minimal UI that identified the ‘broadcaster’ and ‘viewer’. Now I have a bunch of status methods that appear based on feedback from the extension backend service. I’ve even added timeout detection with the EBS with a status message for that. This should also avoid the rejection based on feedback that the extension doesn’t do anything.

  2. Skin: The initial backend service was the vanilla Windows.Forms. I’ve converted to WPF and skinned things to look a bit better.

  3. Hardware: My extension depends on LED hardware. There’s an emulator available that shows the LED lighting if the review team doesn’t have a Chroma enabled device. You can find the supported devices here.

  4. Only the broadcaster can talk to the EBS. Yes only the broadcaster communicates with what I’ve called the ChromaRelay backend service.

Video sync: I’m thinking I might need another video to show what it’s like for the viewer receiving video with Chroma data. I’ll get on that. It takes a couple computers since review needs two accounts for a ‘broadcaster’ and ‘viewer’.

  1. (continued) More about #5. Technically I do have the viewer talking to the ChromaSDK REST API to display the Chroma lighting. This is the nice HTTPS REST interface between the browser and the lighting hardware.


Strictly speaking I may be violating the rules, but it’s necessary to talk to the lighting hardware so the viewer can have their lighting synchronized with the video.

  1. WebWorkers - Regarding JS/HTML5 I’m using setTimeout and setInterval to sync things. I’m pretty sure I need to switch over to WebWorker so I can have reliable timing.

  2. Video latency - Using the context event you can get the hlsLatencyBroadcaster which gives you how many seconds the viewer is behind the live stream. Using this latency you can pad your receive buffer so that your extension messages are in sync with the video. In my case each second of data includes a set of 10 data samples that have a 100 ms duration each. So I’m enforcing that the receive buffer always has (10 data samples for every second of latency).

  window.Twitch.ext.onContext(function(context, contextFields) {
    //console.log("context", context);
    //console.log("contextFields", contextFields);
    if (context != undefined && context.hlsLatencyBroadcaster != undefined) {
      receiveLatency = (context.hlsLatencyBroadcaster) * 10; //100 ms intervals
      if (receiveLatency < 0) {
        receiveLatency = 0;
      //add latency
      while (receivedBuffer.length < receiveLatency) {
        receivedBuffer.push(undefined); //100ms intervals
      //cap the buffer length to maintain sync
      while (receivedBuffer.length > 0 &&
        receivedBuffer.length > receiveLatency) {
        receivedBuffer.splice(0, 1);
  1. Compression - Broadcasting has a 5kb limit per request per second when sending data. I have my extension backend service sending the data, and to get to the 5kb limit the service is doing compression. The EBS is C# and so I’m using SharpZipLib to compress the message. The data contains arrays of RGB data. When sending the values as RGB comma delimited arrays compression could only get down to around 7.5kb. And that’s the largest size when all the colors in every frame on every device are different. Technically it was 5kb, but when you base64 the compressed binary data it ballons by 30%. I found I could further reduce the final size by separating the RGB comma delimited arrays into R, G, B comma delimited arrays. And that’s because there’s more common data when you break RGB integrer values into their red, green, blue component parts. And since compression is being used on the backend, I’m also using decompression in the frontend javascript. I used JSZip for that.
  1. HTTPS Secure - The extension backend service communicates with the frontend by running a secure HTTP server on the backend. For browser security this means that the backend needs to run HTTPS. This means that you need to obtain a trusted certificate for your domain. You can find certificate authorities that are paid or even free so you can acquire a trusted certificate.

  2. Installer - I use InnoSetup to build the application installer. The installer also needs to manage installing the certificate from step 9. You’ll get a certificate and key from your certificate authority which can be combined into a PFX file which can be installed on the command-line by the installer.

  3. Extension Icon - I replaced the default extension icon with a custom icon.

Rejection 1:

These two things were straightforward to fix.

Rejection 2:

What does the forward-facing comment mean? I can add a link to the extension backend service to the config section. For now it’s a dropbox link. Should I be bundling the application installer in the extension zip when I upload the extension files. That way the link would be relative instead of a dropbox link?

I’ve linked to the dropbox download from the config.html for the time being. And I whitelisted the link in the extension settings so the download can work.

Yes only broadcasters would use the extension backend service.

I’ve expanded the description and links on the config.html page.

If they only saw Viewers in the extension, that means they didn’t test with a broadcaster and viewer account. I made a video to show how this works. And with the status messages it should be more apparent about what’s going on. Now they’ll see the viewer with a messages for ‘Waiting for Chroma data…’ or ‘Receiving Chroma data…’. While the broadcaster will display either ‘Waiting to send Chroma data…’ or ‘Sending Chroma data…’.

Rejection 3:

In order to connect with the Chroma REST API, the ChromaSDK needs to be installed.

Users with Chroma hardware would have the Razer Chroma SDK Server service installed.

I’ve added more detection logic to detect if the ChromaSDK is missing to display a status message.

I can simulate this scenario by stopping the Razer Chroma SDK Server service before loading the viewer page for broadcaster and viewer.

1 Like

What are the reasons for your rejection? They should tell you in the email.

Is your code “human readable”? (Code is not compressed/mangled)
Are you including script tags for libraries instead of importing them into your code? (not applicable if you’re not using a module bundler)

(edit) Posted above.

Yes the code is readable. I used the Atom editor and everything is formatted nice.

With the exception of the ChromaSDK which I minified and inlined at the top of viewer.js.

Oopps. I did include JQuery and JSZip from the viewer.html. And I could have inlined the JSZip library.

        <script src="https://extension-files.twitch.tv/helper/v1/twitch-ext.min.js"></script>
        <script src="js/jquery.min.js"></script>
        <script src="js/jszip.min.js"></script>
        <script src="js/common.js"></script>
        <script src="js/viewer.js"></script>

Thanks for that. Okay I’ve inlined the JavaScript minified for JQuery and JSZiip libraries into the viewer.js.

Sorry if I wasn’t clear, the preferred method is using script tags, and not inlining the library code. This is so the reviewer can verify the integrity of each library file. They can’t do this if you inline several libraries into a single file.

Anyways, the rejection reasons are not relevant to the above, so it’s not the core problem.

As far as i know, twitch only tests the viewer experience of your extension. Anything concerning config or live config, they don’t test.

After skimming your video, it seems as if the extension needs streamer interaction to do anything, is that correct? If so - and because I believe twitch only tests the viewer experience - you may need to simulate the streamer interaction.

Here’s a quote from the extensions docs

Also, if your extension requires live data to operate, please simulate the necessary data to allow our reviewers to use the full breadth of features offered by your extension.

I’m not an authoritative source on how the review process works, i’m only speaking from experience.

1 Like

I’ll have to think about simulating the broadcaster They would still need to authenticate the broadcaster and viewer for it to work…

I guess I could add an option to the extension backend service to send mock data.

I added a menu item checkbox to the Twitch menu for “Simulate Chroma Data”. When enabled Chroma will broadcast a blinking purple color.


For rejection #3, I added detection logic. If the ChromaSDK is not installed or if the service isn’t running, there will be a status message.

The ChromaSDK detection logic is on the viewer page for both the broadcaster and viewer.

The broadcaster needs the ChromaSDK so that games can broadcast the Chroma data. The viewer needs the ChromasDK to see the Chroma lighting on their connected devices.

Rejection 4 is the same as rejection 3.

The ChromaSDK needs to be installed in order to connect. The download link can be found on the config page.

Doesn’t this go against this specific requirement?

This is what Chroma gaming looks like:

And the purpose of the Chroma extension is to stream Chroma lighting on the live Twitch channel.

I suppose I could display ChromaLink LEDs in the Viewer. That way some lights appear even if you don’t have the ChromaSDK.

That way I could say the extension is compatible with the ChromaSDK. If the ChromaSDK is missing, at least the user will see virtual LEDs.


Anyone with Chroma hardware will already have the secure Chroma REST API installed. With the ChromaSDK, the user gets the full Chroma experience.

The ChromaSDK is optional and no longer required for the Viewer.

I added support for more devices with toggles for ChromaLink, Headset, Keyboard, Keypad, Mouse, and Mousepad virtual displays.

Very Interesting, I like it. This will be useful when streaming. Thanks! :smiley:

I made it to the Released state! The Chroma extension is now be publicly available.

I’ll put together the documentation for the broadcaster and viewer here.