Use Cases (Aktualisiert: 2.6.2026)

Google Maps mit Claude Code integrieren: praktischer Next.js-Leitfaden

Integriere Google Maps mit Claude Code: Advanced Markers, Geocoding, Store Locator, Mapbox und Produktionsfallen.

Google Maps mit Claude Code integrieren: praktischer Next.js-Leitfaden

Erst die Kartenfunktion entwerfen, dann rendern

Claude Code kann schnell eine Karte einbauen. Produktionsreif wird die Funktion aber erst durch andere Entscheidungen: API-Schlüssel einschränken, Kosten überwachen, Adresssuche sauber trennen, mobile Bedienung prüfen, Datenschutz beachten und Browser- von Serverlogik abgrenzen.

Masa ist bei einem Store-Locator-Prototyp nicht am Marker gescheitert, sondern an der Adresse. Geocoding bedeutet, eine Adresse in Breiten- und Längengrad umzuwandeln. Das klingt einfach, ist aber mehrdeutig, kostenrelevant und an Nutzungsregeln gebunden. Wenn Browser-Key und Server-Key vermischt werden, funktioniert die Demo lokal, aber die Produktion bleibt riskant.

Dieser Artikel zeigt, wie Claude Code als Implementierungspartner genutzt wird. Die Beispiele verwenden Next.js App Router, React, Google Maps JavaScript API, Advanced Markers, Geocoding API und eine Mapbox-GL-JS-Alternative. Für Schlüssel und Berechtigungen passt Claude Code Security Audit. Für Ladezeit siehe Performance-Optimierung. Für geografische Daten passt Datenvisualisierung.

Der richtige Auftrag an Claude Code

Schreibe nicht nur “Google Maps einbauen”. Gib Claude Code die Betriebsbedingungen.

Implementiere einen Store Locator mit Next.js App Router.

Anforderungen:
- Google Maps JavaScript API verwenden
- AdvancedMarkerElement verwenden, nicht die alte Marker-Klasse
- Browser-Key aus NEXT_PUBLIC_GOOGLE_MAPS_API_KEY lesen
- HTTP-referrer- und API-Einschränkungen voraussetzen
- Geocoding API nur über eine Serverroute mit GOOGLE_MAPS_SERVER_KEY aufrufen
- Server-Key nie in das Browser-Bundle geben
- Adresssuche, Liste, Marker-Klicks und Auswahl synchronisieren
- Während SSR weder window noch google lesen
- loading, error, leer, verweigerte Standortfreigabe und mobile Zustände behandeln
- Am Ende Checklist für Einschränkungen, Budgetwarnungen und Richtlinien liefern

Die Verantwortlichkeiten sollten klar getrennt sein.

flowchart LR
  User["Nutzer"]
  Page["Store-Locator-Seite"]
  Map["Google Maps JS API"]
  Route["/api/geocode"]
  Google["Geocoding API"]
  Store["Store-Daten"]
  Alerts["Budgetwarnungen und Logs"]

  User --> Page
  Page --> Map
  Page --> Store
  Page --> Route
  Route --> Google
  Route --> Alerts

Erkläre Fachbegriffe einfach. Geocoding wandelt eine Adresse in Koordinaten um. Reverse Geocoding schätzt aus Koordinaten eine Adresse. Eine Map ID ist die Google-Cloud-Kennung für Kartenstil und Advanced Markers. Diese Klarheit hilft bei Reviews mit Produkt und Support.

Google Maps in Next.js sicher laden

Installiere Loader und Typen. Die Typen helfen, veraltete Beispiele zu erkennen, die Claude Code sonst übernehmen könnte.

npm i @googlemaps/js-api-loader
npm i -D @types/google.maps

Advanced Markers benötigen laut offizieller Dokumentation eine Map ID. DEMO_MAP_ID reicht für lokale Tests, aber Produktion sollte eine eigene Map ID aus der Google Cloud Console nutzen. Der Browser-Key ist bei Maps JavaScript API sichtbar; entscheidend sind Einschränkungen. Folge der offiziellen Google Maps Platform Security Guidance: HTTP referrers und API-Einschränkungen.

// src/lib/google-maps-loader.ts
import { Loader } from "@googlemaps/js-api-loader";

let googleMapsPromise: Promise<typeof google> | null = null;

export function loadGoogleMaps() {
  const apiKey = process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY;

  if (!apiKey) {
    throw new Error("NEXT_PUBLIC_GOOGLE_MAPS_API_KEY is missing");
  }

  if (!googleMapsPromise) {
    const loader = new Loader({
      apiKey,
      version: "weekly",
      libraries: ["marker", "places"],
    });

    googleMapsPromise = loader.load();
  }

  return googleMapsPromise;
}

Die Karte selbst wird als Client-Komponente geladen. Sie greift erst inuseEffectauf Google Maps zu und räumt Marker beim Unmount auf.

// src/components/GoogleBusinessMap.tsx
"use client";

import { useEffect, useRef } from "react";
import { loadGoogleMaps } from "@/lib/google-maps-loader";

