Full width home advertisement

Post Page Advertisement [Top]

 My bike went missing from outside a café last spring. It turned up two days later, abandoned three streets away, but those two days of "did someone actually steal it or is it just moved somewhere" were annoying enough that I finally built a GPS tracker for it. I skipped the commercial trackers with their $8/month subscriptions and instead built my own using an ESP32 and a Neo-6M GPS module — no SIM card, no monthly fee, just Wi-Fi and a cloud dashboard.

This guide walks through the exact build: wiring the GPS module, reading coordinates, and getting them onto a map you can actually check from your phone.

ESP32 GPS Tracker - DIY Build Guide (No SIM Card Required)

Why Skip the GSM/SIM Card Route?

A lot of GPS tracker tutorials use a GSM module with a SIM card so the tracker can send location data from literally anywhere, even without Wi-Fi nearby. That's genuinely useful for something like a car that travels far from home — but it also means paying for a data plan and dealing with GSM module wiring, which is a bigger jump for a first build.

For a lot of use cases — tracking a bike, a bag, a delivery box, or a pet that mostly roams your neighborhood — Wi-Fi-based tracking works just fine and is far simpler to build. This guide uses that approach: the ESP32 connects to nearby Wi-Fi and uploads its GPS location to a free cloud service, no SIM required. If you eventually need true "track it anywhere on Earth" range, adding a GSM module later is a natural upgrade path once you understand the basics here.

What You'll Need

  • 1x ESP32 development board (the smaller XIAO ESP32-S3 works great if you want a compact final build, but any standard ESP32 dev board works fine for learning)
  • 1x Neo-6M GPS module
  • Jumper wires
  • A portable power source if you want this mobile (an 18650 battery with a small charging module works well)
  • Optional: a small enclosure once you've got everything working and want to make it permanent

How This Actually Works

The Neo-6M module listens to signals from GPS satellites and calculates its own position — latitude, longitude, and a timestamp — then sends that data to the ESP32 over a simple serial connection. The ESP32 reads that data, and if it's connected to Wi-Fi, uploads the coordinates to a cloud service where you can view them on a map from your phone or computer.

One thing worth knowing before you start: GPS modules need a clear view of the sky to get a signal lock. They don't work indoors, and they can struggle near tall buildings or dense tree cover. Your first test should be outdoors, not on your desk — I wasted a solid twenty minutes the first time wondering why my module wasn't finding any satellites, before realizing I was sitting inside with a roof over my head.

Step 1: Wiring the GPS Module

  • Neo-6M VCC → ESP32 3.3V (some modules also accept 5V — check your specific module's specs)
  • Neo-6M GND → GND
  • Neo-6M TX → ESP32 GPIO 16 (RX2)
  • Neo-6M RX → ESP32 GPIO 17 (TX2)

A quick but important note here: avoid using the default UART0 pins for this connection. Those pins are shared with the USB connection used for programming and debugging, so using them for the GPS module will cause conflicts. Using a separate hardware serial port (like UART2, shown above) keeps things clean.

ESP32 GPS Tracker - DIY Build Guide (No SIM Card Required) 2

Step 2: Reading GPS Coordinates

Install the TinyGPS++ library through the Arduino IDE's Library Manager — it handles the parsing of raw GPS data into usable latitude and longitude values, which would otherwise be a genuinely annoying string-parsing task to do by hand.

cpp
#include <TinyGPS++.h>
#include <HardwareSerial.h>

TinyGPSPlus gps;
HardwareSerial GPS_Serial(2);

void setup() {
  Serial.begin(115200);
  GPS_Serial.begin(9600, SERIAL_8N1, 16, 17);
}

void loop() {
  while (GPS_Serial.available() > 0) {
    if (gps.encode(GPS_Serial.read())) {
      if (gps.location.isValid()) {
        Serial.print("Latitude: ");
        Serial.println(gps.location.lat(), 6);
        Serial.print("Longitude: ");
        Serial.println(gps.location.lng(), 6);
      }
    }
  }
}

Take this outside, open the Serial Monitor, and give it a minute or two. The first satellite lock is always the slowest — after that, subsequent locks happen much faster since the module caches some of the satellite data.

Step 3: Sending Coordinates Over Wi-Fi

Once you're reliably getting coordinates, the next step is uploading them somewhere you can actually view them as a map instead of raw numbers in a Serial Monitor. There are a few free cloud platforms built specifically for this kind of GPS logging (GeoLinker is a popular one that plenty of recent projects use), or you can build your own simple logging endpoint if you already run a small server.

Here's the general structure for sending data with an HTTP request once you've got a Wi-Fi connection and an API endpoint:

cpp
#include <WiFi.h>
#include <HTTPClient.h>

void sendLocation(double lat, double lng) {
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    http.begin("https://your-api-endpoint.com/update");
    http.addHeader("Content-Type", "application/json");

    String payload = "{\"lat\":" + String(lat, 6) + ",\"lng\":" + String(lng, 6) + "}";
    int responseCode = http.POST(payload);

    http.end();
  }
}

Call this function whenever you get a valid GPS fix, and you'll have a live-updating trail of coordinates you can view on a map dashboard.

Common Problems (And How I Actually Fixed Them)

The module never gets a satellite lock, even outdoors. Give it more time than you'd expect — a cold start (first power-up, or after being off for a long time) can take several minutes. Also double-check the antenna isn't covered by anything metal, including a metal enclosure if you've already mounted it.

Coordinates are readable, but jump around wildly between readings. This is a common GPS accuracy issue, especially near tall buildings ("urban canyon" effect, where signals bounce off buildings before reaching the module). Waiting for more satellites to lock (7 or more gives noticeably better accuracy) helps a lot.

The tracker works on my desk with USB power but dies quickly on battery. GPS modules and Wi-Fi radios both draw meaningful current. If you're running this on a battery, look into using the ESP32's deep sleep mode between location updates — waking up every 30-60 seconds instead of running continuously can stretch your battery life dramatically.

Wi-Fi range is limiting where I can actually use this. That's the honest trade-off of the Wi-Fi approach — it only uploads data when it's near a known network. If your use case genuinely needs tracking far from home (a car on road trips, for example), that's when adding a GSM module for cellular data becomes worth the extra complexity.

ESP32 GPS Tracker - DIY Build Guide (No SIM Card Required) 3

Final Thoughts

This project taught me more about how GPS actually works than I expected going in — it's easy to take "the little blue dot on your phone" for granted until you're the one trying to get that dot to show up reliably. It's not a huge build, and it doesn't need mains wiring or anything risky, which makes it a solid weekend project even if you're still fairly new to ESP32 work.

My bike now has a tracker zip-tied under the seat. It hasn't gone missing again, but honestly, even the peace of mind alone made this one worth building.

Bottom Ad [Post Page]