Rich notification image previews broken in v5.x — iOS app update? confirmed root cause?

Symptom: Text-only push notifications work. Image thumbnails in the notification never load — on any current iPhone 15 iOS 26, or 4th gen iPad Pro. regardless of network setup, certs, or server config. Interestingly, some older devices/older app installs do still get the image preview, which turned out to be the key clue.first gen iPad Pro, low version iOS app.

The iOS app registers for notifications with a GET request that includes a 64-bit reference number (ref=<64-bit value>) identifying that specific registration. When a motion event fires, the server is supposed to send that same ref back in the push payload so the notification extension can match the incoming push to a pending registration, then fetch the image using the connection info tied to that match.

On registration, the app sends a 64-bit reference number identifying that request, e.g.:

ref (64-bit, as registered) = 0x1A2B3C4D5E6F7890

The server is supposed to echo that same value back in the push payload so the phone's notification extension can match the incoming push to the registration it made, then fetch the image using the connection info tied to that match.

What actually gets stored and pushed back is the value truncated to a 32-bit signed int — only the low 32 bits survive:

ref (as pushed back) = 0x5E6F7890

(Hex placeholder to illustrate the mechanism, not a real captured value — but the relationship is exact in every case I captured: low 32 bits preserved, high 32 bits silently dropped.) It's consistent with the value being written through a %d-style (32-bit) format specifier somewhere in the server's storage/push code, where a 64-bit-safe specifier is needed.

Why the failure is silent instead of a timeout: the extension never gets far enough to hit the network. It receives the push, tries to match the truncated value against the full ref it registered with, finds no match, and gives up in under 30ms — before ever calling out to fetch the image. The fetch isn't failing; it's never attempted.

Confirmed server-side, not device-side: registered the same phone against two server instances the same day — one running the current major version, one running the version in question. The current major version stored/pushed the full 64-bit ref intact; the other truncated it. Same device, same app build, same day, different result depending only on server version.

Confirmed not fixed by the latest point release: binary-diffed the newest 5.x build against the prior one specifically to check this. The push payload format and ref handling are byte-identical between the two — whatever else changed in that release, this wasn't touched.

Also ruled out: valid end-to-end cert chain, correct app entitlements per the actual provisioning profile, and a from-scratch reinstall with all local state wiped — identical failure on a completely fresh, freshly-licensed install.

Given that the current major version's push payload already formats this value correctly, and the fix on the older version's side would just be widening how the ref is stored/formatted rather than any kind of redesign — is this a known issue that's been triaged and just hasn't been prioritized, since it happens to nudge anyone who wants working image previews toward the paid upgrade?

I Can share the raw before/after capture if anyone wants to verify.

Comments

  • Ben
    Ben
    edited July 30

    Thanks for this thorough report - your diagnosis is exactly right.

    What happened is that in an iOS app update a few months ago we widened the notification reference from a 32-bit to a 64-bit value, as a general robustness improvement: this reduces the chance of two servers colliding on the same reference. Version 6 stores and echoes that back correctly. Version 5 stores it in a 32-bit integer, so it keeps only the low 32 bits, and the value that comes back in the push no longer matches what the app registered. The extension can't tie the push to a server, so it never gets as far as requesting the image.

    That also explains the pattern you spotted with older installs. The reference is generated once, when a server is first added, and reused from then on. Any server added before that update still has a 32-bit reference, which survives the round trip through v5 intact. A fresh install, or re-adding the server, mints a 64-bit one and breaks.

    To be clear, this was not intentional and there's no upgrade nudge here, it's an improvement designed for v6, which just happens to break in v5 because this older software has been discontinued for a while now and we no longer test with it.

    We've now fixed this in our iOS app codebase, so when the next version of the app is released, this will just start working again.

  • Thanks Ben! Man, you are always so on top of it! Your hard work and attention to all of us doesn’t go unnoticed. Cheers.

  • Many thanks, that's much appreciated!

  • Good morning, Ben. Hope you’re doing well.

    Do you have any update or eta s0n on the revised app you mentioned in your response?

    I monitor and maintain NVR servers, smart home integrations, security systems, and related infrastructure for several clients. A number of them purchased SecuritySpy based on my recommendation. Most have since upgraded to 6.0, and some have moved to other solutions, but two clients with relatively high camera counts are still running 5.5.11.

    For those clients, 5.x has been stable and has met their needs for years. They have no interest in changing or upgrading software that was functioning properly, particularly when the issue they’re now experiencing isn’t the result of an OS change, hardware failure, or something on their end, but rather a change elsewhere that broke previously working functionality.

    I’ve taken some heat from them over this because I was the one who recommended the software, and I understand their position. I also have a hard time justifying asking them to pay for an upgrade to 6.0 simply to regain a feature that was part of the product they originally purchased and that functioned correctly for years. I also now can’t justify billing them for my own time consisting of identifying, resolving and implementing the a solution, So that now puts me of pocket with both my time and money.

    I completely understand that older versions eventually reach end-of-support and that continued development has to be funded. However, I think there’s an important distinction between expecting new features or ongoing support for an older release and losing an existing feature because of a later developer-side change. In this case, absent that breaking change, their existing installations would presumably still be functioning as they always had.

    That’s really the issue I’m hoping the updated app will address. If you have any indication of when it might be available, I’d greatly appreciate an update.

  • Sorry about the delay here, it's simply that we have been focussing more on the macOS software this last month. I understand that you are in a difficult position here, and we'll make sure to get an iOS app update out this coming week, which will include this fix.

  • ONLYONE
    edited September 11

    Hell yea Ben 🔥

  • Hi @ONLYONE just to let you know, we've now submitted the iOS update to the App Store. It needs to go through app review to be approved by Apple before it will be available - this usually takes a day or so, but may be longer over the weekend. It will hopefully be there by Monday.

  • Update: the new version (1.8.10) is now available from the App Store.