Use Cases (Mis à jour: 02/06/2026)

Intégrer Google Maps avec Claude Code : guide Next.js pratique

Ajoutez Google Maps avec Claude Code : Advanced Markers, geocoding serveur, boutiques, Mapbox et pièges de production.

Intégrer Google Maps avec Claude Code : guide Next.js pratique

Concevoir la carte avant de l’afficher

Claude Code peut ajouter une carte très vite. Ce qui détermine la qualité en production, c’est plutôt la restriction des clés API, le coût, la recherche d’adresse, l’expérience mobile, la confidentialité et la séparation entre code navigateur et code serveur.

Dans un prototype de recherche de boutiques, le problème rencontré par Masa n’était pas le marqueur, mais l’adresse. Le geocoding, ou géocodage, consiste à transformer une adresse en latitude et longitude. C’est pratique, mais une adresse peut être ambiguë, chaque appel peut compter dans la facturation et les règles de stockage ou d’affichage dépendent des politiques Google Maps Platform.

Ce guide montre comment utiliser Claude Code comme partenaire d’implémentation. Les exemples utilisent Next.js App Router, React, Google Maps JavaScript API, Advanced Markers, Geocoding API et une alternative Mapbox GL JS. Pour les clés et permissions, lisez aussi l’audit de sécurité Claude Code. Pour la vitesse, gardez l’optimisation de performance à portée. Pour les couches de données géographiques, voyez la visualisation de données.

Le brief à donner à Claude Code

Ne demandez pas seulement d’ajouter Google Maps. Donnez les contraintes opérationnelles.

Implémente une page de recherche de boutiques avec Next.js App Router.

Contraintes:
- Utiliser Google Maps JavaScript API
- Utiliser AdvancedMarkerElement, pas l'ancienne classe Marker
- Lire la clé navigateur depuis NEXT_PUBLIC_GOOGLE_MAPS_API_KEY
- Supposer des restrictions HTTP referrer et des restrictions d'API
- Appeler Geocoding API depuis une route serveur avec GOOGLE_MAPS_SERVER_KEY
- Ne jamais exposer la clé serveur au bundle navigateur
- Synchroniser recherche, liste, clics sur marqueurs et état sélectionné
- Ne pas lire window ni google pendant le SSR
- Gérer loading, error, résultat vide, refus de géolocalisation et mobile
- Fournir une checklist finale de restrictions, budget et politiques

La séparation des responsabilités rend la revue beaucoup plus simple.

flowchart LR
  User["Utilisateur"]
  Page["Page de boutiques"]
  Map["Google Maps JS API"]
  Route["/api/geocode"]
  Google["Geocoding API"]
  Store["Données boutiques"]
  Alerts["Alertes et logs"]

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

Expliquez aussi les termes. Le géocodage transforme une adresse en coordonnées. Le géocodage inverse part des coordonnées pour retrouver une adresse probable. Un map ID est l’identifiant Google Cloud utilisé pour les styles de carte et les Advanced Markers.

Charger Google Maps proprement dans Next.js

Installez le loader officiel et les types. Les types évitent d’accepter sans le voir un exemple ancien ou incomplet.

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

Les Advanced Markers demandent un map ID. DEMO_MAP_ID suffit pour une vérification locale, mais la production doit utiliser un map ID créé dans Google Cloud Console. La clé navigateur sera visible par nature avec Maps JavaScript API. Il faut donc suivre les recommandations de sécurité Google Maps Platform : restrictions HTTP referrer et restrictions d’API.

// 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;
}

Le composant doit rester côté client. Il charge l’API dansuseEffect, crée les marqueurs puis les nettoie au démontage.

// 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" />;
}

Ne concaténez pas du HTML fourni par l’utilisateur dans une InfoWindow. Les noms et adresses peuvent venir d’un CMS ; traitez-les comme du texte.

Placer le geocoding côté serveur

Séparez la clé navigateur et la clé serveur. La première doit être limitée par referrer. La seconde doit être protégée selon l’environnement d’exécution. Les statuts et la forme des réponses sont dans la documentation officielle Geocoding request and response.

// 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: "fr", region: "fr" });
  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,
  });
}

Le cache ne doit pas être ajouté uniquement pour réduire la facture. Les conditions de conservation des résultats de géocodage dépendent des règles Google Maps Platform. Pour un localisateur, gardez les coordonnées officielles des boutiques comme données métier et utilisez le geocoding pour la recherche utilisateur ou les flux internes maîtrisés.

Trois cas d’usage concrets

