[GH-ISSUE #190] WebSockets uses more battery than JSON stream #149

Closed
opened 2026-05-07 00:20:34 +02:00 by BreizhHardware · 9 comments

Originally created by @binwiederhier on GitHub (Mar 29, 2022).
Original GitHub issue: https://github.com/binwiederhier/ntfy/issues/190

I received this email. I shortened it a bit for the ticket. Emphasis I'll highlight the important bits in bold:

"[...]

After a couple days of using WebSockets, however, I noticed that it actually appears to consume as much as 2-3x more battery on my device than HTTP stream. On a day when I receive no notifications (just to make for an easy comparison), HTTP stream always seems to consume about 0.3-0.5% of my battery per hour, while WebSockets appears to consume about 1% of my battery per hour. This is on a six month old Pixel 5a running GrapheneOS with ntfy's battery usage set to Unrestricted to prevent it from being killed.

I guess I was wondering if this was consistent with your own experience, or anyone else's, maybe? Part of the reason that I was wondering is because the options in the Android app appear to indicate that JSON stream may actually use more battery, when it appears to be the opposite in my case. I also thought that it might be helpful to pass along my findings since the app asks to report if WebSockets uses less battery.

[...]"

Originally created by @binwiederhier on GitHub (Mar 29, 2022). Original GitHub issue: https://github.com/binwiederhier/ntfy/issues/190 I received this email. I shortened it a bit for the ticket. Emphasis I'll highlight the important bits **in bold**: "[...] After a couple days of using WebSockets, however, I noticed that it actually appears to consume as much as 2-3x more battery on my device than HTTP stream. On a day when I receive no notifications (just to make for an easy comparison), **HTTP stream always seems to consume about 0.3-0.5% of my battery per hour**, while **WebSockets appears to consume about 1% of my battery per hour**. This is on a six month old Pixel 5a running GrapheneOS with ntfy's battery usage set to Unrestricted to prevent it from being killed. I guess I was wondering if this was consistent with your own experience, or anyone else's, maybe? Part of the reason that I was wondering is because the options in the Android app appear to indicate that JSON stream may actually use more battery, when it appears to be the opposite in my case. I also thought that it might be helpful to pass along my findings since the app asks to report if WebSockets uses less battery. [...]"
BreizhHardware 2026-05-07 00:20:34 +02:00
Author
Owner

@binwiederhier commented on GitHub (Mar 29, 2022):

That is very peculiar. Others have reported the opposite. It must be heavily dependent on the phone and/or connection if the difference is so extreme.

Troubleshooting

Could you do the following:

  1. Go to Settings -> Record logs
  2. Go about your day, for at least 1-2 hours
  3. Go to Settings -> Copy/upload logs (you may choose to censor the logs)
  4. Switch the connection protocol (WS -> JSON, or vice versa, depending on what you started with)
  5. Go about your day, for at least 1-2 hours
  6. Go to Settings -> Copy/upload logs (you may choose to censor the logs)

Then paste the logs here or email me.

Keeping JSON stream 🤔

I am quite convinced that the WebSockets implementation is much better than the JSON stream one, and I had planned to get rid of the JSON stream implementation in June. However, given this drastic difference, I may just keep it around for longer/good depending on how much trouble it is to maintain it. It hasn't been any work to maintain it so far, so I could very well see it sticking around.

<!-- gh-comment-id:1081902048 --> @binwiederhier commented on GitHub (Mar 29, 2022): That is very peculiar. Others have reported the opposite. It must be heavily dependent on the phone and/or connection if the difference is so extreme. ## Troubleshooting Could you do the following: 1. Go to Settings -> Record logs 2. Go about your day, for at least 1-2 hours 3. Go to Settings -> Copy/upload logs (you may choose to censor the logs) 4. Switch the connection protocol (WS -> JSON, or vice versa, depending on what you started with) 5. Go about your day, for at least 1-2 hours 6. Go to Settings -> Copy/upload logs (you may choose to censor the logs) Then paste the logs here or email me. ## Keeping JSON stream :thinking: I am quite convinced that the WebSockets implementation is much better than the JSON stream one, and I had planned to get rid of the JSON stream implementation in June. However, given this drastic difference, I may just keep it around for longer/good depending on how much trouble it is to maintain it. It hasn't been any work to maintain it so far, so I could very well see it sticking around.
Author
Owner

@whats-a-diorama commented on GitHub (Mar 30, 2022):

Hi. I'm the one who spoke to you over email. Following up with some logs!

I had ntfy generating logs for four hours. Two hours with JSON stream, and two hours with WebSockets. The device sat in one place for nearly the entire time and didn't receive any ntfy notifications, which to be honest, is pretty typical usage for me. (It also matches how I was using the device when I experienced the greater battery drain from enabling WebSockets.)

I took a quick look at the logs myself for my own curiosity, and although I imagine they'll be more informative for you (being a whole lot more familiar with ntfy's code than I am!), the one obvious thing that did stick out to me is that the WebSockets log had an exception that was thrown at one point for what appears to possibly be a connection-related issue.

