Use Cases (Atualizado: 02/06/2026)

Integrar Google Maps com Claude Code: guia prático em Next.js

Integre Google Maps com Claude Code: Advanced Markers, geocoding, lojas, Mapbox e cuidados de produção.

Integrar Google Maps com Claude Code: guia prático em Next.js

Projete a função de mapa antes de renderizar

Claude Code consegue colocar um mapa na tela rapidamente. A diferença em produção aparece em outros pontos: restrição de chaves de API, alertas de custo, busca de endereço, layout mobile, privacidade e separação entre código de navegador e código de servidor.

No primeiro protótipo de localizador de lojas, Masa não travou no marcador. O problema foi a busca por endereço. Geocoding significa transformar um endereço em latitude e longitude. Parece uma chamada simples, mas endereços podem ser ambíguos, chamadas geram custo e o uso dos resultados depende das políticas da plataforma.

Este guia mostra como usar Claude Code como parceiro de implementação. Os exemplos usam Next.js App Router, React, Google Maps JavaScript API, Advanced Markers, Geocoding API e uma alternativa com Mapbox GL JS. Para chaves e permissões, leia também auditoria de segurança com Claude Code. Para velocidade, veja otimização de performance. Para camadas de dados geográficos, consulte visualização de dados.

O briefing para Claude Code

Não peça apenas “adicione Google Maps”. Dê as condições de operação.

Implemente um localizador de lojas com Next.js App Router.

Requisitos:
- Usar Google Maps JavaScript API
- Usar AdvancedMarkerElement, não a classe Marker antiga
- Ler a chave do navegador de NEXT_PUBLIC_GOOGLE_MAPS_API_KEY
- Assumir restrições HTTP referrer e restrições de API
- Chamar Geocoding API por uma rota de servidor com GOOGLE_MAPS_SERVER_KEY
- Nunca expor a chave de servidor no bundle do navegador
- Sincronizar busca, lista de lojas, cliques em marcadores e seleção
- Não ler window nem google durante SSR
- Tratar loading, error, vazio, permissão de localização negada e mobile
- Entregar checklist de restrições, orçamento e políticas

Separar responsabilidades facilita a revisão.

flowchart LR
  User["Usuário"]
  Page["Página de lojas"]
  Map["Google Maps JS API"]
  Route["/api/geocode"]
  Google["Geocoding API"]
  Store["Dados de lojas"]
  Alerts["Alertas e logs"]

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

Também traduza os termos para a equipe. Geocoding transforma endereço em coordenadas. Reverse geocoding estima um endereço a partir de coordenadas. Map ID é o identificador do Google Cloud usado para estilo de mapa e Advanced Markers.

Carregar Google Maps com segurança em Next.js

Instale o loader e os tipos. Os tipos ajudam a encontrar exemplos desatualizados que Claude Code pode sugerir.

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

Advanced Markers exigem map ID. DEMO_MAP_ID serve para testes locais, mas produção deve usar um map ID criado no Google Cloud Console. A chave do navegador fica visível por natureza na Maps JavaScript API; o controle real é restringi-la. Siga a orientação de segurança do Google Maps Platform com HTTP referrers e restrições de 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;
}

O componente deve ser client-side. Ele carrega a API dentro deuseEffecte remove marcadores no cleanup.

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

Evite montar HTML com dados do usuário para colocar emInfoWindow. Nomes, endereços e observações podem vir de CMS ou painel administrativo; trate tudo como texto.

Coloque geocoding no servidor

Separe a chave do navegador da chave de servidor. A primeira usa restrição por referrer. A segunda deve ser protegida conforme o ambiente de execução. Estados e estrutura de resposta estão na documentação oficial de 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: "pt-BR", region: "br" });
  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,
  });
}

Não use cache longo apenas para reduzir custo. O armazenamento de resultados de geocoding depende dos termos e políticas do Google Maps Platform. Para lojas, mantenha coordenadas oficiais como dados próprios e use geocoding para busca do usuário ou fluxo administrativo controlado.

Casos de uso práticos

