Bringing the real world to your AI application using Firebase AI Logic

Demo app showing Grounding with Google Maps inside Firebase AI Logic

Build geospatial-aware applications with Google Maps grounding in Firebase AI Logic

In the rapidly evolving landscape of generative AI, the biggest challenge for mobile and web developers remains “hallucinations”—when a model generates plausible but entirely fabricated information. This is especially problematic in geospatial contexts involving places, ratings & reviews, and routes. To solve this, we are excited to introduce Grounding with Google Maps within the Firebase AI Logic SDK. Developers can utilize Grounding with Google Maps with Firebase AI Logic SDK for Android, iOS, Flutter, Javascript, and Unity SDKs.

This new capability allows your AI-powered applications to anchor their responses in high-quality, real-world geospatial data. Whether you’re building a local travel guide or a restaurant recommendation engine, grounding ensures your LLM provides factual, location-aware, and dependable information.

How It Works

Implementing Grounding with Google Maps in your web application involves three main steps: configuring the generative model using Firebase AI Logic, defining the map plotting logic, and extracting grounding metadata to cite sources and resolve place coordinates.

1. Making the Call (Configuration & Model Execution)

To enable Grounding with Google Maps, you configure the generative model (such as Gemini 3.5 Flash) by adding Firebase AI Logic to your setup. You can also pass the user’s latitude and longitude in the retrieval configuration to provide geographic bias, ensuring recommendations are locally relevant.

index.js
import { initializeApp } from "firebase/app";
import { getAI, getGenerativeModel } from "firebase/ai";

const app = initializeApp(firebaseConfig);
const ai = getAI(app);

// Configure the Gemini model with Google Maps grounding enabled
const model = getGenerativeModel(ai, {
  model: "gemini-3.5-flash",
  tools: [{ googleMaps: {} }],
  systemInstruction:
      "You are a professional travel concierge. Provide a detailed day-by-day itinerary in markdown. Ground all recommended places in Google Maps.",
  toolConfig: {
      retrievalConfig: {
          // Provide geographic bias for locally relevant results
          latLng: {
              latitude: 48.8566,
              longitude: 2.3522,
          },
          languageCode: "en_US",
      },
  },
});

const prompt = "Plan a 3-day art and food tour in Paris.";
const result = await model.generateContent(prompt);
Copied!

2. Plotting the Places on the Map

To visualize grounded locations, you can use modern Web Components in the Google Maps JavaScript API (AdvancedMarkerElement and PinElement). PinElement allows you to customize marker colors and display glyph text—such as numbering the sources—without external images. AdvancedMarkerElement then plots the customized pin on the map.

map.js
let map;
let activeMarkers = [];

async function initMap() {
  const { Map } = await google.maps.importLibrary("maps");
  map = new Map(document.getElementById("map"), {
	center: { lat: 48.8566, lng: 2.3522 },
	zoom: 12,
	mapId: "DEMO_MAP_ID",
  });
}

// Plots a grounded location onto the Google Map using Web Components
async function plotLocation(location, index) {
  const { AdvancedMarkerElement, PinElement } =
	await google.maps.importLibrary("marker");

  // Create a customized PinElement showing the itinerary stop number
  const pin = new PinElement({
	background: "#3b82f6",
	borderColor: "#1d4ed8",
	glyphColor: "#ffffff",
	glyphText: `${index + 1}`,
  });

  // Plot AdvancedMarkerElement passing PinElement as content
  const marker = new AdvancedMarkerElement({
	map: map,
	position: { lat: location.latitude, lng: location.longitude },
	title: location.name,
	content: pin,
  });

  activeMarkers.push(marker);
}
Copied!

3. Citing the Text with Sources (Grounding Metadata)

When the model generates a response, it returns grounding metadata containing the sources used (groundingChunks) and the exact text segments they verify (groundingSupports).

To add inline citation links (such as [1], [2]) to the text, you iterate through the supports array. Sorting the supports in descending order by their end index allows you to insert HTML links into the text string from back to front without altering the character indices of earlier segments.

Additionally, the grounding chunks provide Google Place IDs. You use the Google Maps Places Library to fetch precise geographic coordinates for each ID, strip the places/ prefix if present, and pass them to your plotting function.

grounding.js
const groundingMetadata = result.response.candidates?.[0]?.groundingMetadata;
const chunks = groundingMetadata?.groundingChunks || [];
const supports = groundingMetadata?.groundingSupports || [];

let text = result.response.text();

// 3a. Sort supports by endIndex descending to insert links from back to front
const sortedSupports = [...supports].sort((a, b) => {
  return (b.segment?.endIndex || 0) - (a.segment?.endIndex || 0);
});

sortedSupports.forEach(support => {
  const endIndex = support.segment?.endIndex;
  if (endIndex !== undefined && endIndex <= text.length) {
      const indices = support.groundingChunkIndices || [];
      if (indices.length > 0) {
          const linksHtml = indices.map(idx => {
              const chunk = chunks[idx];
              if (!chunk?.maps) return '';
              return `<a href="${chunk.maps.uri}" target="_blank" class="citation-link">[${idx + 1}]</a>`;
          }).join('');

          // Insert citation links directly after the grounded segment
          text = text.slice(0, endIndex) + linksHtml + text.slice(endIndex);
      }
  }
});

document.getElementById("itinerary-container").innerHTML = marked.parse(text);

// 3b. Resolve Place IDs to coordinates and plot markers on the map
const { Place } = await google.maps.importLibrary("places");

const lookupPromises = chunks.map(async (chunk, index) => {
if (!chunk.maps || !chunk.maps.placeId) return;

// Clean the place ID by stripping the 'places/' prefix
const rawPlaceId = chunk.maps.placeId.replace("places/", "");

const place = new Place({ id: rawPlaceId });
await place.fetchFields({ fields: ['location', 'displayName'] });

if (place.location) {
  const locData = {
      name: place.displayName,
      latitude: place.location.lat(),
      longitude: place.location.lng()
  };
  // Call the plotLocation function defined in Step 2
  plotLocation(locData, index);
}
});

await Promise.all(lookupPromises);
Copied!

Get Started

Grounding with Google Maps is generally available. There is no additional charge from Firebase to enable this feature, though usage must comply with the Gemini Developer API or Gemini Enterprise Agent Platform API terms of service.

To implement grounding in your application, review the Firebase AI Logic documentation and try the sample.