Wander is an open-source alternative to the paid iPhone location-spoofing apps. It drives Apple's own developer location-simulation service over USB, so there is no jailbreak, no profile to install, and nothing added to the phone.
Pick a spot on the map and your iPhone believes it is there. Draw a path and it walks, cycles or drives along it at a speed you choose.
Tested end to end on iOS 27.0.
The spoof only lasts while the phone is plugged into this Mac. Wander holds a developer session open for as long as it is running; the moment that session closes — you quit the app, unplug the cable, reboot the phone — the real location comes back. Every tool in this category works this way, including the paid ones.
That makes Wander a good fit for testing location-dependent apps and for geo-restricted content at your desk. It is a poor fit for appearing somewhere else all day, because your phone has to stay on a cable to do it.
Requirements
| Mac | macOS 11 or newer. Xcode is not required. |
| iPhone | iOS 17 or newer for the tunnel path; older versions use the legacy path. |
| Cable | USB. Wi-Fi pairing is not supported yet. |
| On the phone | Developer Mode on, and trusted with this Mac. |
| Root | Only for tunneld on iOS 17+ — see Run. Wander itself never runs as root. |
Wander changes what your own device reports about itself. Whether it is appropriate to show a fabricated location to a particular person or service is your call, and some services' terms prohibit it.
git clone https://github.com/owenautosport/wander.git
cd wander
# Frontend
npm install
# Daemon
cd daemon
uv venv .venv && uv pip install --python .venv/bin/python -e ".[dev]"
cd ..Then, on the iPhone: Settings → Privacy & Security → Developer Mode → On, and restart the phone. Plug it in, unlock it, and tap Trust.
iOS 17 and newer need a privileged tunnel helper. The phone is reached over a
network tunnel, and creating one requires root — confirmed on iOS 27.0, which
fails with Failed to create any utun interface without it. Rather than run
Wander as root, start pymobiledevice3's tunneld, whose only job is to own
tunnels, and leave it running in a Terminal:
sudo daemon/.venv/bin/pymobiledevice3 remote tunneldWander borrows that tunnel automatically. Only tunneld runs as root.
npm run app # the Mac appThe first connection takes a minute or so while the Developer Disk Image is downloaded and mounted; later ones take a few seconds.
To work on the interface with no iPhone attached, run the daemon against an in-memory phone and open the UI in a browser:
npm run daemon:fake # terminal 1
npm run dev # terminal 2 — then open http://localhost:1420| Click the map | Jump the phone to that point. |
| Shift-click | Drop a route waypoint. Two or more, then Start. |
| Search | Find a place by name. |
| Save this spot | Keep somewhere you use often. |
| GPS wander | A few metres of drift, so a resting fix does not look synthetic. |
| ⌘. | Re-centre on the phone. |
| Stop & restore | Hand the real location back. |
Quitting Wander restores the real location too — the daemon clears the simulation on the way out rather than leaving it stuck.
Tauri window (Rust) ← owns the window and the daemon's lifetime
│ spawns, reads {port, token} from stdout
▼
wanderd (Python) ← all device logic lives here
│ usbmux → CoreDeviceTunnelProxy → RemoteXPC tunnel
▼ → DVT LocationSimulation
iPhone
The daemon holds the developer session open for the whole session rather than reconnecting per fix, because the simulated location dies with the connection — and a route pushes a new fix every second.
Everything the interface shows comes from the daemon over a WebSocket. The UI never computes where the phone is, so it cannot show a position the phone has not confirmed.
Layout
| Path | What lives there |
|---|---|
daemon/wanderd/geo.py |
Spherical geometry — interpolation along a path |
daemon/wanderd/motion.py |
The movement engine; RouteRunner is pure and clock-free |
daemon/wanderd/device.py |
pymobiledevice3: tunnel, DDI mount, location service |
daemon/wanderd/session.py |
Supervisor — reconnects, resumes, fans state out |
src/ |
Map, controls, and the coordinate readout |
src-tauri/ |
The Mac shell |
scripts/make_icon.py |
The app icon, generated rather than checked in as a blob |
npm test # frontend
npm run test:py # daemonThe route engine is deliberately testable without hardware: RouteRunner takes
elapsed seconds and returns a position, with no clock and no device, so every
looping and reversal rule is covered by ordinary unit tests. A FakeBackend
stands in for the phone across the API tests.
What tests cannot cover is the device layer itself — that needs a real iPhone, and is verified by hand.
Wander tries to say what to do rather than print a stack trace. The usual causes:
| Symptom | Cause |
|---|---|
| "Developer Mode is off" | Turn it on in Settings, then restart the phone. |
| "This Mac is not paired" | Unlock the phone and tap Trust. |
| "The iPhone is locked" | Keep it unlocked while Wander connects. |
| "No Developer Disk Image available" | Your iOS build is likely newer than pymobiledevice3 knows about. |
| Tunnel needs privileges | Some iOS builds need root to create the network interface. |
Wander is built on pymobiledevice3, which tracks Apple's private protocols. On an iOS beta, breakage after an update is normal and usually fixed upstream:
cd daemon && uv pip install --python .venv/bin/python -U pymobiledevice3Built on pymobiledevice3 by doronz88, which does the genuinely hard work. Maps from OpenStreetMap; search by Nominatim.
MIT licensed.