wifi – iOS 16 displays captive portal when using NEHotspotConfigurationManager to connect IoT device


We maintain an iOS app that connects our IoT devices to the internet. Due to historical reasons, some of these IoT devices host a captive portal page embedded in the firmware. With iOS 13, 14, and 15, we have been able to connect to the device’s access point (AP) and finish onboarding the device to wifi without any issue.

Unfortunately, when iOS 16 came out, the process is not as smooth as it should be. Now, after connecting to the device’s AP, the captive portal is displayed while the user is on my app. The captive portal should not be shown.

Here is the gist of the code we use to connect to the device’s AP (in Swift):

    let hcm = NEHotspotConfigurationManager.shared
    let config = NEHotspotConfiguration(ssidPrefix: "our-prefix-")
    config.joinOnce = true
    hcm.apply(config) {

Is there anything we can do to prevent the captive portal from being displayed?

Here are some things we’ve looked into:

  • Yes, we can update the firmware to remove the captive portal. Updating the firmware for all the devices in the field and on the shelves is a very expensive option.
  • We have not tried using NEHotspotNetwork & NEHotspotHelper. That would require applying a different entitlement to our app and potentially restarting the approval process with Apple. We would really like to avoid that.
  • Yes, this process works perfectly fine in Android. About half our users are on iOS though.
  • Yes, the user can finish onboarding their device even with the captive portal popping up occasionally. However, if they dismiss the captive portal instead of waiting for it to error out they will drop off the AP and have to start over.