export type MapPoint = {
  id: string;
  title: string;
  lat: number;
  lng: number;
  category?: "store" | "warehouse" | "property";
};

type Props = {
  points: MapPoint[];
  center: google.maps.LatLngLiteral;
  zoom?: number;
  onSelect?: (point: MapPoint) => void;
};

export function GoogleBusinessMap({ points, center, zoom = 13, onSelect }: Props) {
  const mapRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    let cancelled = false;
    let markers: google.maps.marker.AdvancedMarkerElement[] = [];

    async function renderMap() {
      await loadGoogleMaps();
      if (!mapRef.current || cancelled) return;

      const { Map } = (await google.maps.importLibrary("maps")) as google.maps.MapsLibrary;
      const { AdvancedMarkerElement, PinElement } = (await google.maps.importLibrary(
        "marker",
      )) as google.maps.MarkerLibrary;

      const map = new Map(mapRef.current, {
        center,
        zoom,
        mapId: process.env.NEXT_PUBLIC_GOOGLE_MAPS_MAP_ID ?? "DEMO_MAP_ID",
        fullscreenControl: false,
        gestureHandling: "cooperative",
      });

      markers = points.map((point, index) => {
        const pin = new PinElement({
          glyph: String(index + 1),
          background: point.category === "warehouse" ? "#0f766e" : "#2563eb",
          borderColor: "#ffffff",
          glyphColor: "#ffffff",
        });

        const marker = new AdvancedMarkerElement({
          map,
          position: { lat: point.lat, lng: point.lng },
          title: point.title,
          content: pin.element,
        });

        marker.addListener("click", () => onSelect?.(point));
        return marker;
      });
    }

    renderMap().catch((error) => console.error("Failed to render Google Map", error));

    return () => {
      cancelled = true;
      markers.forEach((marker) => {
        marker.map = null;
      });
    };
  }, [center.lat, center.lng, points, zoom, onSelect]);

  return <div ref={mapRef} className="h-[420px] w-full rounded-lg border" />;
}

Benutzerdaten sollten nicht als HTML-String in ein InfoWindow gelangen. Store-Namen und Adressen können aus CMS oder Admin-Tools kommen und müssen als Text behandelt werden.

Geocoding auf den Server legen

Browser-Key und Server-Key gehören getrennt. Der Browser-Key wird per Referrer eingeschränkt. Der Server-Key wird passend zur Laufzeitumgebung geschützt. Statuswerte und Antwortstruktur stehen in der offiziellen Geocoding-Dokumentation.

// src/app/api/geocode/route.ts
import { NextResponse } from "next/server";

type GeocodeResponse = {
  status: string;
  error_message?: string;
  results: Array<{
    formatted_address: string;
    place_id: string;
    geometry: { location: { lat: number; lng: number } };
  }>;
};

const endpoint = "https://maps.googleapis.com/maps/api/geocode/json";

export async function GET(request: Request) {
  const key = process.env.GOOGLE_MAPS_SERVER_KEY;
  const { searchParams } = new URL(request.url);
  const address = searchParams.get("address")?.trim();

  if (!key) return NextResponse.json({ error: "Server key is missing" }, { status: 500 });
  if (!address || address.length > 180) {
    return NextResponse.json({ error: "Address is required" }, { status: 400 });
  }

  const params = new URLSearchParams({ address, key, language: "de", region: "de" });
  const response = await fetch(`${endpoint}?${params}`, { cache: "no-store" });
  const data = (await response.json()) as GeocodeResponse;
  const first = data.results[0];

  if (!response.ok || data.status !== "OK" || !first) {
    return NextResponse.json(
      { error: data.error_message ?? data.status },
      { status: data.status === "ZERO_RESULTS" ? 404 : 502 },
    );
  }

  return NextResponse.json({
    formattedAddress: first.formatted_address,
    placeId: first.place_id,
    location: first.geometry.location,
  });
}

Langfristiges Caching ist kein reiner Kostenhebel. Ob und wie Geocoding-Ergebnisse gespeichert werden dürfen, hängt von den Google-Maps-Platform-Regeln ab. Offizielle Store-Koordinaten sollten als eigene Geschäftsdaten gepflegt werden; Nutzersuchen bleiben auf das Nötige beschränkt.

Drei echte Anwendungsfälle

Der erste Fall ist ein Store Locator für Filialen, Kliniken, Kurse, Showrooms oder Veranstaltungsorte. Wichtig sind Adresssuche, aktueller Standort, Öffnungszeiten, Telefonnummer und Buchungs-CTA. Masas erster Prototyp zeigte mobil zu viel Karte und zu wenig Liste. Besser war: Liste zuerst, Kartenmitte nach Auswahl verschieben.

Der zweite Fall ist Immobilien- oder Unterkunftssuche. Preis, Verfügbarkeit, Fläche, Fußweg, Filter und Kartenbereich müssen synchron bleiben. Alle Marker gleichzeitig zu rendern ist bei vielen Ergebnissen falsch. Claude Code sollte nur den sichtbaren Bereich laden, dichte Bereiche clustern und die Liste mit der Karte abstimmen.

