Why one donation triggers two alerts after refreshing the browser source
Why one donation triggers two alerts
After refreshing the browser source, the page starts over. The script connects to the server again, subscribes to events, and creates handlers to display notifications. If the old handler isn't removed or two connections run at the same time, a single donation event gets processed multiple times.
The refresh itself isn't necessarily the cause of the failure. It often only exposes an error in the connection logic. For example, the initialization function may run on page load, then again when the connection is restored, and once more after receiving a service message. Each run adds a new subscription to the donation event.
As a result, the server sends one donation object, but the browser calls the same function twice. Sometimes the duplication happens on the server side: the application treats the new connection as a separate recipient and sends the event to both the old and the new session. So first you need to determine where the repeat appears: in the source, in the handler, or at the display stage.
How to find where the duplicate occurs
Start with a simple test. Open the browser source link in a separate window or tab, leave only one instance of the page, and send a test event. If the alert appears once, the cause is most likely related to scene settings or multiple instances of the source. If it duplicates already in a separate tab, check the page code and the subscription mechanism.
It helps to split donation processing into several stages: receiving the event, validating the event, queuing the alert, and rendering. Temporarily log a marker at each stage in the log or console. If the receipt entry appears twice, the problem lies before the visual layer. If the event is received once but there are two items in the queue, the error is in the handler. If the queue contains one item but there are two alerts on screen, check the display function and the HTML container.
For diagnostics, add the event's identifier to each event if it's passed in the donation data. Log this identifier on receipt and before display. The same identifier in two calls shows that one event was processed twice. Two different identifiers indicate two deliveries, which need to be investigated separately.
Don't just check the number of tabs. In OBS, two instances can appear after copying a scene, adding a nested scene, or re-adding a browser source with the same address. Sometimes one source stays in a separate layer and the second is added on top of it. Visually this looks like a double alert, even though the event arrived once.
Resubscription after reconnecting
The most common cause is that the handler is added on every connection but not removed on disconnect. Simplified, the problem looks like this: the function calls socket.on with an alert-display handler, then the connection drops, the app reconnects and repeats socket.on. After that, one incoming donation triggers two functions. On the next reconnect there may be even more.
The same error occurs with a regular addEventListener. If the initialization function is called several times, the browser adds several listeners for the same event. Checking an "already initialized" flag doesn't always help: a full page refresh resets the variables, but on a reconnect within the same page the problem persists.
The subscription should be created once per connection lifecycle, and the old subscription should be explicitly removed before the new one. For event handlers, use removeEventListener with the same function reference that was passed on connection. For socket libraries, you usually need an off method, unsubscribe, or a similar way to detach.
A minimal socket pattern might look like this: const onDonation = data => showAlert(data); socket.off('donation', onDonation); socket.on('donation', onDonation); function cleanup() { socket.off('donation', onDonation); window.removeEventListener('beforeunload', cleanup); socket.close(); } window.addEventListener('beforeunload', cleanup);
What matters here isn't the specific library but the order of actions. The handler is stored in a variable, so it can be removed with the same reference. Before a new subscription, the old one is removed, and when the page closes or the source stops, cleanup runs. If a new socket is created on every run, close the old one first and only then create the new one. Otherwise both connections may keep receiving the same data.
When reconnecting, also close the old connection and clear related timers. Otherwise the old socket may keep receiving data while the new one is already running. This happens especially often when the code starts a new reconnect timer without canceling the previous one.
What to check in OBS and the browser source
If a separate window shows the alert once, move on to the scene. Stop the preview, temporarily remove extra layers, and leave one browser source. Then check the behavior on the target scene. This test is faster than checking all scenes and filters at once.
- Look for two sources with the same page address.
- Check scene copies and nested scenes where the same overlay may be present.
- Make sure the alert isn't displayed simultaneously by the browser source and another layer with the same page.
- After changing settings, fully restart the source rather than just switching scenes.
Sometimes an old browser source tab lingers in OBS after the URL or parameters change. Closing and re-adding the source helps test the hypothesis, but it doesn't replace fixing the code. If the problem returns after every refresh, look for re-registration of the handler or a double connection.
Also keep the disconnect delay in mind. On refresh, the old session may not close instantly. If the server considers it active for a few seconds, an event arriving in that window can end up in two sessions. Proper server logic should remove inactive connections and not leave a subscription after the page closes.

