Cannot get WiFi SSID inside launchctl agent

I am developing a macOS application that depends on noticing when the user's computer switches WiFi association, and the SSID determines specific actions. I am currently testing on Tahoe and found that using CoreWLAN can even get notifications and discover the actual SSID inside an app, as long as the app is signed with a real certificate and a corresponding profile is installed on my development machine. The app, however, installs and launches a launchctl agent, which will always be running and hence the component to discover changes and act upon them.

Although app and agent both have their own bundle identifier, both configured in the portal, the agent always received a redacted SSID (nil), while the app does not.

The only app entitlement currently is "com.apple.security.get-task-allow = true", which I don't think has anything to do with this. The agent has: com.apple.application-identifier com.apple.developer.team-identifier com.apple.security.get-task-allow com.apple.security.personal-information.location

Both have asked for permission, and both have location services enabled in system settings. The agent runs as an LSUIElement=1, headless/background configuration.

So, am I missing something, a step, or is there a fundamental restriction on an agent that makes this an impossible task? (Right now, it runs a shortcut to discover the name, but requires the user to create it, and it has side effects I'd rather not see, like the flashing indicator in the menu bar)

On recent versions of macOS a program needs the Location privilege (from System Settings > Privacy & Security) to access SSID information. It should be feasible for a launchd agent to get that — unlike, say, a launchd daemon — but it’s not without its challenges. My usual advice here is:

  1. Install the from a container app using SMAppService. This ensures that the system understands the relationship between the app and the agent.
  2. Request the Location privilege in the container app.
  3. In the agent, confirm that you have the Location privilege before attempting to do anything with Core WLAN. There’s a new-fangled way to do this but I tend to rely on the old ways.

I’ve run through this process for other privileges and it works a treat. However, the Location privilege is kinda weird — it’s not managed by the standard TCC infrastructure — so I’m not 100% sure this will work in that case. But give it a whirl and lemme know how you get along.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks again for your guidance. I’m following up with concrete implementation details and current repro logs because we still cannot read SSID via CoreWLAN from our agent process.

Environment:

macOS 26.3 (build 25D125)
Xcode 26.2 (17C52)
Wi-Fi interface: en0
Agent bundle ID: com.acme.SSIDInspector.Agent
App bundle ID: com.acme.SSIDInspector
How we launch the agent:

We use SMAppService.agent(plistName:) from the main app. Embedded LaunchAgent plist path in app bundle: com.acme.SSIDInspector.Agent.plist Plist details:

Label = com.acme.SSIDInspector.Agent
BundleProgram = Contents/Resources/SSIDInspectorAgent.app/Contents/MacOS/SSIDInspectorAgent
MachServices includes com.acme.SSIDInspector.Agent
RunAtLoad = true, KeepAlive = true
We call register()/unregister() on SMAppService, and use XPC (NSXPCConnection to mach service) to verify the agent is running/reachable.

Privacy/authorization setup:

Agent Info.plist usage strings are present:

  • NSLocationAlwaysUsageDescription
  • NSLocationUsageDescription
  • NSLocationWhenInUseUsageDescription

Agent entitlement includes:

  • com.apple.security.personal-information.location = true

Agent requests location authorization via CLLocationManager.requestAlwaysAuthorization().

On startup we consistently see: notDetermined -> authorizedAlways one warmup location update received and stopped. Observed CoreWLAN behavior:

In the agent process, CWWiFiClient.shared().interface()?.ssid() remains nil. At the same time, CoreWLAN interface data indicates association (BSSID/channel present), so our diagnostic path marks this as redacted/unavailable SSID. Representative log sequence (2026-02-26 13:16:02 local):

location authorization changed: authorizedAlways
location authorization granted; CoreWLAN SSID reads should be eligible
corewlan summary currentInterface=en0 currentSSID=nil interfaces=en0:ssid=nil
probe source corewlan returned redacted SSID marker
observed SSID becomes <SSID Redacted> (not actual SSID)
Important note:

The remaining issue is specifically CoreWLAN SSID visibility in this LaunchAgent context.

Question: Given this setup, is there any additional requirement/restriction for SSID visibility when the process is a background LaunchAgent registered via SMAppService (as opposed to a foreground app process)?

If helpful, I can provide a minimal reproducible sample project with this exact architecture.

Thank you.

“Also, in System Settings > Privacy & Security > Location Services, we consistently see duplicate SSIDInspector entries (one with a warning icon) plus SSIDInspectorAgent. This suggests stale or conflicting TCC identity records. We are resetting TCC and re-registering via SMAppService, but wanted to confirm whether duplicate/stale TCC rows can affect CoreWLAN SSID visibility for a LaunchAgent process.”

Disregard that last remark about duplicate tcc entries. I cleaned everything out manually.

Thanks for all the extra info. I have a couple of comments.

I cleaned everything out manually.

How exactly?

I try to avoid testing this stuff on my development machine because the constant build / run / debug cycle exposes edge cases that are rarely seen on normal user machines. I explain my standard approach for this sort of testing in Testing a Notarised Product. It’s discussing a different technology, but the general approach will work here.

IMPORTANT Most VM apps don’t virtualise Wi-Fi, so you won’t be able to test the Core WLAN side of this. But you can test the Core Location side, and I think that’s what’s key here.

Agent requests location authorization

Have you tried requesting location authorisation from the container app? That should work because the app is just a normal GUI application. And I’m hoping that this authorisation will then be available to your agent because the app is the responsible code for your agent.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Cannot get WiFi SSID inside launchctl agent
 
 
Q