For what it's worth, I wasn't moving the device around, it generally has full bars in the spot that it was in, and I don't recall ever experiencing issues with my device losing its data connection in general. (Though of course I can't rule out a momentary lapse in its data connection there!) Additionally, one thing that I forgot to mention before is that I also run Signal, which also maintains a persistent WebSocket connection due to a lack of Google Play Services on my device. Signal's battery usage with WebSockets consistently averages about 0.5% per hour, including when ntfy's WebSocket usage was at about 1% per hour.

Anyway, I hope this is helpful. Let me know if you'd like me to test or provide anything else!

Thanks again for your help, and for all of your work on ntfy 🙂

ntfy-json-stream.txt
ntfy-websockets.txt

<!-- gh-comment-id:1082548626 --> @whats-a-diorama commented on GitHub (Mar 30, 2022): Hi. I'm the one who spoke to you over email. Following up with some logs! I had ntfy generating logs for four hours. Two hours with JSON stream, and two hours with WebSockets. The device sat in one place for nearly the entire time and didn't receive any ntfy notifications, which to be honest, is pretty typical usage for me. (It also matches how I was using the device when I experienced the greater battery drain from enabling WebSockets.) I took a quick look at the logs myself for my own curiosity, and although I imagine they'll be more informative for you (being a whole lot more familiar with ntfy's code than I am!), the one obvious thing that did stick out to me is that the WebSockets log had an exception that was thrown at one point for what appears to possibly be a connection-related issue. For what it's worth, I wasn't moving the device around, it generally has full bars in the spot that it was in, and I don't recall ever experiencing issues with my device losing its data connection in general. (Though of course I can't rule out a momentary lapse in its data connection there!) Additionally, one thing that I forgot to mention before is that I also run Signal, which also maintains a persistent WebSocket connection due to a lack of Google Play Services on my device. Signal's battery usage with WebSockets consistently averages about 0.5% per hour, including when ntfy's WebSocket usage was at about 1% per hour. Anyway, I hope this is helpful. Let me know if you'd like me to test or provide anything else! Thanks again for your help, and for all of your work on ntfy 🙂 [ntfy-json-stream.txt](https://github.com/binwiederhier/ntfy/files/8376279/ntfy-json-stream.txt) [ntfy-websockets.txt](https://github.com/binwiederhier/ntfy/files/8376280/ntfy-websockets.txt)
Author
Owner

@binwiederhier commented on GitHub (Mar 30, 2022):

Those logs are both very interesting and very boring at the same time.

Boring because nothing happens, no weird exceptions at all in both logs. The Software caused connection abort exception happens a lot when the phone goes into deep sleep. It just radically kills all connections. Happens on my device all the time. Nothing we can do about it, except wake locks, and then your battery will really be hurting.

The JSON HTTP stream log is interesting because it shows Connection is active only every few minutes, when it should be every 30s, which probably means that your phone OS is just not giving the app time to run, which is fine as long as that means that the connection isn't killed on either side.

I think if the JSON stream works for you, then stick with it. I think this experience is evidence enough to keep JSON stream around as an option. So I'll still switch to WebSockets by default, but I won't remove the option. I'll adjust the deprecation notice accordingly.

Thanks for the bug report!

