Best Practices

AI Rules for Maps Integration

AI loads the full Google Maps SDK on every page regardless of whether a map is shown. Rules for lazy loading map SDKs, marker clustering, custom map styles, static map fallbacks, and map API cost management.

7 min read·March 17, 2025

200KB map SDK on every page, 2000 individual markers crashing the browser, surprise $5,000 API bill

Lazy-loaded SDKs, marker clustering, custom styles, static fallbacks, API cost management

AI Loads 200KB of Map SDK on Every Page

AI generates maps integration with: the full Google Maps or Mapbox SDK loaded on every page (200KB+ of JavaScript even when no map is displayed), thousands of individual markers (the map freezes at 500 markers because each is a separate DOM element), default map styles (the generic Google Maps look that clashes with your brand), no static fallback (a full interactive map for a simple store location that users never interact with), and no cost awareness (Google Maps API charges per load, per direction, per geocode — a surprise $5,000 bill).

Modern maps integration is: lazy-loaded (map SDK loads only when the map component enters the viewport), clustered (thousands of points grouped into cluster markers that expand on zoom), styled (custom map design matching your brand colors and removing unnecessary details), fallback-optimized (static map image for non-interactive contexts, interactive only when needed), and cost-managed (API key restrictions, usage monitoring, billing alerts, and cheaper alternatives for simple use cases). AI generates none of these.

These rules cover: lazy loading map SDKs, marker clustering for large datasets, custom map styling, static map fallbacks, API cost management, and accessible map alternatives.

Rule 1: Lazy Load Map SDKs

The rule: 'Load the map SDK only when the map is about to be displayed. Use dynamic import with Intersection Observer: when the map container scrolls into viewport (with 200px rootMargin), dynamically import the map library and initialize it. Before that: show a static image placeholder or a skeleton. The map SDK (Google Maps: 200KB, Mapbox GL: 250KB) should never be in the initial page bundle — it loads on demand when the user actually needs a map.'

For Next.js implementation: 'const Map = dynamic(() => import("../components/InteractiveMap"), { ssr: false, loading: () => <MapSkeleton /> }). ssr: false is required because map SDKs use browser APIs (window, document) that do not exist during server rendering. The skeleton matches the map dimensions (no layout shift on load). For pages where the map is above the fold: use the @googlemaps/js-api-loader with async loading rather than a script tag in the head.'

AI generates: <script src="https://maps.googleapis.com/maps/api/js?key=..." /> in the HTML head — 200KB loaded on every page, blocking render, even on pages without a map. The contact page, the blog, the pricing page — all pay the 200KB cost. Lazy loading: only the store locator page loads the SDK, and only when the map section scrolls into view. 200KB saved on every non-map page load.

  • Dynamic import + Intersection Observer: load SDK when map enters viewport
  • Next.js: dynamic(() => import('./Map'), { ssr: false }) — client-only, lazy
  • 200KB saved on every non-map page when SDK is lazy loaded
  • Skeleton placeholder: matches map dimensions, zero layout shift
  • @googlemaps/js-api-loader: async loading for above-fold maps

Rule 2: Marker Clustering for Large Datasets

The rule: 'When displaying more than 100 points, use marker clustering. Clusters: group nearby markers into a single cluster marker showing the count ("42 stores"). On zoom: clusters split into smaller clusters or individual markers. Libraries: @googlemaps/markerclusterer (Google Maps), supercluster (framework-agnostic, works with Mapbox/Leaflet), react-map-gl with Supercluster integration. Clustering turns O(n) DOM elements into O(1) visible clusters — the map renders smoothly at any data size.'

For the performance impact: '1000 individual markers: 1000 DOM elements, the map stutters on pan/zoom, mobile browsers crash. 1000 points with clustering: 10-20 visible cluster markers at any zoom level. Zoom in: clusters smoothly split. Zoom out: markers smoothly merge. The rendering cost is proportional to what is visible (clusters), not what exists (total points). supercluster processes 100,000 points in under 50ms — the clustering itself is not the bottleneck, unclustered rendering is.'

AI generates: markers.forEach(m => new google.maps.Marker({ position: m, map })) — one DOM element per marker. At 500 markers: noticeable lag. At 2000: unusable. At 5000: the page crashes on mobile. With clustering: 5000 points display as 15 clusters, smooth as a map with 15 markers. The user zooms in to see individual markers in their area of interest. Same data, usable at any scale.

💡 5000 Points, 15 Clusters, Smooth as Butter

5000 individual markers: page crashes on mobile. 5000 points with supercluster: 15 visible cluster markers at any zoom level. Zoom in to see individual markers. Same data, usable at any scale. supercluster processes 100,000 points in under 50ms.

Rule 3: Custom Map Styles and Branding

The rule: 'Apply custom map styles that match your brand. Remove unnecessary map elements (transit lines, points of interest, terrain labels) to reduce visual noise and focus on your data. Google Maps: pass a styles array to the map constructor. Mapbox: create a custom style in Mapbox Studio. Minimum customization: brand color for primary features, muted colors for background, hidden POI labels (your markers are the points of interest, not Google default ones).'

