Privacy Tools Guide

Google Maps builds a complete history of everywhere you have ever been. This data is used for ad targeting, sold to third parties, and shared with law enforcement upon request — without a warrant in many jurisdictions. The good news is that OpenStreetMap-based apps are now good enough to replace Google Maps entirely for most users.

The Problem with Google Maps

Google Maps collects:

Location data from Google is routinely subpoenaed in criminal investigations. It has been used to identify protesters, track domestic abuse victims who fled their abusers, and implicate people in crimes committed near places they visited.

Best Privacy-Respecting Map Apps

OsmAnd (Android and iOS)

OsmAnd uses OpenStreetMap data downloaded to your device. It works fully offline after the initial map download.

Setup:

  1. Install from F-Droid or the official website (avoid the Google Play version which has tracking)
  2. Go to Downloads > Download Maps
  3. Select your region and download
  4. Disable location permissions when not actively navigating

Organic Maps (Android and iOS)

Organic Maps is a fork of Maps.me with all tracking removed. It is the most polished OSM-based app for casual navigation.

Organic Maps is the best recommendation for users switching from Google Maps who want a clean interface.

Magic Earth (Android and iOS)

Magic Earth uses HERE Maps data (not OSM) and offers fully offline navigation. It includes dashcam features and 3D maps.

Qwant Maps (Browser)

For browser-based mapping without Google tracking:

https://www.qwant.com/maps

Qwant Maps uses OpenStreetMap and respects privacy. It does not store search history. For route planning without an account, Qwant Maps is a solid Google Maps replacement in the browser.

OpenStreetMap.org (Browser)

The underlying data source for most privacy-respecting apps. The website itself does not track users or require an account for basic map viewing and directions.

https://www.openstreetmap.org

For turn-by-turn routing, use the OSRM routing engine built into the website or query it directly:

# Get driving route between two coordinates
curl "http://router.project-osrm.org/route/v1/driving/\
-0.1278,51.5074;2.3522,48.8566\
?overview=false&steps=true" | \
jq '.routes[0] | {distance: .distance, duration: .duration}'

Using Maps Without Revealing Your Location

The key insight: you do not need to give a maps app your real-time GPS location to get useful navigation.

Manual Location Entry

Instead of tapping “My Location”:

  1. Type your starting address manually
  2. Navigate to an approximate location (e.g., your neighborhood center, a nearby landmark)

This prevents the app from knowing your exact home address.

Offline Pre-Planning

Plan your route at home on a desktop, then memorize or screenshot the steps:

# Query OpenRouteService API (free, self-hostable)
curl -X POST \
  "https://api.openrouteservice.org/v2/directions/driving-car/json" \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "coordinates": [[-0.1278, 51.5074], [2.3522, 48.8566]],
    "instructions": true
  }' | jq '.routes[0].segments[0].steps[] | {instruction: .instruction, distance: .distance}'

OpenRouteService is open-source and can be self-hosted:

docker run -dt --name ors-app \
  -p 8080:8082 \
  -v /path/to/osm-data:/home/ors/files \
  openrouteservice/openrouteservice:latest

Revoke Location Always-On Permissions

On Android:

On iOS:

Self-Hosted Tile Server

For maximum privacy, serve your own map tiles from an OSM extract:

# Using the tileserver-gl Docker image
# First, download a regional OSM extract from geofabrik.de
wget https://download.geofabrik.de/europe/germany-latest.osm.pbf

# Convert to MBTiles format
docker run --rm -v $(pwd):/data \
  ghcr.io/mapbox/tippecanoe \
  tippecanoe -o /data/germany.mbtiles /data/germany-latest.osm.pbf

# Serve tiles
docker run --rm -p 8080:8080 \
  -v $(pwd):/data \
  maptiler/tileserver-gl:latest \
  --file /data/germany.mbtiles

Access your private tile server at http://localhost:8080 and configure OsmAnd or other clients to use it as a tile source.

Advanced Privacy Setup for Navigation

Running Your Own Geocoding Service

For maximum privacy, you can run a local geocoding server that converts addresses to coordinates without sharing searches with any external service:

# Install Nominatim (the geocoder behind OpenStreetMap)
docker run -d --name nominatim \
  -p 8080:8080 \
  -e PBF_URL=https://download.geofabrik.de/europe/germany-latest.osm.pbf \
  mediagis/nominatim:latest

# Query your local geocoder
curl "http://localhost:8080/search?q=Berlin+Hauptbahnhof&format=json" | \
  jq '.[] | {lat: .lat, lon: .lon, name: .display_name}'

Once running, configure OsmAnd or Organic Maps to use your local Nominatim server for address lookups. Addresses never leave your network.

Tor Integration for Navigation Privacy

For users concerned about IP-based location inference, routing through Tor adds another privacy layer:

# Install Tor
sudo apt install tor

# Configure Tor to use a SOCKS5 proxy
# Then route map tile requests through Tor

