A native macOS menu bar application that bridges Apple's Find My friend locations to Home Assistant via MQTT auto-discovery.
Apple's Find My app can track shared friend and family locations, but no existing Home Assistant integration can access this data. Integrations like iCloud3 and FindMySync only support your own devices and AirTags via cache files. Since macOS 14.4+, even those cache files are encrypted.
FindMyFriends solves this by reading location data directly from the Find My app using macOS Accessibility APIs, geocoding addresses to GPS coordinates, and publishing real-time location updates to Home Assistant.
- Multi-person tracking — track any number of friends/family members simultaneously
- Sequential polling with configurable intervals (per-cycle randomization to avoid detection patterns)
- Movement detection — only publishes updates when a person moves beyond a configurable threshold
- Address extraction — reads full street addresses from Find My's detail panel, not just city-level data
- MQTT auto-discovery — tracked people automatically appear as
device_trackerentities in Home Assistant - Zone-aware states — configurable zones (Home, Work, etc.) determine
home/not_home/ zone name states - Full attribute publishing — latitude, longitude, GPS accuracy, street address, location label, and timestamps
- Retained messages — location data persists across Home Assistant restarts
When Find My shows only a neighborhood name (e.g., "Northwest Los Angelas, Los Angelas, CA") instead of a street address, Nominatim geocoding can be off by 1000+ meters. The optional AI vision feature:
- Captures a screenshot of the Find My map window
- Sends it to the Anthropic API where the AI reads visible street names and the pin position
- Returns GPS coordinates or an intersection — coordinates bypass geocoding entirely for maximum accuracy
- Falls back gracefully if disabled, unconfigured, or if the API call fails
- Supports Haiku 4.5 (
$0.002/call) and Sonnet 4.5 ($0.01/call)
- Menu bar app — lives in your menu bar, keeps running when the window is closed
- Sleep schedule — automatically pauses tracking during configured hours
- Export/Import — backup and restore all settings as JSON
- Live log viewer — real-time activity log with filtering, search, and file logging
- Geocoding cache — minimizes Nominatim API calls with in-memory and on-disk caching
Main Window
The main window shows tracked people on the left with tracking controls and a live log on the right.
- macOS 13.0 (Ventura) or later
- Apple's Find My app with at least one shared friend/family contact
- Home Assistant with an MQTT broker (Mosquitto, EMQX, etc.)
- Anthropic API key (optional, only for AI-enhanced location feature)
- Download
FindMyTracker.app.zipfrom the latest release - Unzip and move
FindMyTracker.appto your Applications folder - Important: The app is not code-signed or notarized. On first launch:
- Right-click the app and select Open (do not double-click)
- Click Open in the Gatekeeper dialog
- Alternatively, go to System Settings > Privacy & Security and click Open Anyway after the first blocked attempt
git clone https://github.com/bytePatrol/FindMyFriends.git
cd FindMyFriends
./build-app.sh
open FindMyTracker.appRequires Xcode or Xcode Command Line Tools (for the Swift toolchain).
FindMyFriends requires specific macOS permissions to function. The app will guide you through granting each one on first launch.
| Permission | Why It's Needed | How to Grant |
|---|---|---|
| Accessibility | Read UI elements from the Find My app (sidebar entries, address labels) | System Settings > Privacy & Security > Accessibility > Enable FindMyTracker |
| Automation (Find My) | Send AppleScript commands to Find My (click sidebar entries, open detail panels) | Granted automatically on first use via system prompt |
| Permission | Why It's Needed | How to Grant |
|---|---|---|
| Screen Recording | Capture the Find My map window for AI-enhanced location (only if AI feature is enabled) | System Settings > Privacy & Security > Screen Recording > Enable FindMyTracker |
Note: After granting Accessibility or Screen Recording permissions, you may need to restart the app for changes to take effect.
On first launch, the app displays a permissions screen. Click the buttons to open System Settings and grant each permission. The app checks permissions in real time and proceeds automatically once both are granted.
Click the network icon in the bottom toolbar to open MQTT settings:
- Broker — hostname or IP of your MQTT broker
- Port — default
1883(or8883for TLS) - Username / Password — your MQTT credentials
- TLS — enable if your broker requires it
- Topic Prefix — default
homeassistant(matches HA's MQTT discovery prefix)
Use Test Connection to verify connectivity before saving.
Click Scan People to discover all contacts visible in Find My's People tab. The app reads the sidebar and lists everyone it finds. Use the checkboxes to select who you want to track.
Click the map pin icon to add known locations (zones). Each zone has a name, GPS coordinates, and radius. When a tracked person is within a zone's radius, their Home Assistant state reflects the zone name instead of not_home.
Click Start to begin. The app will:
- Connect to your MQTT broker
- Publish auto-discovery configs for each tracked person
- Poll each person sequentially, extracting their location from Find My
- Geocode addresses to GPS coordinates
- Publish state and attribute updates to Home Assistant
Click the brain icon to configure AI vision:
- Enable the feature
- Enter your Anthropic API key
- Select a model (Haiku 4.5 recommended for cost)
- Grant Screen Recording permission if prompted
- Use Test AI Vision to verify it's working
The AI feature only activates when Find My shows a neighborhood name instead of a street address. Street addresses are geocoded normally without using the AI.
Once tracking starts, each person appears as a device_tracker entity:
# Entity: device_tracker.findmy_john
state: home # or "not_home", or a zone name
attributes:
latitude: 33.8752
longitude: -117.5664
gps_accuracy: 50
source_type: gps
address: "251 E 6th St, Los Angeles, CA 90014"
location_label: "Home"
time_ago: "1 minute ago"
friendly_name: "FindMy John"Use these entities in automations, presence detection, or the Home Assistant map.
FindMyFriends/
├── Package.swift # SPM manifest (CocoaMQTT dependency)
├── build-app.sh # Build script → .app bundle
├── Sources/FindMyTracker/
│ ├── App/
│ │ ├── FindMyTrackerApp.swift # @main entry, menu bar setup
│ │ ├── AppDelegate.swift # NSApplicationDelegate lifecycle
│ │ └── ServiceContainer.swift # Dependency injection container
│ ├── Models/
│ │ ├── AppState.swift # Observable app state, persistence
│ │ ├── TrackedPerson.swift # Person model with location data
│ │ ├── KnownLocation.swift # Zone model (name, coords, radius)
│ │ ├── MQTTConfig.swift # MQTT connection configuration
│ │ └── LogEntry.swift # Log entry model with levels
│ ├── Services/
│ │ ├── FindMyService.swift # AppleScript/Accessibility extraction
│ │ ├── TrackingEngine.swift # Main polling loop orchestrator
│ │ ├── GeocodingService.swift # Nominatim geocoding with cache
│ │ ├── MQTTService.swift # CocoaMQTT wrapper, auto-discovery
│ │ ├── VisionLocationService.swift # AI screenshot analysis (optional)
│ │ └── PermissionsService.swift # macOS permission checks
│ ├── Views/
│ │ ├── MainWindowView.swift # Split view layout
│ │ ├── PeopleListView.swift # Sidebar with person list
│ │ ├── TrackingControlsView.swift # Start/Pause/Stop controls
│ │ ├── LogView.swift # Live log with filtering
│ │ ├── PermissionsView.swift # First-launch permission guide
│ │ ├── MQTTSettingsView.swift # MQTT configuration sheet
│ │ ├── ZonesSettingsView.swift # Zone editor sheet
│ │ ├── SleepSettingsView.swift # Sleep schedule sheet
│ │ ├── AISettingsView.swift # AI vision configuration sheet
│ │ └── MenuBarView.swift # Menu bar dropdown
│ ├── Utilities/
│ │ ├── AppLogger.swift # Thread-safe logger (UI + file)
│ │ ├── Haversine.swift # GPS distance calculation
│ │ └── ExportImport.swift # JSON settings export/import
│ └── Resources/
│ ├── Info.plist # App metadata and usage descriptions
│ └── FindMyTracker.entitlements # Non-sandboxed + AppleEvents
FindMyFriends uses a three-step extraction method via macOS Accessibility APIs:
- Click the person's name in the Find My sidebar (clicks the
static textelement directly) - Click "More Info" on the map callout to open the detail panel
- Read the detail panel labels via
AXIdentifierattributes (PrimaryLabel,SecondaryLabel,SecondaryTitleLabel,TertiaryLabel)
This yields the full street address (e.g., "1436 S Lombard Dr, Fullerton, CA 92832") rather than just city-level data. The address is then geocoded via OpenStreetMap's Nominatim API with a multi-strategy fallback system.
Why Accessibility APIs? Friend/family locations are only available in Find My's UI. They are not stored in any cache file, plist, or API endpoint accessible to third-party apps. Screen scraping via Accessibility is the only viable approach.
All data is stored in ~/.config/findmy-tracker/:
| File | Purpose |
|---|---|
tracker.log |
Application log file |
geocode_cache.json |
Geocoding results cache (5-minute TTL) |
App settings (tracked people, MQTT config, zones, polling intervals) are stored in macOS UserDefaults.
| Issue | Solution |
|---|---|
| App blocked by Gatekeeper | Right-click > Open, or System Settings > Privacy & Security > Open Anyway |
| "No people discovered" | Ensure Find My is open with the People tab selected before scanning |
| Accessibility permission not working | Restart the app after granting permission in System Settings |
| MQTT connection fails | Verify broker address, port, and credentials; use Test Connection |
| Geocoding returns wrong location | This happens with neighborhood-level addresses; enable AI-enhanced location for better accuracy |
| AI Vision screenshot fails | Grant Screen Recording permission and restart the app |
| Find My shows "No location found" | The contact has stopped sharing their location or their device is offline |
- No data leaves your Mac except MQTT messages to your broker and Nominatim geocoding requests
- API keys and passwords are stored locally in macOS UserDefaults, never transmitted elsewhere
- AI screenshots are sent to the Anthropic API only when the feature is explicitly enabled and configured
- No telemetry, analytics, or tracking of any kind
- The app is not sandboxed (required for Accessibility API access)
MIT License. See LICENSE for details.