O primeiro caso é localizador de lojas: filiais, clínicas, cursos, showrooms ou eventos. O fluxo precisa de busca por endereço, localização atual, horário, telefone e CTA de reserva. No protótipo de Masa, a primeira versão ocupava a tela mobile com o mapa e escondia a lista. Funcionou melhor mostrar a lista primeiro e mover o mapa depois da seleção.

O segundo caso é busca imobiliária ou hospedagem. Preço, disponibilidade, área, distância a pé, filtros e limites do mapa precisam ficar sincronizados. Exibir todos os marcadores de uma vez costuma ser ruim. Peça ao Claude Code para buscar somente o viewport, agrupar áreas densas e manter a lista coerente com o mapa.

O terceiro caso é operação de campo: entregas, vendas externas ou manutenção. O mapa é uma superfície de trabalho. Defina frequência de atualização, quem pode ver, tempo de retenção e comportamento quando a geolocalização for negada. Para rotas, revise custos de Routes API ou Directions API antes de codar.

Um quarto caso é conteúdo editorial: guias de viagem, bairros, eventos e recomendações locais. O mapa aumenta exploração, mas não substitui texto útil. Mantenha instruções, contexto local, acessibilidade e critérios de escolha no artigo.

Quando escolher Mapbox

Google Maps é forte para lojas, endereços, Places e experiência conhecida. Mapbox GL JS é melhor quando você tem muitos dados geográficos próprios, precisa de estilo cartográfico customizado ou quer camadas WebGL. Comece pelos guias do Mapbox GL JS.

CritérioGoogle MapsMapbox GL JS
Busca de lojasForte com Geocoding e PlacesBom quando o dado é próprio
Controle visualCloud Styling costuma bastarControle alto de estilos e camadas
AprendizadoMais simples para apps comunsExige source, layer e style
OperaçãoChaves e alertas de custoTokens e atribuição
// 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: [-46.6333, -23.5505],
      zoom: 12,
    });

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

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

A orientação para Claude Code deve dividir papéis: Google Maps para endereço e descoberta de lojas; Mapbox para camada de dados própria. Isso evita uma arquitetura confusa.

Armadilhas antes de publicar

A primeira armadilha é uma chave sem restrição. A chave do navegador fica visível, mas precisa de restrição por referrer e API. A chave de servidor nunca deve chegar ao navegador.

A segunda é copiar exemplos antigos deMarker. O Google recomenda Advanced Markers; o guia oficial de Advanced Markers mostraAdvancedMarkerElement.

A terceira é SSR. Em Next.js, usargoogle.maps.Map no topo do arquivo causagoogle is not defined. Mantenha o mapa em componente cliente e carregue a API dentro deuseEffect.

A quarta é ambiguidade de endereço. Bairro, estação ou rua podem retornar vários candidatos. Use idioma, região, país, campos estruturados ou lista de candidatos. Não use endereço cru como chave de banco.

A quinta é performance. Centenas de marcadores e cards deixam a página lenta. Use clustering, consultas por viewport, paginação ou busca no servidor.

A sexta é privacidade. Localização atual exige permissão. A interface deve funcionar quando o usuário negar; se você salvar localização, explique finalidade e retenção.

Resumo e verificação

A integração segura de Google Maps com Claude Code separa renderização, geocoding, chaves, orçamento, privacidade e mobile UX. Google Maps é forte para endereços e lojas. Mapbox é forte para dados próprios e controle visual.

Nesta atualização, foram verificados os pontos que não exigem chave real: divisão de responsabilidades no Next.js, carregamento seguro contra SSR, ramos de erro e formato dos blocos de código. Antes de ligar chaves reais, configure Maps JavaScript API, Geocoding API, restrições HTTP referrer, restrições da chave de servidor e alertas de orçamento no Google Cloud Console. Comece com três lojas, teste busca, clique no marcador, mobile e métricas de faturamento, depois expanda para dados reais.

#Claude Code #Google Maps #Mapbox #mapas #geolocalização
Grátis

PDF grátis: cheatsheet do Claude Code

Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.

Cuidamos dos seus dados e não enviamos spam.

Masa

Sobre o autor

Masa

Engenheiro focado em workflows práticos com Claude Code.