<!-- gh-comment-id:1083048848 --> @binwiederhier commented on GitHub (Mar 30, 2022): Those logs are both very interesting and very boring at the same time. Boring because nothing happens, no weird exceptions at all in both logs. The `Software caused connection abort` exception happens a lot when the phone goes into deep sleep. It just radically kills all connections. Happens on my device all the time. Nothing we can do about it, except wake locks, and then your battery will really be hurting. The JSON HTTP stream log is interesting because it shows `Connection is active` only every few minutes, when it should be every 30s, which probably means that your phone OS is just not giving the app time to run, which is fine as long as that means that the connection isn't killed on either side. I think if the JSON stream works for you, then stick with it. I think this experience is evidence enough to keep JSON stream around as an option. So I'll still **switch to WebSockets by default, but I won't remove the option.** I'll adjust the deprecation notice accordingly. Thanks for the bug report!
Author
Owner

@binwiederhier commented on GitHub (Mar 30, 2022):

github.com/binwiederhier/ntfy@62512b7a1a

<!-- gh-comment-id:1083180440 --> @binwiederhier commented on GitHub (Mar 30, 2022): https://github.com/binwiederhier/ntfy/commit/62512b7a1aa76c886413e911ecf53e69052ca7c5
Author
Owner

@whats-a-diorama commented on GitHub (Mar 30, 2022):

Interesting!

If how my device behaves with regards to the JSON stream option is atypical, that definitely has me curious, as I was under the impression that my OS is pretty close to stock AOSP when it comes to stuff like that. But I guess even if there is something slightly unusual happening on my end, I haven't had any issues at all receiving ntfy notifications quickly while using JSON stream and a typical day's battery usage is around 5-6%. Considering how that's all without me having FCM, I certainly can't complain!

That sounds really great to me. Thanks so much for being so responsive and listening to my issue. If you'd ever like me to provide any logs again, just let me know!

<!-- gh-comment-id:1083563997 --> @whats-a-diorama commented on GitHub (Mar 30, 2022): Interesting! If how my device behaves with regards to the JSON stream option is atypical, that definitely has me curious, as I was under the impression that my OS is pretty close to stock AOSP when it comes to stuff like that. But I guess even if there is something slightly unusual happening on my end, I haven't had any issues at all receiving ntfy notifications quickly while using JSON stream and a typical day's battery usage is around 5-6%. Considering how that's all without me having FCM, I certainly can't complain! That sounds really great to me. Thanks so much for being so responsive and listening to my issue. If you'd ever like me to provide any logs again, just let me know!
Author
Owner

@binwiederhier commented on GitHub (Mar 30, 2022):

So I've learned in the last half year or so that not all Android devices are created equal. the manufacturers are pretty different in terms of their tuning, battery optimization and such.

day's battery usage is around 5-6%

That's pretty bad. My device, a OnePlus 8, uses 0-1% battery even with instant delivery enabled (no FCM). And many others have reported similar battery performance. Before we removed the wake lock, I'd have 4-5% per day, but since about 5-6 releases, it's been much much less.

I'm closing this for now. Let me know if there is anything else.

<!-- gh-comment-id:1083590835 --> @binwiederhier commented on GitHub (Mar 30, 2022): So I've learned in the last half year or so that not all Android devices are created equal. the manufacturers are pretty different in terms of their tuning, battery optimization and such. > day's battery usage is around 5-6% That's pretty bad. My device, a OnePlus 8, uses 0-1% battery even with instant delivery enabled (no FCM). And many others have reported similar battery performance. Before we removed the wake lock, I'd have 4-5% per day, but since about 5-6 releases, it's been much much less. I'm closing this for now. Let me know if there is anything else.
Author
Owner

@whats-a-diorama commented on GitHub (Mar 31, 2022):

That's pretty bad. My device, a OnePlus 8, uses 0-1% battery even with instant delivery enabled (no FCM). And many others have reported similar battery performance. Before we removed the wake lock, I'd have 4-5% per day, but since about 5-6 releases, it's been much much less.

Oof. And here I thought that 5-6% for 16-18 hours on JSON stream with no FCM was pretty good. Haha. Well that's entirely on me and my device, of course! I'll have to look into this.

I'm closing this for now. Let me know if there is anything else.

That sounds good. Thanks again for your help!

<!-- gh-comment-id:1083828581 --> @whats-a-diorama commented on GitHub (Mar 31, 2022): > That's pretty bad. My device, a OnePlus 8, uses 0-1% battery even with instant delivery enabled (no FCM). And many others have reported similar battery performance. Before we removed the wake lock, I'd have 4-5% per day, but since about 5-6 releases, it's been much much less. Oof. And here I thought that 5-6% for 16-18 hours on JSON stream with no FCM was pretty good. Haha. Well that's entirely on me and my device, of course! I'll have to look into this. > I'm closing this for now. Let me know if there is anything else. That sounds good. Thanks again for your help!
Author
Owner

