DEV Community

Onizuka
Onizuka

Posted on

Auto-Locate Nearby Golf Courses on Your Map Using IP Geolocation

webdev #python #javascript #maps #api #geolocation #golf #rapidapi #showhn

A recent Show HN project mapped every US golf course—16,000+ of them, free, no signup. That is a goldmine for anyone building a golf app, travel planner, or local discovery map. But a map full of pins is only useful if you know where the user is.

Instead of asking users to type in a ZIP code, you can auto-locate them from their IP address and immediately suggest nearby courses. In this post, I’ll show you how to wire the IP Geolocation API (RapidAPI, GitHub) to a golf-course dataset so your app can say:

“You’re in Scottsdale, AZ. Here are the 5 closest golf courses.”


What we are building

  1. A visitor opens your web app.
  2. Your backend reads the visitor’s IP.
  3. You call the IP Geolocation API to get latitude, longitude, city, and state.
  4. You compare that position against a local golf-course dataset using the haversine formula.
  5. You return the closest courses and render them on a map.

The golf-course data can come from the Show HN dataset. For this example, we’ll assume a CSV like this:

name,lat,lon,city,state
TPC Scottsdale,33.6405,-111.9086,Scottsdale,AZ
Grayhawk Golf Club,33.6754,-111.8240,Scottsdale,AZ
...
Enter fullscreen mode Exit fullscreen mode

Backend: Flask + IP Geolocation API

Here is a minimal Flask endpoint that does the heavy lifting.

from flask import Flask, request, jsonify
import requests
import csv
import math

app = Flask(__name__)

RAPIDAPI_KEY = "YOUR_RAPIDAPI_KEY"
GEOLOCATION_URL = "https://ip-geolocation44.p.rapidapi.com/"
COURSES_FILE = "courses.csv"


def haversine(lat1, lon1, lat2, lon2):
    """Return distance in miles between two lat/lon points."""
    R = 3958.8  # Earth radius in miles

    phi1 = math.radians(lat1)
    phi2 = math.radians(lat2)
    dphi = math.radians(lat2 - lat1)
    dlambda = math.radians(lon2 - lon1)

    a = (
        math.sin(dphi / 2) ** 2
        + math.cos(phi1) * math.cos(phi2) * math.sin(dlambda / 2) ** 2
    )
    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))

    return R * c


@app.route("/api/nearby")
def nearby_courses():
    # Grab the client IP, accounting for proxies like Heroku/Render/Vercel
    ip = request.headers.get("X-Forwarded-For", request.remote_addr)
    ip = ip.split(",")[0].strip() if ip else ""

    # 1. Geolocate the IP
    headers = {
        "X-RapidAPI-Key": RAPIDAPI_KEY,
        "X-RapidAPI-Host": "ip-geolocation44.p.rapidapi.com",
    }
    params = {"ip": ip}

    geo_resp = requests.get(GEOLOCATION_URL, headers=headers, params=params)
    geo_resp.raise_for_status()
    geo = geo_resp.json()

    user_lat = float(geo["latitude"])
    user_lon = float(geo["longitude"])

    # 2. Find the closest courses
    courses = []
    with open(COURSES_FILE, newline="") as f:
        reader = csv.DictReader(f)
        for row in reader:
            d = haversine(
                user_lat,
                user_lon,
                float(row["lat"]),
                float(row["lon"]),
            )
            courses.append(
                {
                    "name": row["name"],
                    "city": row["city"],
                    "state": row["state"],
                    "lat": float(row["lat"]),
                    "lon": float(row["lon"]),
                    "distance_mi": round(d, 1),
                }
            )

    courses.sort(key=lambda c: c["distance_mi"])

    return jsonify(
        {
            "user": {
                "city": geo.get("city"),
                "state": geo.get("region"),
                "country": geo.get("country"),
                "lat": user_lat,
                "lon": user_lon,
            },
            "courses": courses[:5],
        }
    )


if __name__ == "__main__":
    app.run(debug=True)
Enter fullscreen mode Exit fullscreen mode

A request to GET /api/nearby returns JSON like:

{
  "user": {
    "city": "Scottsdale",
    "state": "Arizona",
    "country": "US",
    "lat": 33.4942,
    "lon": -111.9261
  },
  "courses": [
    {
      "name": "TPC Scottsdale",
      "city": "Scottsdale",
      "state": "AZ",
      "lat": 33.6405,
      "lon": -111.9086,
      "distance_mi": 10.1
    }
    ...
  ]
}
Enter fullscreen mode Exit fullscreen mode

Frontend: Plot the results on a map

Once the backend returns the user location and nearby courses, the frontend is straightforward. Here is a minimal Leaflet example.

<!DOCTYPE html>
<html>
  <head>
    <link
      rel="stylesheet"
      href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
    />
    <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
    <style>
      #map { height: 500px; }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script>
      async function initMap() {
        const res = await fetch("/api/nearby");
        const data = await res.json();

        const map = L.map("map").setView([data.user.lat, data.user.lon], 11);

        L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
          attribution: "&copy; OpenStreetMap contributors",
        }).addTo(map);

        // User marker
        L.marker([data.user.lat, data.user.lon])
          .addTo(map)
          .bindPopup(`You are here: ${data.user.city}, ${data.user.state}`)
          .openPopup();

        // Course markers
        data.courses.forEach((course) => {
          L.marker([course.lat, course.lon])
            .addTo(map)
            .bindPopup(
              `<b>${course.name}</b><br>${course.distance_mi} miles away`
            );
        });
      }

      initMap();
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

How to use IP Geolocation API

The IP Geolocation API (RapidAPI listing) geolocates any IP address and returns country, city, latitude/longitude, timezone, ISP, and ASN. It also has a dual-source fallback, so you get more reliable results than a single-source service.

cURL example

curl --request GET \
  --url 'https://ip-geolocation44.p.rapidapi.com/?ip=8.8.8.8' \
  --header 'X-RapidAPI-Key: YOUR_RAPIDAPI_KEY' \
  --header 'X-RapidAPI-Host: ip-geolocation44.p.rapidapi.com'
Enter fullscreen mode Exit fullscreen mode

Python example

import requests

url = "https://ip-geolocation44.p.rapidapi.com/"
querystring = {"ip": "8.8.8.8"}
headers = {
    "X-RapidAPI-Key": "YOUR_RAPIDAPI_KEY",
    "X-RapidAPI-Host": "ip-geolocation44.p.rapidapi.com",
}

response = requests.get(url, headers=headers, params=querystring)
print(response.json())
Enter fullscreen mode Exit fullscreen mode

For more response fields, SDKs, and error handling, check the official docs on RapidAPI and the open-source repo at github.com/On13uka/ip-geolocation-api.


Other ways to use this combo

  • Geo-restricted content delivery: Only show US golf courses to US visitors.
  • Fraud detection by IP location: Flag bookings where the IP country does not match the billing address.
  • Analytics and visitor statistics: Track which cities drive the most golfers to your site.
  • Timezone detection for users: Schedule tee-time reminders in the user’s local timezone.

Conclusion

With a free golf-course dataset and the IP Geolocation API, you can turn a static map into a personalized discovery tool in under an hour. No signup friction for the user, no manual location input, and no expensive geolocation stack.

Grab your RapidAPI key at rapidapi.com/On13uka/api/ip-geolocation44, download the Show HN course data, and start routing golfers to their next tee time automatically.

Happy hacking! ⛳

Top comments (0)