For dark mode maps: 'Provide light and dark map styles that match your application theme. Google Maps: two style arrays, swap based on the theme. Mapbox: two style URLs (mapbox://styles/your-org/light, mapbox://styles/your-org/dark). The map should visually integrate with the page — a bright Google Maps default inside a dark-mode dashboard looks broken. Match the map background, road colors, and label colors to your design system color tokens.'

AI generates: the default Google Maps style with bright colors, restaurant icons, transit routes, and tourist attractions cluttering the view. The user is looking for your store locations but sees 50 Google POI pins first. Custom styles: your brand colors, your markers only, clean background, focused data visualization. The map serves your feature, not Google default content.

Rule 4: Static Map Image Fallbacks

The rule: 'Use static map images for non-interactive contexts: contact page store location, email footer map, social share preview, and print layouts. Google Static Maps API: one URL = one image, no JavaScript required: https://maps.googleapis.com/maps/api/staticmap?center=47.6,-122.3&zoom=14&size=600x300&markers=47.6,-122.3&key=YOUR_KEY. Cost: $2 per 1000 loads (vs $7 per 1000 for dynamic maps). No SDK loaded, instant display, works in emails and print.'

For the decision framework: 'Use static map when: the user does not need to pan, zoom, or interact (showing one store location). Use interactive map when: the user needs to explore (store locator with multiple locations, route planning, area selection). Hybrid: show a static map initially, load the interactive map on click ("Click to explore the map"). This pattern: zero JavaScript for users who just want to see the location, full interactivity for users who want to explore.'

AI generates: a full interactive Google Maps embed for a single store address on the contact page. 200KB of JavaScript loaded, API charge incurred, and the user never pans or zooms — they just wanted to see where the store is. Static image: 30KB, instant load, no JavaScript, lower API cost, same information communicated. Interactive maps for interactive needs; static images for informational display.

  • Static Maps API: one URL = one image, no JavaScript, works in emails and print
  • $2/1000 loads (static) vs $7/1000 (dynamic) — 3.5x cost reduction for non-interactive
  • Hybrid: static image initially, interactive map on click — best of both worlds
  • Contact page, email footer, social preview, print: static maps always
  • Store locator, route planning, area selection: interactive maps required
⚠️ 30KB Static vs 200KB Interactive

Contact page with one store address: AI loads a 200KB interactive SDK. The user never pans or zooms. Static map image: 30KB, instant load, no JavaScript, 3.5x cheaper API cost. Same information communicated. Interactive maps for interactive needs only.

Rule 5: Map API Cost Management

The rule: 'Map APIs charge per load, per geocode, per direction, and per place detail. Manage costs: (1) API key restrictions (HTTP referrer restriction — only your domains can use the key), (2) billing alerts (alert at $100, $500, $1000 — catch runaway costs before the monthly bill), (3) caching (geocode results, direction results — the same address always produces the same coordinates), (4) rate limiting (client-side throttle on autocomplete — debounce 300ms, not request per keystroke), (5) cheaper alternatives for simple needs (Leaflet + OpenStreetMap is free for basic maps, Mapbox has a generous free tier).'

For the cost breakdown: 'Google Maps pricing: Dynamic Maps $7/1000 loads, Static Maps $2/1000, Geocoding $5/1000 requests, Directions $5-10/1000, Places Autocomplete $2.83/1000 sessions. A store locator with 10,000 monthly users: 10,000 map loads ($70) + 10,000 geocodes ($50) + 30,000 autocomplete sessions ($85) = $205/month. With caching and debouncing: 10,000 map loads ($70) + 1,000 geocodes ($5, 90% cache hit) + 10,000 autocomplete sessions ($28, debounced) = $103/month. 50% cost reduction from caching and debouncing alone.'

AI generates: a Google Maps Places Autocomplete that fires on every keystroke (30 characters typed = 30 API calls per search). 1000 users searching once per day: 30,000 autocomplete calls per day, $2,550/month. With 300ms debounce: 3-5 calls per search, $255-425/month. 6-10x cost reduction from one debounce. API cost management is not optimization — it is preventing a surprise $5,000 bill.

ℹ️ One Debounce, 6-10x Cost Reduction

Places Autocomplete on every keystroke: 30 API calls per search. With 300ms debounce: 3-5 calls per search. 1000 users/day: $2,550/month vs $255/month. One debounce line turns a $30K annual bill into a $3K annual bill.

Complete Maps Integration Rules Template

Consolidated rules for maps integration.

  • Lazy load SDK: dynamic import + Intersection Observer — 200KB saved on non-map pages
  • Marker clustering: supercluster or @googlemaps/markerclusterer — smooth at any data size
  • Custom styles: brand colors, hide default POIs, dark mode variant — map matches your design
  • Static images for non-interactive: contact page, email, print — 3.5x cheaper, no JS
  • Hybrid: static initially, interactive on click — zero JS for viewers, full for explorers
  • API key restrictions: HTTP referrer only — prevent unauthorized usage from other domains
  • Billing alerts: $100, $500, $1000 thresholds — catch runaway costs early
  • Debounce autocomplete 300ms + cache geocodes — 50% cost reduction from two optimizations