One evening I opened Companion, scanned the QR code, and waited about ten minutes. The screen stayed white. No error, no spinner that went anywhere.
The Wi-Fi icon was there. The same project was running fine in my browser. Nothing was reaching the phone.
What I did first was restart the router. Then I deleted and reinstalled Companion. Neither helped. It was only when I opened the Settings app that I found it: the Local Network permission had been turned off.
That cost me about fifteen minutes, and the lesson wasn't about networking at all. It was about order. The harder something is to undo, the later it belongs in the sequence. Restarts and reinstalls now sit at the very end of my list.
"Nothing appears" and "it stops after a while" are different problems
Both feel like "it won't connect," but they happen in different places. If you don't separate them first, you can't tell whether something you did actually fixed it.
| What you see | Layer to suspect | First place to look |
|---|---|---|
| QR scans, screen stays blank | The path between device and router | Local Network permission |
| It loads, then dies a few minutes in | Power management on the phone | Low Power Mode, auto-lock |
| Works on the Mac, not on this iPhone | Something specific to that phone | Private Wi-Fi Address |
| Fails at home, works elsewhere | Router-side isolation | Guest network, AP isolation |
Mixing up the first two rows and restarting over and over was the slowest path I found. Now I say it out loud before touching anything: blank means routing, dies later means power.
Split the problem in half in one minute
Before you start doubting your home network, try once without it. Turn on Personal Hotspot on the iPhone, connect your computer to that hotspot, and scan the same QR code again.
If the preview appears, the phone and Companion are fine together, and the problem lives in your home router. If it still doesn't appear, it's the device or the account side.
That single step cuts roughly half the search space. It does use mobile data, so switch back as soon as you have your answer.
It's worth being strict about what counts as a result here. A preview that appears and then immediately stalls is not the same as one that never arrives, and on a hotspot the signal can be weak enough to muddy the difference. I wait for the first screen to render and respond to a tap before I call it a pass.
I write the result down, one line, right then. When the same symptom shows up the following week, I don't trust myself to remember which half it was last time.
Four things to check on the iPhone
If the device side is implicated, I go through Settings from the top. All four of these can end up in a state you never chose deliberately.
| Where to look | What it does | How to undo it |
|---|---|---|
| Privacy & Security > Local Network | Blocks discovery of other devices on the same Wi-Fi | Switch Companion back on |
| Wi-Fi > current network > Private Wi-Fi Address | Rotates the device identifier, so router allowlists stop matching | Set it to Fixed for that network only |
| Battery > Low Power Mode | Throttles activity once the screen goes dark | Turn it off while you're testing |
| General > VPN & Device Management | Can route traffic somewhere you didn't expect | Disconnect for the duration of the test |
The second row deserves a word too, because it fails in a way that looks random. Private Wi-Fi Address is set per network, and it rotates. If your router has any kind of allowlist or reserved-address rule tied to the phone, the match quietly stops holding and the symptom arrives days after the change that caused it.
The first row is the one I hit most often. iOS asks for that permission exactly once, and if you tap Don't Allow, the prompt never comes back. Nothing on screen tells you why the preview is missing, so unless you know where the switch lives, there's no trail to follow.
A note on iCloud Private Relay, since it comes up: it mainly covers Safari and some unencrypted traffic, and it doesn't sit between two devices on the same Wi-Fi. I'd only add it to the list if there's a managed configuration profile from work or school on the phone.
Two things on the router side
If the phone comes back clean, look at the house. There isn't much to check — realistically, two things.
The first is AP isolation. Depending on the manufacturer it might be called Privacy Separator, client isolation, or something about blocking device-to-device traffic. When it's on, two devices joined to the same SSID can't see each other at all. Guest networks often ship with it enabled, which is how I lost an afternoon once.
The second is simply being on a different network than you think. If your 2.4 GHz and 5 GHz bands have separate SSIDs, your laptop and your phone may be on different names. Mesh setups can do the same thing when a device latches onto a different node. Phones are especially good at quietly reconnecting to whichever access point had the stronger signal when you last walked through the house.
The quickest way to rule this out is to read the network name on both devices and compare them character for character, rather than trusting that they're "on the Wi-Fi." Twice now I've found a trailing -5G I'd never noticed, on a network I set up myself.
| Setting | Common label | What to do while testing |
|---|---|---|
| Device-to-device blocking | AP isolation / Privacy Separator | Turn off temporarily |
| Visitor network | Guest SSID | Don't use it for testing |
| Per-band SSID split | Names ending in -A or -G | Put both devices on the same one |
I've rarely had something survive all of that. If it does, that's the moment to restart the router and reinstall Companion — last, not first, because those are the steps that erase the evidence you'd need to understand what happened.
What you learn here comes back in your own app
There's a second half to this detour. The Local Network permission isn't a Companion quirk. Your own app needs it too, the moment it tries to find anything else on the same network.
In Expo you declare the purpose in app.json. Without it, iOS never shows the permission prompt at all — your discovery code simply finds nothing.
{
"expo": {
"ios": {
"infoPlist": {
"NSLocalNetworkUsageDescription": "Used to find speakers on your Wi-Fi network.",
"NSBonjourServices": ["_myapp._tcp"]
}
}
}
}NSLocalNetworkUsageDescription is the sentence the user reads in the prompt. NSBonjourServices lists the service types you intend to browse for; anything you forget to declare stays invisible even after permission is granted.
One thing I've grown careful about is the wording. Concrete purposes get accepted far more often than vague ones. "Used for communication" gives the reader nothing to decide with. And as we just saw, this prompt appears once — after a decline, the only way back is buried in Settings. So: a prompt you get one shot at deserves a sentence that lands on the first read.
I've rewritten those strings in my own published apps more than once. The first version was almost always written for me rather than for the person holding the phone.
One thing to do today
Open Settings, go to Privacy & Security, and tap Local Network. Check that Companion is listed and switched on. That's the whole task.
The next time you're staring at a blank preview, that memory will shorten the first minute. For me it's been the difference between fifteen minutes and one.
Thank you for reading. If you're stuck at the same white screen, I hope this trims the detour a little.