Pokémon GO - How I changed my location


I wrote this article to present my research on the implementation of a program that is able to fake the geolocation (to move myself virtually) in the game Pokémon GO.

While spoofing the GPS may simply be seen as cheating, I made it because I live in a rural area and the closest pokéstops and arenas are kilometers away. For me, the game was fairly difficult, while some people living in populated areas just need to walk a few meters to come across tens of them.

Main idea

My idea was therefore to provide a web interface using the Google Maps API, to control the move of the player, and adjust his speed (walking, running, bike, car, etc.).

The coordinates were periodically transmitted to a server. The server would send these coordinates to an Android application that would update the GPS location on the mobile phone. Finally, Pokémon GO would use this modified data to geolocate my player and the surrounding pokémons.

The reason that I had to use a server middleware instead of directly sending the data from the web interface to the Android application is because Pokémon GO only works on ARM processor (ARM emulators on PC are very slow, this would have made the use of the game very difficult).

Web server / web interface

I set up a web server with NodeJS in order to generate and serve simple pages as well as static files. I also set up websockets (with socket.io) to communicate between the web clients and the server, and between the server and mobile applications. For each client, an identifier of simulation is randomly generated. This identifier acts as the login on the mobile application. This especially allows the server to handle multiple clients and phones.

The web interface then uses the Google Maps API in order to have a visual representation of the current position. A control panel is then used to simulate movements (by walking, running, biking, etc.).

The generated values (speed, latitude, longitude, altitude, accuracy, bearing and angle) are slightly randomized to simulate a movement closer to the reality (not to have strict or too perfect travel). Each type of movement can have different settings: the bearing (the angle of GPS orientation - the four cardinal points) is for example less subject to changes in plane rather than walking.

In addition to the field accuracy, some data are sometimes not sent to simulate a bad network connection.

Screenshot Web Interface

Android application

The Android app is for its part pretty basic. It uses the socket.io library to connect to the server.

At this stage of the program, I could see myself virtually moving (remotely controlled by the web app) in the Google Maps application installed on my Android phone.

Android and Google Maps Screenshot

Pokémon GO application

However, even after configuring a location of the phone as a high precision in the settings (necessary to be run), it did not work on the application Pokémon GO.

Unlike Google Maps which is using the GPS provider, Pokémon GO is mainly using the network provider. The GPS provider's values are periodically compared to the network provider's values in order to check whether they are too distant. Also, I noticed that if I set both providers at the same time (GPS and network), the application was not working. So I decided to set the location randomly between the GPS and network.

Despite this, the application refused once again to run, since it was detected that the location data were defined by an application rather than by the system/network/GPS directly (via the isFromMockProvider method of the class android.location.Location).

Since I could not override this method to force it to return false, I chose to use Xposed Module with the Mock Mock Locations module, which effectively overrides this method directly in the system (I quickly explain its installation in the next section).

Android Installation

I did not want to do all these manipulations on my Android directly; Pokémon GO is not the only application that I use, and I wanted to keep real location data for some others.

So I installed a dual boot on my phone via the application MultiROM Manager (my phone was already rooted). After a restart on the recovery system, I created a dual boot by adding a second image (I chose CM13). After the installation, I flashed OpenGApps (in order to have access to Google Play and Google Maps for testing - I also think it is necessary to have these applications in order to run Pokémon GO). As seen above, I also flashed the Xposed Module (v86-sdk23-arm for my case, being on a Nexus 5).

After a few restarts and configurations, I installed the applications XposedInstaller and Mock Mock Locations.

At this point, it only remained for me to select my application in the setting Select mock location app (in developers options), and to start my service with my simulation ID. Pokémon GO run successfully, and well positioned locations for the phone, defined virtually by the web interface.

Pokemon GO Screenshot


Honestly, I did not abused of this program. I chose to begin the adventure in Paris (France), walking, running, or riding a bike, by traveling from one park to another, from pokéstops to arenas, etc.

All that I wanted was to play without having to travel kilometers to go in the nearest town, which contains only one pokéstop. I use this program with moderated use, even though I know it is easier to stay in front of a computer rather than going out to do sports.

All the source code is available on my GitHub (the web server/web interface and the Android application): github.com/Dewep/GeoLocationSimulation.

The purpose of this article is to present and share my research, not to destroy the game. If you intend to use this program for your adventure, thank you to do it with responsible use (I did not try to teleport between far locations, or traveling very quickly, it may be possible to get banned by doing it).

If you have some comments about my source code or my research, post a comment or send me an email (see Contact in the header).

NodeJS Express EJS Android Pokémon GO

Article date publication: 15 July 2016.