The most common cause is the duplication of Realtime clients inside your app.
Every time you create an instance of a Realtime client (usually through factory.createClient) and invoke the connect method, you are establishing a new independent TCP connection to a Realtime server (a WebSocket or some fallback polyfill).
Most likely each established connection will subscribe the same channel, so when you send a message on that channel your app will receive as many messages as the number of connected/subscribed clients running at the moment.
If you are developing a web project you may inspect the network tab of your browser developer console and look for WebSockets (see below).
If you see several "Pending" WebSockets then you're "guilty as charged"!
(In a different environment like a native mobile app you may find easier to add a log into your Realtime client onConnected event to see if it's being invoked more than once).
As a rule-of-thumb your Realtime connection should be a singleton, a single instance used throughout the app.
Don't worry, reconnection is automatic!
If you have implemented your own reconnection procedure that's probably the root cause of the duplication problem.
Unless you explicitly call the disconnect method, each Realtime connection (in any SDK) will always try to reconnect automatically as soon as possible.
When you successfully establish a Realtime connection (meaning the onConnected event was fired), you don't need to add any specific logic to recover from dropped connections, whether they happen because the user paused your app, entered a tunnel and lost mobile data signal or some other network failure.
Just let the underlying Realtime SDK do the job and you'll be fine.
If you want to show some "offline" signal to your user, simply implement the onReconnecting and onReconnected events and update the UI accordingly.