How do you deal with scenarios when the same user has 2 browser windows of the extension open?

The scenario: One user has 2 browser windows pointing to the same channel with the extension open.

They useBits on one window -> onTransactionComplete is called on both.

I use onTransactionComplete to know when a user has actually spent bits and I can safely trigger the action they paid for. In my case, I call my EBS. In a scenario like this though, I end up calling it twice and thus triggering the same action twice.

Both actions are triggered pretty much at the same time, so there is no time for me to write the timestamp to my DB and try to read that on the second call in an attempt to invalidate it.

Do you have any similar scenarios? How do you deal with them? Is there another way to know for sure that a user has now spent their bits?


  • Hold the transaction ID in server memory, and reject a repeat. (In memory in redis rather than waiting for DB writes/if node in an array/whatever)
  • process events using a FIFO queue.
  • use the webhook for transactions rather than sending the receipt from the front end to the backend. As you’ll only get the one Webhook for the transaction.

Or Have “broadcast” turned off on that bits product and that fixes it I think/changes the behavior (not tested this fully/recall the exact behaviour)

Thanks Barry.

Interesting suggestions.
What’s the webhook for transactions?

“broadcast” is turned off but it still broadcasts the message to the current_user instance

persoanlly I have this off.

But I have a “basket” flow in my extension

So for each instance of the extension.
Only one of those instances is in a basket state ready for a purchase event.
So if the other instance gets a trigger, it ignore it, as it’s not in “basket state”

Thanks. The basket flow idea is also interesting.
Might try that over webhooks.

I was hoping for a quick win here but both implementations will require some time…

I run both!

Webhooks + fifo queue + the basket flow.

So all three.

The Fifo queue works best, just absorbs data from all sources (on the EBS) and works out from there

Just for clarity, regardless of the broadcast setting Twitch will ALWAYS send a receipt to onTransactionComplete for ALL connections by a user on the channel where they have used bits.

Personally I just use a basket flow, sort of, and have had no issue with it. If the user has something selected and has clicked useBits (regardless of if they actually use confirm that within that tab) they’ll send any transaction they get back to my EBS, first one there is considered the definitive source of data for me. If a tab got a receipt but a nothing selected, or they never attempted to call useBits then the frontend for that tab just assumes it wasn’t a transaction for their tab.

Another alternative is to use ‘tokens’. For example if a sku is to get ‘gold tokens’, then the EBS can credit those ‘tokens’ to the users account and this can completely ignore any duplicate transactions as no meta-data or state needs to be sent from the user to your EBS. Then the user can use those ‘tokens’ in your extension to do whatever it is they need to do, and there’s no issue with duplication there as it’s directly between a client and your EBS.

Well you still need to stop them getting gold tokens twice for a given transaction

Each useBits transaction has a single id, regardless of how many tabs that receipt is sent to. I could be sent a thousand to my EBS, 1 id = 1 transaction = 1 increase in ‘tokens’ by the SKU used. Once the ID is in the database, all future messages sent to the EBS with that ID can be dropped.

This doesn’t solve OP’s problem.

The problem being EBS gets two Transactions at the same time and is processing transaction B whilst Transaction A is being written to the database. (Where transaction B is a duplicate of Transaction A)

You’ve just moved the problem