# Create proxy rule for map tiles in Organic Maps or OsmAnd:
# In app settings, set proxy to: socks5://127.0.0.1:9050

This prevents the tile server from seeing your IP address (and inferring location from it). The tradeoff: map rendering is noticeably slower.

Comparing Location Metadata from Different Apps

Different navigation apps handle location metadata differently. Here’s how to audit what each app stores:

#!/bin/bash
# audit-location-metadata.sh
# Compare metadata stored by different navigation apps

for app in "OsmAnd" "Organic Maps" "Magic Earth"; do
  echo "=== $app ==="

  # Check app directory
  app_data_dir="$(find ~/.local/share -type d -name '*osm*' 2>/dev/null | head -1)"

  if [ -n "$app_data_dir" ]; then
    echo "Cache size: $(du -sh "$app_data_dir")"
    echo "Files: $(find "$app_data_dir" -type f | wc -l)"

    # Check for location history
    grep -r "latitude\|longitude" "$app_data_dir" 2>/dev/null | wc -l | \
      xargs -I {} echo "Location references found: {}"
  fi

  echo ""
done

Encrypted Route Sharing Without Location Exposure

If you need to share a route with someone without revealing your exact starting point, use encrypted routing:

#!/bin/bash
# share-route-encrypted.sh
# Generate shareable route without exposing home location

START_COORD="52.5200,13.4050"  # Generic city center
END_COORD="48.8566,2.3522"     # Destination

# Generate route via OpenRouteService
ROUTE_JSON=$(curl -s -X POST \
  "https://api.openrouteservice.org/v2/directions/driving-car" \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"coordinates\": [
      [$(echo $START_COORD | tr ',' ' ')],
      [$(echo $END_COORD | tr ',' ' ')]
    ]
  }")

# Encrypt with GPG before sharing
echo "$ROUTE_JSON" | gpg --symmetric --cipher-algo AES256 | \
  base64 > route-encrypted.txt

# Share the file with recipient
# They decrypt with: gpg --decrypt route-encrypted.txt | jq

Browser-Based Private Route Planning

For quick route planning without downloading apps:

# Use uMap (privacy-respecting fork of Leaflet)
# Self-host or use public instance

docker run -d --name umap \
  -p 8000:8000 \
  -e DATABASE_URL=postgresql://user:pass@localhost/umap \
  umap/umap:latest

# Access at http://localhost:8000
# Plan routes locally with no tracking

Location History Sanitization

If you’ve used location-tracking apps in the past, remove the records:

# Download and analyze your location history from Google Takeout
# Then generate a sanitized version with gaps

python3 << 'EOF'
import json
from datetime import datetime, timedelta

# Load downloaded location history
with open('Takeout/Location History/Records.json') as f:
    history = json.load(f)

# Remove entries from sensitive locations
# (home, office, medical facilities, etc.)
sanitized = []
sensitive_coords = {
    'home': (52.5200, 13.4050, radius_km=1),
    'work': (48.8566, 2.3522, radius_km=1),
}

for record in history['locations']:
    lat, lon = float(record['latitudeE7'])/1e7, float(record['longitudeE7'])/1e7

    # Check if within sensitive radius
    is_sensitive = False
    for location, (safe_lat, safe_lon, radius) in sensitive_coords.items():
        distance = ((lat - safe_lat)**2 + (lon - safe_lon)**2)**0.5
        if distance < radius / 111:  # Rough km to degrees conversion
            is_sensitive = True
            break

    if not is_sensitive:
        sanitized.append(record)

# Write sanitized history
with open('Location_History_Sanitized.json', 'w') as f:
    json.dump({'locations': sanitized}, f)

print(f"Removed {len(history['locations']) - len(sanitized)} entries from sensitive locations")
EOF

Offline-First Workflow for Complete Privacy

Design your navigation entirely offline:

#!/bin/bash
# offline-navigation-setup.sh
# Complete workflow using only offline data

# 1. Download regional maps for your areas
for region in "germany" "france" "spain"; do
  wget https://download.geofabrik.de/europe/${region}-latest.osm.pbf
done

# 2. Convert to offline routing format
for pbf_file in *.pbf; do
  region=${pbf_file%-latest.osm.pbf}
  docker run --rm -v $(pwd):/data ghcr.io/project-osrm/osrm-backend \
    osrm-extract -p /opt/car.lua /data/$pbf_file
  osrm-contract /data/${region}.osrm
done

# 3. Set up local OSRM servers
for osrm_file in *.osrm; do
  port=$((5000 + $RANDOM % 1000))
  docker run -d -p $port:5000 \
    -v $(pwd):/data \
    osrm/osrm-backend \
    osrm-routed --algorithm ch /data/$osrm_file
done

# 4. Configure apps to use local routing
# Add local servers to OsmAnd custom endpoints
# All routing stays on-device, no external requests