# Grounding with Google Search Guide Complete guide to using grounding with Google Search to connect Gemini models to real-time web information, reducing hallucinations and providing verifiable, up-to-date responses. --- ## What is Grounding? Grounding connects the Gemini model to Google Search, allowing it to: - Access real-time information beyond training cutoff - Reduce hallucinations with fact-checked web sources - Provide citations and source URLs - Answer questions about current events - Verify information against the web --- ## How It Works 1. **Model receives query** (e.g., "Who won Euro 2024?") 2. **Model determines** if current information is needed 3. **Performs Google Search** automatically 4. **Processes search results** (web pages, snippets) 5. **Incorporates findings** into response 6. **Provides citations** with source URLs --- ## Two Grounding APIs ### 1. Google Search (`googleSearch`) - Recommended for Gemini 2.5 **Simple, automatic grounding**: ```typescript const response = await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: 'Who won the euro 2024?', config: { tools: [{ googleSearch: {} }] } }); ``` **Features**: - Simple configuration (empty object) - Automatic search when model needs current info - Available on all Gemini 2.5 models - Recommended for new projects ### 2. Google Search Retrieval (`googleSearchRetrieval`) - Legacy for Gemini 1.5 **Dynamic threshold control**: ```typescript import { DynamicRetrievalConfigMode } from '@google/genai'; const response = await ai.models.generateContent({ model: 'gemini-1.5-flash', contents: 'Who won the euro 2024?', config: { tools: [{ googleSearchRetrieval: { dynamicRetrievalConfig: { mode: DynamicRetrievalConfigMode.MODE_DYNAMIC, dynamicThreshold: 0.7 // Search only if confidence < 70% } } }] } }); ``` **Features**: - Control when searches happen via threshold - Used with Gemini 1.5 models - More configuration options **Recommendation**: Use `googleSearch` for Gemini 2.5 models (simpler and newer). --- ## Basic Usage ### SDK Approach (Gemini 2.5) ```typescript import { GoogleGenAI } from '@google/genai'; const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY }); const response = await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: 'What are the latest developments in AI?', config: { tools: [{ googleSearch: {} }] } }); console.log(response.text); // Check if grounding was used if (response.candidates[0].groundingMetadata) { console.log('✓ Search performed'); console.log('Sources:', response.candidates[0].groundingMetadata.webPages); } else { console.log('✓ Answered from model knowledge'); } ``` ### Fetch Approach (Cloudflare Workers) ```typescript const response = await fetch( `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-goog-api-key': env.GEMINI_API_KEY, }, body: JSON.stringify({ contents: [{ parts: [{ text: 'What are the latest developments in AI?' }] }], tools: [{ google_search: {} }] }), } ); const data = await response.json(); console.log(data.candidates[0].content.parts[0].text); ``` --- ## Grounding Metadata ### Structure ```typescript { groundingMetadata: { // Search queries performed searchQueries: [ { text: "euro 2024 winner" } ], // Web pages retrieved webPages: [ { url: "https://example.com/euro-2024", title: "UEFA Euro 2024 Results", snippet: "Spain won UEFA Euro 2024..." } ], // Citations (inline references) citations: [ { startIndex: 42, endIndex: 47, uri: "https://example.com/euro-2024" } ], // Retrieval queries (alternative search terms) retrievalQueries: [ { query: "who won euro 2024 final" } ] } } ``` ### Accessing Metadata ```typescript if (response.candidates[0].groundingMetadata) { const metadata = response.candidates[0].groundingMetadata; // Display sources console.log('Sources:'); metadata.webPages?.forEach((page, i) => { console.log(`${i + 1}. ${page.title}`); console.log(` ${page.url}`); }); // Display citations console.log('\nCitations:'); metadata.citations?.forEach((citation) => { console.log(`Position ${citation.startIndex}-${citation.endIndex}: ${citation.uri}`); }); } ``` --- ## When to Use Grounding ### ✅ Good Use Cases **Current Events**: ```typescript 'What happened in the news today?' 'Who won the latest sports championship?' 'What are the current stock prices?' ``` **Recent Developments**: ```typescript 'What are the latest AI breakthroughs?' 'What are recent changes in climate policy?' ``` **Fact-Checking**: ```typescript 'Is this claim true: [claim]?' 'What does the latest research say about [topic]?' ``` **Real-Time Data**: ```typescript 'What is the current weather in Tokyo?' 'What are today's cryptocurrency prices?' ``` ### ❌ Not Recommended For **General Knowledge**: ```typescript 'What is the capital of France?' // Model knows this 'How does photosynthesis work?' // Stable knowledge ``` **Mathematical Calculations**: ```typescript 'What is 15 * 27?' // Use code execution instead ``` **Creative Tasks**: ```typescript 'Write a poem about autumn' // No search needed ``` **Code Generation**: ```typescript 'Write a sorting algorithm' // Internal reasoning sufficient ``` --- ## Chat with Grounding ### Multi-Turn Conversations ```typescript const chat = await ai.chats.create({ model: 'gemini-2.5-flash', config: { tools: [{ googleSearch: {} }] } }); // First question let response = await chat.sendMessage('What are the latest quantum computing developments?'); console.log(response.text); // Display sources if (response.candidates[0].groundingMetadata) { const sources = response.candidates[0].groundingMetadata.webPages || []; console.log(`\nSources: ${sources.length} web pages`); sources.forEach(s => console.log(`- ${s.title}: ${s.url}`)); } // Follow-up question response = await chat.sendMessage('Which company made the biggest breakthrough?'); console.log('\n' + response.text); ``` --- ## Combining with Other Features ### Grounding + Function Calling ```typescript const weatherFunction = { name: 'get_current_weather', description: 'Get weather for a location', parametersJsonSchema: { type: 'object', properties: { location: { type: 'string', description: 'City name' } }, required: ['location'] } }; const response = await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: 'What is the weather like in the city that won Euro 2024?', config: { tools: [ { googleSearch: {} }, // For finding Euro 2024 winner { functionDeclarations: [weatherFunction] } // For weather lookup ] } }); // Model will: // 1. Use Google Search to find Euro 2024 winner (Madrid/Spain) // 2. Call get_current_weather function with the city // 3. Combine both results in response ``` ### Grounding + Code Execution ```typescript const response = await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: 'Find the current stock prices for AAPL, GOOGL, MSFT and calculate their average', config: { tools: [ { googleSearch: {} }, // For current stock prices { codeExecution: {} } // For averaging ] } }); // Model will: // 1. Search for current stock prices // 2. Generate code to calculate average // 3. Execute code with the found prices // 4. Return result with citations ``` --- ## Checking Grounding Usage ### Determine if Search Was Performed ```typescript const queries = [ 'What is 2+2?', // Should NOT use search 'What happened in the news today?' // Should use search ]; for (const query of queries) { const response = await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: query, config: { tools: [{ googleSearch: {} }] } }); console.log(`Query: ${query}`); console.log(`Search used: ${response.candidates[0].groundingMetadata ? 'YES' : 'NO'}`); console.log(); } ``` **Output**: ``` Query: What is 2+2? Search used: NO Query: What happened in the news today? Search used: YES ``` --- ## Dynamic Retrieval (Gemini 1.5) ### Threshold-Based Grounding ```typescript const response = await ai.models.generateContent({ model: 'gemini-1.5-flash', contents: 'Who won the euro 2024?', config: { tools: [{ googleSearchRetrieval: { dynamicRetrievalConfig: { mode: DynamicRetrievalConfigMode.MODE_DYNAMIC, dynamicThreshold: 0.7 // Search only if confidence < 70% } } }] } }); if (!response.candidates[0].groundingMetadata) { console.log('Model answered from knowledge (confidence >= 70%)'); } else { console.log('Search performed (confidence < 70%)'); } ``` **How It Works**: - Model evaluates confidence in its internal knowledge - If confidence < threshold → performs search - If confidence >= threshold → uses internal knowledge **Threshold Values**: - `0.0`: Never search (always use internal knowledge) - `0.5`: Search if moderately uncertain - `0.7`: Search if somewhat uncertain (good default) - `1.0`: Always search --- ## Best Practices ### ✅ Do 1. **Check Metadata**: Always verify if grounding was used ```typescript if (response.candidates[0].groundingMetadata) { ... } ``` 2. **Display Citations**: Show sources to users for transparency ```typescript metadata.webPages.forEach(page => { console.log(`Source: ${page.title} (${page.url})`); }); ``` 3. **Use Specific Queries**: Better search results with clear questions ```typescript // ✅ Good: "What are Microsoft's Q3 2024 earnings?" // ❌ Vague: "Tell me about Microsoft" ``` 4. **Combine Features**: Use with function calling/code execution for powerful workflows 5. **Handle Missing Metadata**: Not all queries trigger search ```typescript const sources = response.candidates[0].groundingMetadata?.webPages || []; ``` ### ❌ Don't 1. **Don't Assume Search Always Happens**: Model decides when to search 2. **Don't Ignore Citations**: They're crucial for fact-checking 3. **Don't Use for Stable Knowledge**: Waste of resources for unchanging facts 4. **Don't Expect Perfect Coverage**: Not all information is on the web --- ## Cost and Performance ### Cost Considerations - **Added Latency**: Search takes 1-3 seconds typically - **Token Costs**: Retrieved content counts as input tokens - **Rate Limits**: Subject to API rate limits ### Optimization **Use Dynamic Threshold** (Gemini 1.5): ```typescript dynamicThreshold: 0.7 // Higher = more searches, lower = fewer searches ``` **Cache Grounding Results** (if appropriate): ```typescript const cache = await ai.caches.create({ model: 'gemini-2.5-flash-001', config: { displayName: 'grounding-cache', tools: [{ googleSearch: {} }], contents: 'Initial query that triggers search...', ttl: '3600s' } }); // Subsequent queries reuse cached grounding results ``` --- ## Troubleshooting ### Grounding Not Working **Symptom**: No `groundingMetadata` in response **Causes**: 1. Grounding not enabled: `tools: [{ googleSearch: {} }]` 2. Model decided search wasn't needed (query answerable from knowledge) 3. Google Cloud project not configured (grounding requires GCP) **Solution**: - Verify `tools` configuration - Use queries requiring current information - Set up Google Cloud project ### Poor Search Quality **Symptom**: Irrelevant sources or wrong information **Causes**: - Vague query - Search terms ambiguous - Recent events not yet indexed **Solution**: - Make queries more specific - Include context in prompt - Verify search queries in metadata ### Citations Missing **Symptom**: `groundingMetadata` present but no citations **Explanation**: Citations are **inline references** - they may not always be present if model doesn't directly quote sources. **Solution**: Check `webPages` instead for full source list --- ## Important Requirements ### Google Cloud Project **⚠️ Grounding requires a Google Cloud project, not just an API key.** **Setup**: 1. Create Google Cloud project 2. Enable Generative Language API 3. Configure billing 4. Use API key from that project **Error if Missing**: ``` Error: Grounding requires Google Cloud project configuration ``` ### Model Support **✅ Supported**: - All Gemini 2.5 models (`googleSearch`) - All Gemini 1.5 models (`googleSearchRetrieval`) **❌ Not Supported**: - Gemini 1.0 models --- ## Examples ### News Summary ```typescript const response = await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: 'Summarize today's top 3 technology news headlines', config: { tools: [{ googleSearch: {} }] } }); console.log(response.text); metadata.webPages?.forEach((page, i) => { console.log(`${i + 1}. ${page.title}: ${page.url}`); }); ``` ### Fact Verification ```typescript const claim = "The Earth is flat"; const response = await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: `Is this claim true: "${claim}"? Use reliable sources to verify.`, config: { tools: [{ googleSearch: {} }] } }); console.log(response.text); ``` ### Market Research ```typescript const response = await ai.models.generateContent({ model: 'gemini-2.5-flash', contents: 'What are the current trends in electric vehicle adoption in 2024?', config: { tools: [{ googleSearch: {} }] } }); console.log(response.text); console.log('\nSources:'); metadata.webPages?.forEach(page => { console.log(`- ${page.title}`); }); ``` --- ## References - Official Docs: https://ai.google.dev/gemini-api/docs/grounding - Google Search Docs: https://ai.google.dev/gemini-api/docs/google-search - Templates: See `grounding-search.ts` for working examples - Combined Features: See `combined-advanced.ts` for integration patterns