Protection against re-delivery of a single event
Even when the browser source works correctly, a single event can sometimes be delivered twice. This is possible during connection recovery, message resending, or a failure between receiving an event and confirming its processing. That's why the alert handler should be resilient to repeats.
The best approach is to check the donation's unique identifier. Before queuing the event, save its identifier in a set of already processed events. If that identifier has been seen before, skip the repeat. Keep the list for a limited time so it doesn't grow indefinitely.
Don't rely only on the amount, sender name, or message text for this. Two different donations can have identical data. Time-based checks are also unreliable: several different donations can arrive almost simultaneously. If there's no identifier, you can temporarily compare a combination of fields and timestamps, but that's a fallback with the risk of mistakenly merging two events.
Duplicate protection should sit before the alert is shown, not inside the animation. Otherwise the second call will still add an element to the page, play the sound, or put another entry in the queue. Control the queue separately: one event should be added to it once, and a repeat call shouldn't start a second independent queue.
If the event is passed between multiple tabs or components, check whether several recipients are processing it at once. A single shared message channel may be connected to several handlers. In that case, either keep a single consumer or explicitly define which component is responsible for showing the alert.
Why clearing the cache doesn't always help
After refreshing the browser source, people often advise clearing the cache. This can fix the situation if an old version of the script was loaded, but the cache doesn't remove extra handlers in an already running page and doesn't close a second copy of the source. If the duplicate keeps repeating after every reconnect, the cause is almost certainly in the connection logic or the scene structure.
Check whether the new version of the files is actually being loaded. Temporarily change the resource URL or use the provided update mechanism, then restart the browser source. After that, run the test again with one window and one instance of the source. Don't add random parameters to the link permanently: this can create many cache variants and make diagnostics harder.
If an intermediate cache or service worker is in use, it can also serve a stale script. In that case, compare the version of the loaded file with the version you expect to see. But even with an old file, you need to fix the cause of the resubscription, otherwise the problem will return after the next refresh.
What to check in the alert code
First, find all the places where socket.on, addEventListener, connection functions, and queue startup are called. Sometimes the problem isn't one handler but that two different modules independently listen to the donation event and each triggers its own display.
Then check the component lifecycle if the alert is rendered through a framework. The subscription is placed in an effect or similar block and returns a cleanup function. You must not create a new handler on every state update without removing the previous one. In plain JavaScript, it's important to store a reference to the active socket and the current handler so they can be properly closed when the page stops.
Check the reconnect timers. A new timer shouldn't start on top of an old one. Otherwise, after several drops, parallel connection attempts are created, and with them extra subscriptions. Each timer needs to be cleared with clearTimeout or clearInterval if it's no longer needed.
Also look at the code that shows the alert. It must not simultaneously add an element to the queue and immediately call the display function for the same object. Also check whether the animation restarts when the element's state changes. If the log shows one receipt and one queue entry but there are two notifications on screen, that's exactly where to look.
Diagnostics checklist: what to do in order
- Open the browser source URL in a separate tab and send one test donation. Note whether the duplicate appears outside OBS.
- Leave only one instance of the source in the scene. Check scene copies, nested scenes, and layers where the same address may be present.
- Add logging with the event identifier at the receipt, queuing, and display stages. This will show where the number of objects increases.
- Find all calls to socket.on and addEventListener. Check whether old handlers are removed via socket.off and removeEventListener with the same function reference.
- Check reconnection: is the old socket closed, is the old timer canceled, and is a new subscription created on top of the previous one.
- Add a check of the donation's unique identifier before queuing, then fully restart the source and repeat the test with a single event.
If a separate tab receives the event once but OBS shows two alerts, look for a second instance of the source or duplication in the scenes. If the event arrives twice already in a separate tab, check subscriptions, connections, and server delivery. If receipt and queuing are logged once but there are two notifications on screen, the problem lies in the visual layer.
Last Articles
What has changed in design and functionality We have updated the website to make working with it faster and more convenient. The main changes affect ..
Good afternoon, I've collected all the news during this time.: 1. The main news is that prices for twitch viewers have been greatly reduced, while Tw..
1. Use promo code "December2025" for a 15% discount for all our viewers2. We have reduced the base prices for our configurator and the most affordable..
Twitch services are working stably, so we are ready to cooperate with squads, resellers, service owners, bot owners, and many others.Individual te..
We have completely updated our Twitch viewer services, and they are now working stably. We only use high-quality IP addresses for the viewers.The ..
Hello everyone! Today, we are announcing a new feature—"Twitch Viewer Configurator". Now, you can customize any plan for your Twitch channel. Choo..
Greetings, I have compiled a guide for streamers, which will be very relevant at the moment. Now YouTube and twitch have disabled monetization from vi..
We have finally developed the APINow it will be more convenient for our partner sites to work with us.To update the maximum tariffs for YouTube, an up..
Due to the huge popularity of the partnership services and referral program, we have made a cooperation table. The essence is very simple: more live a..
Our Services for Streamers
Our Services for Content Creators