@dcousens commented on GitHub (May 13, 2022):

My daily battery usage, no battery optimisation is <2% with notifications every 15 minutes, or unlisted (<1%) for intermittent notifications (~every 1-2 hours).

I am using a x-ndjson stream, and I would love for it to NOT be deprecated as it has been trivial to integrate with nodejs, using only the http built-ins - my self-hosted ntfy server is <120 lines with no other dependencies.
I used websockets for a few days, but the added complexity didn't benefit me or my battery life, personally.

Notification latency ranged from 1-2 seconds to 1-2 minutes depending on how long the phone is asleep, this did not vary between the x-ndjson stream or websockets either. This is the same as my experience with other applications that are using GCM.

res.writeHead(200, { 'Content-Type': 'application/x-ndjson' })
res.socket.setKeepAlive(true, 45) // same as ntfy.sh
  
// ...
  
const server = http.createServer(app)
server.keepAliveTimeout = 0
server.timeout = 0
server.listen(process.env.PORT)
<!-- gh-comment-id:1125564002 --> @dcousens commented on GitHub (May 13, 2022): My daily battery usage, no battery optimisation is <2% with notifications every 15 minutes, or unlisted (<1%) for intermittent notifications (~every 1-2 hours). I am using a `x-ndjson` stream, and I would love for it to **NOT** be deprecated as it has been trivial to integrate with nodejs, using only the `http` built-ins - my self-hosted ntfy server is <120 lines with no other dependencies. I used websockets for a few days, but the added complexity didn't benefit me or my battery life, personally. Notification latency ranged from 1-2 seconds to 1-2 minutes depending on how long the phone is asleep, this did not vary between the `x-ndjson` stream or websockets either. This is the same as my experience with other applications that are using GCM. ``` res.writeHead(200, { 'Content-Type': 'application/x-ndjson' }) res.socket.setKeepAlive(true, 45) // same as ntfy.sh // ... const server = http.createServer(app) server.keepAliveTimeout = 0 server.timeout = 0 server.listen(process.env.PORT) ```
Author
Owner

@binwiederhier commented on GitHub (May 13, 2022):

I am using a x-ndjson stream, and I would love for it to NOT be deprecated as it has been trivial to integrate with nodejs, using only the http built-ins - my self-hosted ntfy server is <120 lines with no other dependencies.

The deprecation was only for the Android app, and even that is something that I've already decided to revert. I'll switch to WebSockets by default in the Android app, but keep the JSON stream switcher in the settings.

I am using a x-ndjson stream, and I would love for it to NOT be deprecated as it has been trivial to integrate with nodejs, using only the http built-ins - my self-hosted ntfy server is <120 lines with no other dependencies.

This is very very phone specific. You can record the logs (Settings -> Record logs) and watch how often your phone kills the connection ("Software caused connection abort"). Your are right though, when the phone has been asleep longer, messages do take a few more seconds to be delivered.

I will say this: WebSockets on Android is much much faster to recover from connection resets. Much faster!

<!-- gh-comment-id:1125567978 --> @binwiederhier commented on GitHub (May 13, 2022): > I am using a x-ndjson stream, and I would love for it to NOT be deprecated as it has been trivial to integrate with nodejs, using only the http built-ins - my self-hosted ntfy server is <120 lines with no other dependencies. The deprecation was only for the Android app, and even that is something that I've already decided to revert. I'll switch to WebSockets by default in the Android app, but keep the JSON stream switcher in the settings. > I am using a x-ndjson stream, and I would love for it to NOT be deprecated as it has been trivial to integrate with nodejs, using only the http built-ins - my self-hosted ntfy server is <120 lines with no other dependencies. This is very very phone specific. You can record the logs (Settings -> Record logs) and watch how often your phone kills the connection ("Software caused connection abort"). Your are right though, when the phone has been asleep longer, messages do take a few more seconds to be delivered. I will say this: WebSockets on Android is much much faster to recover from connection resets. Much faster!
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/ntfy#149
No description provided.