Detecting hotspot connection without internet

Is there an effective method for detecting if an app is connected to a hotspot without an internet connection?

Apple addresses this challenge by attempting to access one of their websites, like https://captive.apple.com, and searching for a success string. If this string isn't found, indicating a captive portal, the app can respond accordingly.

Our customers utilize the app while driving, leading it to connect to various hotspots they've previously used. Frequently, these hotspots return an HTML page from the hotspot service rather than our backend response.

Does anyone know if there is a better way to detect this?

You can (and almost certainly should) use HTTPS on the connection to your backend system, which will at least produce a networking-level error instead of a decoding error when the hotspot tries to intercept the connection to your backend.

Yes, that could work. This is not about the error the app shows, but about avoiding this kind of connection. Our backend can reply with HTML too if an internal error occurs.

Ultimately, we want to detect hotspot connections with captive portals (either to log in or a promotion web page) and present an alert to the customer to disconnect from them.

Yep, using HTTPS will allow your app to detect with cryptographic certainty that it's not connected to your backend (whatever the reason, including captive portals), and surface that as a networking error in Swift which you would then turn into a user-facing error telling them they need to change their internet connection.

We are using https at the moment. How would it detect this with cryptographic? Do you mean checking some specific headers in the response?

You're definitely not using HTTPS in your connection to your backend if your app is able to receive and attempt to decode a response from the captive portal without an error being returned - the whole point of HTTPS is that any attempt to modify a connection in any way will be detected and result in an error. In general, this would be thrown as a Swift Error (though it depends on exactly how you're connecting to your backend), but in no case would it be in headers as all HTTPS errors occur before that.

Search your code to make sure every time your backend is accessed it's prefixed with https:// and not http:// (or without a prefix at all, just backend.example.com), otherwise we'll need to see a code snippet of where you make the requests.