Changing your apparent location with a VPN is common knowledge now, even outside tech circles. But a VPN only changes your IP address. I wanted to know whether the GPS coordinates an iPhone reports to Location Services could be spoofed.
The first results were third-party apps like iMyFone, which looked dodgy at best. Digging further, I found a whole community built around this, mostly Pokémon Go players faking their location to play the game. There are even companies selling dedicated hardware that spoofs GPS coordinates. If hardware can do it, there had to be a software route.
And there is: Apple's own developer tooling lets you simulate a GPS location on a connected device. This is traditionally used by developers to test geofencing capabilities and see how their apps behave in different places around the world. So I set out to build a small box that does it automatically. Plug the iPhone in and it jumps to a preset location. Unplug it and it's back to reality.
iOS Developer Mode lowers some of iOS's protections, so I wouldn't leave it enabled on a daily-driver phone longer than needed. And if you're tempted to use this for things like Pokémon Go, Niantic actively bans location spoofers, so treat that as your risk to take.
How does it work?
When you debug an app in Xcode, you can tell the phone to pretend it's somewhere else. That feature runs over Apple's developer services (DVT), which are available once the phone has Developer Mode enabled and a Developer Disk Image mounted.
pymobiledevice3 is an open-source Python implementation of those same protocols. It runs on Linux, which means a Raspberry Pi can do what Xcode does, without a Mac.
From iOS 17 onwards, developer services run over an encrypted tunnel, so a background daemon (tunneld) needs to be running to broker that connection.
What you need
- Raspberry Pi + microSD with a decent 5 V / 2.5 A+ power supply. The phone draws charging current through the Pi, and undervoltage kills USB.
- A proper USB data cable. Charge-only cables won't enumerate.
- An iPhone that supports Developer Mode (iOS 16+). iOS 17.4+ preferably.
- Wi-Fi for the Pi, so you can SSH in later and so it can reach Apple's servers when mounting the disk image.
1. Flash the SD card
Use Raspberry Pi Imager to write Raspberry Pi OS Lite. In the Imager settings:
- Hostname:
pispoof - User:
youruser - Enable SSH
- Add your Wi-Fi details
Boot the Pi and SSH in:
2. Install dependencies
sudo apt update && sudo apt full-upgrade -y
sudo apt install -y usbmuxd python3-venv python3-pip
python3 -m venv ~/pmd
~/pmd/bin/pip install --upgrade pip
~/pmd/bin/pip install pymobiledevice3
3. Pair the phone (one-time)
Plug the phone in and unlock it, then run:
~/pmd/bin/pymobiledevice3 usbmux list
Tap Trust on the phone and run the command again. You should see the device's JSON.
Next, check Developer Mode:
~/pmd/bin/pymobiledevice3 amfi developer-mode-status
If it's false, enable it:
~/pmd/bin/pymobiledevice3 amfi enable-developer-mode
The phone reboots. Unlock it and confirm the Developer Mode prompt. If the command refuses (it may not work while a passcode is set), run amfi reveal-developer-mode instead, then turn it on manually on the iPhone under Settings > Privacy & Security > Developer Mode.
Finally, mount the Developer Disk Image:
~/pmd/bin/pymobiledevice3 mounter auto-mount
This needs internet access and the image unmounts every time the phone reboots. The script below re-mounts it automatically.
4. Test it manually
In one terminal, start the tunnel daemon as root:
sudo ~/pmd/bin/pymobiledevice3 remote tunneld
Leave that running, and in a second terminal set a location:
~/pmd/bin/pymobiledevice3 developer dvt simulate-location set --tunnel '' -- 51.5074 -0.1278
Note the dvt and --tunnel ''. The older non-dvt command is the pre-iOS 17 service and no longer works.
Open Maps on the phone and you should be standing in the middle of Trafalgar Square.

To undo it:
~/pmd/bin/pymobiledevice3 developer dvt simulate-location clear --tunnel ''
If you get Failed to start service, run mounter auto-mount first. If iOS 17+ complains about needing a tunnel, make sure tunneld is running as root in the other terminal.
5. Automating the process for plug-and-play location spoofing
You will need two systemd services: one keeps tunneld running, the other watches for a phone and applies the location.
/etc/systemd/system/tunneld.service
[Unit]
Description=pymobiledevice3 tunneld
After=usbmuxd.service
[Service]
ExecStart=/home/youruser/pmd/bin/pymobiledevice3 remote tunneld
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
/usr/local/bin/spoof-location.sh (set LAT and LON to your preset)
#!/bin/bash
LAT=51.5074
LON=-0.1278
P=/home/youruser/pmd/bin/pymobiledevice3
while true; do
if $P usbmux list 2>/dev/null | grep -q UniqueDeviceID; then
$P mounter auto-mount >/dev/null 2>&1 # no-op if already mounted
if $P developer dvt simulate-location set --tunnel '' -- "$LAT" "$LON" >/dev/null 2>&1; then
sleep 60 # re-apply every minute, harmless
else
sleep 5 # tunnel not ready or phone locked, retry
fi
else
sleep 3 # no phone connected
fi
done
/etc/systemd/system/spoof-location.service
[Unit]
Description=Auto iPhone location spoof
After=tunneld.service
Requires=tunneld.service
[Service]
ExecStart=/usr/local/bin/spoof-location.sh
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
Enable everything:
sudo chmod +x /usr/local/bin/spoof-location.sh
sudo systemctl daemon-reload
sudo systemctl enable --now tunneld spoof-location
sudo systemctl status tunneld spoof-location
Reboot the Pi, plug the phone in, wait about 20 seconds and check Maps.
Once it works, pin the working version of pymobiledevice3:
~/pmd/bin/pip freeze | grep pymobiledevice3 > ~/pinned.txt
If an update ever breaks things, roll back with ~/pmd/bin/pip install -r ~/pinned.txt.
Notes on behaviour
- Plugged in: spoofed within 10 to 20 seconds.
- Unplugged: back to the real location.
- Reboots: the Pi will spin up the services on a reboot, but after the phone reboots, the iPhone has to be unlocked once before the Developer Disk Image can re-mount.
- iOS major updates: I did not test this, but I suppose it could break things. SSH in, run
~/pmd/bin/pip install -U pymobiledevice3and retest. - New phone: SSH in, plug it in and repeat step 3 (Trust and Developer Mode).