Der dritte Fall ist Außendienst, Lieferung oder Wartung. Die Karte ist hier ein Arbeitswerkzeug. Vor dem Code müssen Updatefrequenz, Sichtrechte, Speicherfrist und Verhalten bei abgelehnter Standortfreigabe feststehen. Für Routenoptimierung müssen Routes API oder Directions API finanziell geprüft werden.

Ein vierter Fall sind redaktionelle Karten: Reiseführer, Stadtteile, Events. Die Karte verbessert Exploration, ersetzt aber keinen hilfreichen Text. Anfahrt, lokale Hinweise, Barrierefreiheit und Entscheidungskriterien gehören weiterhin in den Artikel.

Wann Mapbox besser passt

Google Maps ist stark bei Adresssuche, Stores, Places und vertrauter Kartenlogik. Mapbox GL JS passt besser, wenn eigene Geodaten, Kartendesign oder WebGL-Layer im Mittelpunkt stehen. Die Grundlagen beschreibt der Mapbox GL JS Guide.

KriteriumGoogle MapsMapbox GL JS
Store LocatorStark mit Geocoding und PlacesGut bei eigenen Daten
Visuelle KontrolleCloud Styling reicht oftSehr hohe Style- und Layer-Kontrolle
LernkurveEinfacher für Standard-WebappsSources, Layers und Styles nötig
BetriebSchlüssel und BudgetwarnungenToken und Attribution
// src/components/MapboxPreview.tsx
"use client";

import { useEffect, useRef } from "react";
import mapboxgl from "mapbox-gl";
import "mapbox-gl/dist/mapbox-gl.css";

export function MapboxPreview() {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const token = process.env.NEXT_PUBLIC_MAPBOX_TOKEN;
    if (!containerRef.current || !token) return;

    mapboxgl.accessToken = token;

    const map = new mapboxgl.Map({
      container: containerRef.current,
      style: "mapbox://styles/mapbox/streets-v12",
      center: [13.405, 52.52],
      zoom: 12,
    });

    map.addControl(new mapboxgl.NavigationControl(), "top-right");
    return () => map.remove();
  }, []);

  return <div ref={containerRef} className="h-[420px] w-full rounded-lg border" />;
}

Die bessere Claude-Code-Anweisung lautet nicht “beides bauen”, sondern “Google Maps für Adresse und Store-Findung, Mapbox für eigene Datenlayer”.

Produktionsfallen

Die erste Falle ist ein uneingeschränkter API-Schlüssel. Browser-Keys sind sichtbar, müssen aber per Referrer und API begrenzt werden. Server-Keys gehören nie in den Browser.

Die zweite Falle sind alteMarker-Beispiele. Google empfiehlt Advanced Markers; der offizielle Advanced-Markers-Guide zeigtAdvancedMarkerElement.

Die dritte Falle ist SSR. In Next.js führt ein Top-Level-Zugriff aufgoogle.maps.Map zugoogle is not defined. Lade Maps nur in einer Client-Komponente.

Die vierte Falle ist mehrdeutige Geocoding-Eingabe. Bahnhöfe, Straßen und Stadtteile liefern oft mehrere Kandidaten. Nutze Sprache, Region, Land, strukturierte Eingaben oder eine Kandidatenliste.

Die fünfte Falle ist Performance. Hunderte Marker und Listeneinträge machen die Seite langsam. Nutze Clustering, Viewport-Abfragen, Pagination oder Serversuche.

Die sechste Falle ist Datenschutz. Der aktuelle Standort braucht Zustimmung. Die UI muss bei Ablehnung funktionieren, und gespeicherte Standortdaten brauchen Zweck und Aufbewahrungsfrist.

Zusammenfassung und Prüfergebnis

Eine gute Google-Maps-Integration mit Claude Code trennt Kartenrendering, Geocoding, Schlüsselverwaltung, Kostenkontrolle, Datenschutz und mobile UX. Google Maps ist stark für Stores und Adressen. Mapbox ist stark für eigene Datenlayer und visuelle Kontrolle.

Für diese Aktualisierung wurden die ohne echten API-Schlüssel prüfbaren Teile kontrolliert: Next.js-Verantwortlichkeiten, SSR-sicheres Laden, Fehlerzweige und Codeblock-Format. Vor echten Schlüsseln sollten Maps JavaScript API, Geocoding API, HTTP-referrer-Einschränkungen, Server-Key-Einschränkungen und Budgetwarnungen in Google Cloud Console eingerichtet werden. Starte mit drei Stores und prüfe Suche, Marker-Klick, Mobile Layout und Billing-Metriken.

#Claude Code #Google Maps #Mapbox #Karten #Geolocation
Kostenlos

Kostenloses PDF: Claude-Code-Cheatsheet

E-Mail eintragen und eine Seite mit Befehlen, Review-Gewohnheiten und sicheren Workflows herunterladen.

Wir schützen Ihre Daten und senden keinen Spam.

Masa

Über den Autor

Masa

Engineer für praktische Claude-Code-Workflows und Team-Einführung.