Premier cas : localisateur de boutiques, cliniques, cours, showrooms ou lieux d’événement. Les éléments essentiels sont la recherche d’adresse, la position actuelle, les horaires, le téléphone et le bouton de réservation. Dans le prototype de Masa, la première version donnait trop de hauteur à la carte sur mobile. La version plus utile affichait d’abord la liste, puis déplaçait la carte après sélection.

Deuxième cas : immobilier ou hébergement. Prix, disponibilité, surface, distance à pied, filtres et limites de carte doivent rester synchronisés. N’affichez pas tous les marqueurs si les résultats sont nombreux. Demandez à Claude Code de charger uniquement le viewport, de regrouper les zones denses et d’aligner la liste avec ce qui est visible.

Troisième cas : livraison, ventes terrain ou maintenance. La carte devient un outil opérationnel. Décidez la fréquence de mise à jour, les droits de lecture, la durée de conservation et le comportement si la géolocalisation est refusée. Si vous ajoutez l’optimisation d’itinéraire, examinez le coût des API Routes ou Directions avant de coder.

Un quatrième usage est éditorial : guides de voyage, quartiers, événements. La carte améliore l’exploration, mais ne remplace pas le texte. Gardez les conseils de trajet, les remarques locales et les critères de choix dans l’article.

Quand choisir Mapbox

Google Maps est très adapté aux recherches d’adresses, aux boutiques et aux données Places. Mapbox GL JS convient mieux si vous possédez beaucoup de données géographiques, si le style cartographique est central ou si vous voulez des couches WebGL. Les bases sont dans les guides Mapbox GL JS.

CritèreGoogle MapsMapbox GL JS
Recherche de boutiquesFort avec Geocoding et PlacesBon si vos données sont centrales
Contrôle visuelCloud Styling suffit souventContrôle élevé des styles et couches
ApprentissagePlus simple pour une app classiqueDemande de comprendre sources et layers
Risque opérationnelClés et alertes de budgetTokens et 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: [2.3522, 48.8566],
      zoom: 12,
    });

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

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

La bonne consigne n’est pas de tout faire deux fois. Dites plutôt : Google Maps pour la recherche d’adresse, Mapbox pour la couche de données propriétaire.

Pièges de production

Le premier piège est la clé sans restriction. Une clé navigateur est visible, mais elle doit être limitée par referrer et API. Une clé serveur ne doit jamais partir dans le bundle navigateur.

Le deuxième piège est l’ancienMarker. Google met en avant Advanced Markers ; le guide officiel Advanced Markers montreAdvancedMarkerElement. Si Claude Code génère l’ancien modèle, demandez une mise à jour.

Le troisième piège est le SSR. Dans Next.js, utilisergoogle.maps.Map au niveau supérieur provoquegoogle is not defined. Chargez l’API dans un composant client.

Le quatrième piège est l’ambiguïté d’adresse. Une gare, un quartier ou une rue peut produire plusieurs candidats. Utilisez langue, région, pays, saisie structurée ou choix de résultat. Ne faites pas de l’adresse brute une clé de base de données.

Le cinquième piège est la performance. Des centaines de marqueurs et de cartes de résultats ralentissent l’interface. Utilisez clustering, requêtes par viewport, pagination ou recherche serveur.

Le sixième piège est la confidentialité. La position actuelle demande un consentement. L’interface doit fonctionner si l’utilisateur refuse, et toute conservation de position doit avoir un objectif et une durée.

Résumé et note de vérification

La bonne intégration Google Maps avec Claude Code sépare rendu de carte, geocoding, clés, budget, confidentialité et mobile. Google Maps est fort pour les adresses et les boutiques. Mapbox est fort pour les données propres et le contrôle visuel.

Pour cette mise à jour, les points vérifiables sans clé réelle ont été contrôlés : séparation Next.js, chargement sûr face au SSR, branches d’erreur et blocs de code. Avant d’utiliser une vraie clé, configurez Maps JavaScript API, Geocoding API, restrictions HTTP referrer, restrictions de clé serveur et alertes de budget dans Google Cloud Console. Testez d’abord avec trois boutiques, puis validez recherche, clic marqueur, mobile et métriques de facturation.

#Claude Code #Google Maps #Mapbox #cartes #géolocalisation
Gratuit

PDF gratuit: cheatsheet Claude Code

Saisissez votre email et téléchargez une page avec commandes, habitudes de review et workflow sûr.

Nous protégeons vos données et n'envoyons pas de spam.

Masa

À propos de l'auteur

Masa

Ingénieur spécialisé dans les workflows pratiques avec Claude Code.