<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: SerpApi</title>
    <description>The latest articles on DEV Community by SerpApi (serpapi).</description>
    <link>https://dev.to/serpapi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F2993%2F7009fcb6-41c1-44c2-b881-75eef15b2791.png</url>
      <title>DEV Community: SerpApi</title>
      <link>https://dev.to/serpapi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/serpapi"/>
    <language>en</language>
    <item>
      <title>Introducing SerpApi Search Tools: Real-Time Web Search for Python AI Agents</title>
      <dc:creator>Adarsh D</dc:creator>
      <pubDate>Sun, 09 Aug 2026 10:17:07 +0000</pubDate>
      <link>https://dev.to/serpapi/introducing-serpapi-search-tools-real-time-web-search-for-python-ai-agents-3bf</link>
      <guid>https://dev.to/serpapi/introducing-serpapi-search-tools-real-time-web-search-for-python-ai-agents-3bf</guid>
      <description>&lt;p&gt;&lt;code&gt;serpapi-search-tools&lt;/code&gt; gives Python AI agents real-time access to the web, news, maps, images, shopping, videos, hotels, flights, and travel search, powered by SerpApi. It works with 14 popular agent SDKs, including LangChain, Agno, CrewAI, OpenAI Agents, Pydantic AI, and Google ADK.&lt;/p&gt;

&lt;p&gt;AI agents are useful, but they cannot answer questions about current news, prices, places, or travel options unless they have a way to search. &lt;a href="https://serpapi.com/" rel="noopener noreferrer"&gt;SerpApi&lt;/a&gt; lets applications search services such as Google, Bing, Google Maps, Google News, Google Shopping, YouTube, Google Hotels, and Google Flights, then returns organized data that the agent can use.&lt;/p&gt;

&lt;p&gt;We released &lt;a href="https://pypi.org/project/serpapi-search-tools/" rel="noopener noreferrer"&gt;serpapi-search-tools&lt;/a&gt; to make that search data easy to use in Python agents. The package gives your agent ready-to-use search tools, so you can focus on what the agent should do instead of building a search integration from scratch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F00in50dqi2o70ltg0650.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F00in50dqi2o70ltg0650.png" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The package is open source on &lt;a href="https://github.com/serpapi/serpapi-search-tools-python" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, and the complete guides and examples are available in the &lt;a href="https://serpapi.github.io/serpapi-search-tools-python/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add real-time web search to your first Python agent
&lt;/h2&gt;

&lt;p&gt;This example uses the OpenAI Agents SDK and gives a simple agent access to web search.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install
&lt;/h3&gt;

&lt;p&gt;You need Python 3.10 or newer, a SerpApi account, and an API key for the model provider your agent uses. This example uses OpenAI.&lt;/p&gt;

&lt;p&gt;For this tutorial, install &lt;code&gt;serpapi-search-tools&lt;/code&gt; and the OpenAI Agents SDK together using pip:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="s2"&gt;"serpapi-search-tools[openai-agents]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If OpenAI Agents is already installed, you can install only the search tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;serpapi-search-tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use uv, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv add &lt;span class="s2"&gt;"serpapi-search-tools[openai-agents]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For another agent SDK, choose its install option from the &lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/sdk-examples/" rel="noopener noreferrer"&gt;SDK examples&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add your API keys
&lt;/h3&gt;

&lt;p&gt;Your agent needs a SerpApi key for search and an OpenAI key for the model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SERPAPI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your-serpapi-key"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your-openai-key"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can &lt;a href="https://serpapi.com/users/sign_up" rel="noopener noreferrer"&gt;create a SerpApi account&lt;/a&gt; and copy your private API key from the &lt;a href="https://serpapi.com/dashboard" rel="noopener noreferrer"&gt;SerpApi dashboard&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build your first agent
&lt;/h3&gt;

&lt;p&gt;Save this as &lt;code&gt;search_agent.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;agents&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Runner&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;serpapi_search_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;web_search&lt;/span&gt;


&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;research-agent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-5.6-luna&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Use web search for current facts.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;web_search&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Runner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Find three new Python features and briefly explain them.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new_items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_call_item&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tool called: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tool_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Arguments: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raw_item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Agent Response: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;final_output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python search_agent.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example prints each tool call and its arguments before the final answer. This makes the agent's search process visible, including the queries it created and the search engine it selected.&lt;/p&gt;

&lt;p&gt;Here is the output from an actual run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Tool called: web_search
Arguments: {"query":"Python latest release new features Python 3.14 official what's new","engine":"google_light"}

Tool called: web_search
Arguments: {"query":"site:python.org/downloads/release Python 3.14 new features","engine":"google_light"}

Agent Response:  According to the official Python 3.14 documentation, three notable new features are:
&lt;span class="p"&gt;
1.&lt;/span&gt; &lt;span class="gs"&gt;**Template string literals (t-strings)**&lt;/span&gt; — A flexible way to create customized string-processing templates, useful for safer formatting and domain-specific text handling.
&lt;span class="p"&gt;
2.&lt;/span&gt; &lt;span class="gs"&gt;**Deferred evaluation of annotations**&lt;/span&gt; — Type annotations are evaluated later rather than immediately, reducing import problems and improving compatibility with forward references.
&lt;span class="p"&gt;
3.&lt;/span&gt; &lt;span class="gs"&gt;**Standard-library subinterpreters**&lt;/span&gt; — Python now provides tools for running isolated interpreters within one process, enabling better parallelism and isolation.

Source: &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Python 3.14 “What’s New”&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://docs.python.org/3/whatsnew/3.14.html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The two printed calls show that the agent searched more than once to verify the answer. &lt;code&gt;web_search()&lt;/code&gt; gave it the search capability, while the instruction told it to use that capability for current facts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nine search tools for common agent tasks
&lt;/h2&gt;

&lt;p&gt;Different searches need different information. A hotel search needs stay dates, while a flight search needs airports and a travel date. &lt;code&gt;serpapi-search-tools&lt;/code&gt; gives your agent a focused tool for each task so it knows what information to provide.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What you want your agent to do&lt;/th&gt;
&lt;th&gt;Search tool&lt;/th&gt;
&lt;th&gt;Search source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Research a current topic&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/user-guide/web_search.html" rel="noopener noreferrer"&gt;&lt;code&gt;web_search&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://serpapi.com/google-light-api" rel="noopener noreferrer"&gt;Google Light&lt;/a&gt; by default, with Google, Bing, Yahoo, or DuckDuckGo available&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Follow the latest news&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/user-guide/news_search.html" rel="noopener noreferrer"&gt;&lt;code&gt;news_search&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.com/google-news-api" rel="noopener noreferrer"&gt;Google News&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Find places and local businesses&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/user-guide/maps_search.html" rel="noopener noreferrer"&gt;&lt;code&gt;maps_search&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.com/google-maps-api" rel="noopener noreferrer"&gt;Google Maps&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Find images and visual references&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/user-guide/images_search.html" rel="noopener noreferrer"&gt;&lt;code&gt;images_search&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.com/google-images-api" rel="noopener noreferrer"&gt;Google Images&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compare products, prices, and sellers&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/user-guide/shopping_search.html" rel="noopener noreferrer"&gt;&lt;code&gt;shopping_search&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://serpapi.com/google-shopping-api" rel="noopener noreferrer"&gt;Google Shopping&lt;/a&gt;, Amazon, Walmart, or eBay&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Find videos on YouTube&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/user-guide/videos_search.html" rel="noopener noreferrer"&gt;&lt;code&gt;videos_search&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.com/youtube-search-api" rel="noopener noreferrer"&gt;YouTube&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Find hotel stays and prices&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/user-guide/hotels_search.html" rel="noopener noreferrer"&gt;&lt;code&gt;hotels_search&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.com/google-hotels-api" rel="noopener noreferrer"&gt;Google Hotels&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compare flights for a route&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/user-guide/flights_search.html" rel="noopener noreferrer"&gt;&lt;code&gt;flights_search&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.com/google-flights-api" rel="noopener noreferrer"&gt;Google Flights&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Discover possible destinations&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/user-guide/travel_explore_search.html" rel="noopener noreferrer"&gt;&lt;code&gt;travel_explore_search&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.com/google-travel-explore-api" rel="noopener noreferrer"&gt;Google Travel Explore&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Choose only the tools your agent needs. A shopping assistant might use web, shopping, and image search. A trip planner might use flights, hotels, maps, and travel exploration.&lt;/p&gt;

&lt;h2&gt;
  
  
  One package for 14 Python agent SDKs
&lt;/h2&gt;

&lt;p&gt;An agent SDK is the Python library you use to build and run an agent. You can use &lt;code&gt;serpapi-search-tools&lt;/code&gt; with the SDK you already know, and each link below opens a complete example.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Supported SDK&lt;/th&gt;
&lt;th&gt;Start here&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI Agents SDK&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/sdk-examples/openai_agents.html" rel="noopener noreferrer"&gt;OpenAI Agents example&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pydantic AI&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/sdk-examples/pydantic_ai.html" rel="noopener noreferrer"&gt;Pydantic AI example&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LangChain&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/sdk-examples/langchain.html" rel="noopener noreferrer"&gt;LangChain example&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LangGraph&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/sdk-examples/langgraph.html" rel="noopener noreferrer"&gt;LangGraph example&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CrewAI&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/sdk-examples/crewai.html" rel="noopener noreferrer"&gt;CrewAI example&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LlamaIndex&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/sdk-examples/llamaindex.html" rel="noopener noreferrer"&gt;LlamaIndex example&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Agent SDK&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/sdk-examples/claude_agent_sdk.html" rel="noopener noreferrer"&gt;Claude Agent SDK example&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Microsoft Agent Framework&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/sdk-examples/microsoft_agent_framework.html" rel="noopener noreferrer"&gt;Microsoft Agent Framework example&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AutoGen&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/sdk-examples/autogen.html" rel="noopener noreferrer"&gt;AutoGen example&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Haystack&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/sdk-examples/haystack.html" rel="noopener noreferrer"&gt;Haystack example&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Semantic Kernel&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/sdk-examples/semantic_kernel.html" rel="noopener noreferrer"&gt;Semantic Kernel example&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agno&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/sdk-examples/agno.html" rel="noopener noreferrer"&gt;Agno example&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;smolagents&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/sdk-examples/smolagents.html" rel="noopener noreferrer"&gt;smolagents example&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google ADK&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/sdk-examples/google_adk.html" rel="noopener noreferrer"&gt;Google ADK example&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  The same search tools in every SDK
&lt;/h3&gt;

&lt;p&gt;The search tool names stay the same across supported SDKs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;serpapi_search_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;maps_search&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;news_search&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;web_search&lt;/span&gt;

&lt;span class="n"&gt;search_tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;web_search&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nf"&gt;news_search&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nf"&gt;maps_search&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add these to your SDK the way you normally add tools. If you later switch SDKs, the surrounding agent code changes but your search setup stays familiar: &lt;code&gt;web_search()&lt;/code&gt; is still &lt;code&gt;web_search()&lt;/code&gt;. The &lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/sdk-examples/" rel="noopener noreferrer"&gt;SDK examples&lt;/a&gt; show the complete setup for every supported integration.&lt;/p&gt;

&lt;h3&gt;
  
  
  The package recognizes your SDK automatically
&lt;/h3&gt;

&lt;p&gt;In a typical project, you install one supported agent SDK and call a search tool such as &lt;code&gt;web_search()&lt;/code&gt;. The package recognizes the installed SDK and prepares the tool for it automatically.&lt;/p&gt;

&lt;p&gt;You usually do not need any extra setup. If your project has more than one supported SDK installed, the &lt;a href="https://serpapi.github.io/serpapi-search-tools-python/user-guide/frameworks.html" rel="noopener noreferrer"&gt;agent SDK guide&lt;/a&gt; shows how to select the one you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  Customize search for your agent
&lt;/h2&gt;

&lt;p&gt;The defaults are a good place to start, so you can use a simple call such as &lt;code&gt;web_search()&lt;/code&gt; in your first agent. When you need more control, these six recipes cover common search and response settings.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Use one fast web search engine
&lt;/h3&gt;

&lt;p&gt;Google Light is the default web engine. You can make it the agent's only choice and set the language, country, result count, and timeout in your application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;serpapi_search_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;web_search&lt;/span&gt;

&lt;span class="n"&gt;search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;web_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;allowed_engines&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;google_light&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;default_params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;num&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;20.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent still chooses the search query. Your application keeps control of the search engine and settings.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Give the agent regional search choices
&lt;/h3&gt;

&lt;p&gt;Create separately named tools when the agent needs to search different countries or languages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;serpapi_search_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;web_search&lt;/span&gt;

&lt;span class="n"&gt;search_us&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;web_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;allowed_engines&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;google_light&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;default_params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;num&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;web_search_us&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;search_de&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;web_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;allowed_engines&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;google_light&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;default_params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;de&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;de&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;num&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;web_search_de&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;search_us&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;search_de&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The names help the agent choose the right regional search for the question.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Compare products across marketplaces
&lt;/h3&gt;

&lt;p&gt;Create separate shopping tools when you want the agent to compare results from different marketplaces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;serpapi_search_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;shopping_search&lt;/span&gt;

&lt;span class="n"&gt;google_products&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;shopping_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;allowed_engines&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;google_shopping&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;default_params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;num&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;google_products&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;amazon_products&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;shopping_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;allowed_engines&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;default_params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;num&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon_products&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;google_products&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amazon_products&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Google Shopping can compare products across merchants, while Amazon searches its own marketplace. You can create similar tools for Walmart and eBay.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Add safe, localized image search
&lt;/h3&gt;

&lt;p&gt;Keep safe search, language, and country settings under your application's control:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;serpapi_search_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;images_search&lt;/span&gt;

&lt;span class="n"&gt;safe_images&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;images_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;default_params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;safe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;active&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;safe_image_search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent only needs to describe what images it wants to find; your application applies the search policy every time.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Keep travel prices in one currency
&lt;/h3&gt;

&lt;p&gt;Use the same currency and locale across flight and hotel tools so their prices are easier to compare:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;serpapi_search_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;flights_search&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hotels_search&lt;/span&gt;

&lt;span class="n"&gt;travel_defaults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;currency&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;USD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;flight_search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;flights_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;default_params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;travel_defaults&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us_flights&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;hotel_search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hotels_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;default_params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;travel_defaults&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us_hotel_prices&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;flight_search&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hotel_search&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent still provides the route, destination, and dates. Your application keeps the display currency and locale consistent.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Choose compact or full results
&lt;/h3&gt;

&lt;p&gt;Every search tool uses compact results by default. Compact mode keeps the response focused, which is usually the best choice for an agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;serpapi_search_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;web_search&lt;/span&gt;

&lt;span class="n"&gt;search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;web_search&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your application needs the complete SerpApi response, including additional sections and metadata, choose full mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;serpapi_search_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SearchResultMode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;web_search&lt;/span&gt;

&lt;span class="n"&gt;search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;web_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;SearchResultMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use full results only when your application needs the extra data; compact results help avoid filling the model's context with information it may not use.&lt;/p&gt;

&lt;p&gt;You can also configure locations, result limits, and other tool-specific settings. The &lt;a href="https://serpapi.github.io/serpapi-search-tools-python/user-guide/configuration.html" rel="noopener noreferrer"&gt;configuration guide&lt;/a&gt; contains the complete set of options and examples. Visit the &lt;a href="https://serpapi.github.io/serpapi-search-tools-python/" rel="noopener noreferrer"&gt;full documentation&lt;/a&gt; for installation, SDK guides, recipes, and API details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complete agent projects you can copy
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/cookbook/" rel="noopener noreferrer"&gt;agent cookbook&lt;/a&gt; contains complete projects for every supported SDK. Each guide includes setup instructions, a prompt you can edit, runnable code, and an output you can inspect.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SDK&lt;/th&gt;
&lt;th&gt;Cookbook agent&lt;/th&gt;
&lt;th&gt;SerpApi capabilities used&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/cookbook/langchain.html" rel="noopener noreferrer"&gt;LangChain&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Deep market research brief&lt;/td&gt;
&lt;td&gt;Web and news&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/cookbook/langgraph.html" rel="noopener noreferrer"&gt;LangGraph&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Product-launch intelligence graph&lt;/td&gt;
&lt;td&gt;Web, news, and shopping&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/cookbook/crewai.html" rel="noopener noreferrer"&gt;CrewAI&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Collaborative trip planner&lt;/td&gt;
&lt;td&gt;Flights, hotels, and maps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/cookbook/llamaindex.html" rel="noopener noreferrer"&gt;LlamaIndex&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Remote-work destination brief&lt;/td&gt;
&lt;td&gt;Travel Explore, web, and maps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/cookbook/openai-agents.html" rel="noopener noreferrer"&gt;OpenAI Agents&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Managed research report&lt;/td&gt;
&lt;td&gt;Web and news&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/cookbook/claude-agent-sdk.html" rel="noopener noreferrer"&gt;Claude Agent SDK&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Source-verification memo&lt;/td&gt;
&lt;td&gt;Web and news&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/cookbook/pydantic-ai.html" rel="noopener noreferrer"&gt;Pydantic AI&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Visual location scout&lt;/td&gt;
&lt;td&gt;Images, maps, and web&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/cookbook/microsoft-agent-framework.html" rel="noopener noreferrer"&gt;Microsoft Agent Framework&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Technology due-diligence memo&lt;/td&gt;
&lt;td&gt;Web and news&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/cookbook/autogen.html" rel="noopener noreferrer"&gt;AutoGen&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Company intelligence memo&lt;/td&gt;
&lt;td&gt;Web and news&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/cookbook/haystack.html" rel="noopener noreferrer"&gt;Haystack&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Weekly industry newsletter&lt;/td&gt;
&lt;td&gt;Web and news&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/cookbook/semantic-kernel.html" rel="noopener noreferrer"&gt;Semantic Kernel&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Plan-and-execute competitor brief&lt;/td&gt;
&lt;td&gt;Web and news&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/cookbook/agno.html" rel="noopener noreferrer"&gt;Agno&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Market research report&lt;/td&gt;
&lt;td&gt;Web, news, and shopping&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/cookbook/smolagents.html" rel="noopener noreferrer"&gt;smolagents&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Purchase research assistant&lt;/td&gt;
&lt;td&gt;Shopping, images, and videos&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/cookbook/google-adk.html" rel="noopener noreferrer"&gt;Google ADK&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Retail location strategy&lt;/td&gt;
&lt;td&gt;Maps, web, and news&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Start with the cookbook project closest to your idea, then change the prompt and search tools to fit your use case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn more about building agents
&lt;/h2&gt;

&lt;p&gt;If you are new to AI agents or want a longer tutorial, continue with these guides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://serpapi.com/blog/building-an-ai-agent-in-python/" rel="noopener noreferrer"&gt;Building an AI Agent in Python&lt;/a&gt; explains agents, prompts, context, memory, tools, MCP, and skills from the beginning.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://serpapi.com/blog/smarter-pydantic-ai-agents-with-real-time-search/" rel="noopener noreferrer"&gt;Build Smarter Pydantic AI Agents with Real-Time Search&lt;/a&gt; shows how to add SerpApi search to a Pydantic AI agent step by step.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://serpapi.com/blog/build-an-ai-agent-with-claude-agent-sdk/" rel="noopener noreferrer"&gt;Build an AI Agent with the Claude Agent SDK&lt;/a&gt; shows how to build a Claude agent and connect it to custom tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Start building
&lt;/h2&gt;

&lt;p&gt;Install the option for your SDK, add one or two search tools, and start from the &lt;a href="https://serpapi.github.io/serpapi-search-tools-python/docs/cookbook/" rel="noopener noreferrer"&gt;cookbook project&lt;/a&gt; closest to your idea. The package is on &lt;a href="https://pypi.org/project/serpapi-search-tools/" rel="noopener noreferrer"&gt;PyPI&lt;/a&gt;, the source is on &lt;a href="https://github.com/serpapi/serpapi-search-tools-python" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, and issues and pull requests are welcome.&lt;/p&gt;

&lt;p&gt;If you are new to SerpApi, &lt;a href="https://serpapi.com/users/sign_up" rel="noopener noreferrer"&gt;create a free account&lt;/a&gt; and give your Python agent real-time search data in a few minutes.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Measuring World Cup Attention: What the data says about Vozinha</title>
      <dc:creator>Tomás Murúa</dc:creator>
      <pubDate>Sun, 09 Aug 2026 02:13:34 +0000</pubDate>
      <link>https://dev.to/serpapi/measuring-world-cup-attention-what-the-data-says-about-vozinha-38ff</link>
      <guid>https://dev.to/serpapi/measuring-world-cup-attention-what-the-data-says-about-vozinha-38ff</guid>
      <description>&lt;p&gt;During the 2026 World Cup, Cape Verde played for the first time, and its goalkeeper Vozinha had the kind of attention that nobody could have imagined before the event started.&lt;/p&gt;

&lt;p&gt;His Instagram following stood at roughly 27,000 before the tournament. Then Cape Verde held Spain to a goalless draw, with Vozinha stopping all eight shots on target from the 23 Spain produced. In the days after that match his following passed 14 million. By the end of the tournament it had grown past 29 million.&lt;/p&gt;

&lt;p&gt;Vozinha's story raised a question. How many smaller versions of that story were buried across 48 teams and 104 matches?&lt;/p&gt;

&lt;p&gt;So during the tournament, we tracked search interest, news coverage, and Instagram followers for a watchlist of players to answer a simple question. Beyond the trophy, who actually captured the world's attention?&lt;/p&gt;

&lt;p&gt;This blog is about what the data showed, the player stories hiding in it, and what any of it can and cannot tell you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://sports-pulse.apps.serpapi.com/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F07c9rp2dgjxze4ndj8fb.png" alt="The final attention leaderboard in Sports Pulse" width="800" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The final attention leaderboard in Sports Pulse&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Everything in this post comes from &lt;a href="https://sports-pulse.apps.serpapi.com/" rel="noopener noreferrer"&gt;Sports Pulse&lt;/a&gt;, a live dashboard I built on SerpApi's APIs to track this, the same data teams use for sponsorship scouting, media monitoring, and market research. Every number below has a page there where you can see it for yourself.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sports-pulse.apps.serpapi.com/" rel="noopener noreferrer"&gt;Sports Pulse&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Question That Turned Into a Dashboard
&lt;/h2&gt;

&lt;p&gt;The World Cup writes down everything that happens on the pitch. Every goal, every save, every minute played. What it does not write down is who the world went looking for while it happened. That record is scattered across search queries, news archives, and follower counts, three things measured in different units and stored in different shapes. The match report tells you Vozinha played four games. It does not tell you the world went looking for him afterwards.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://serpapi.com/playground?q=vozinha+stats&amp;amp;location=Austin,+Texas,+United+States&amp;amp;gl=us&amp;amp;hl=en" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftt4k64nqa6qyr2nrlgix.png" alt="Vozinha’s World Cup stats" width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Vozinha’s World Cup stats&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So I built a pipeline that assembles that second record. For every player it produces a single attention score from 0 to 100, built from three signals. Search interest, news coverage, and follower growth, each compared against the rest of the field. The score answers one narrow question.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Relative to everyone else at this tournament, how much attention did this player draw during the event?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is not a measure of how good a player is, and it is not a measure of fame. A player who was already massively popular before the tournament and stayed that way will score low, because the score is built around movement. And it never says why something happened. A spike after a match is a spike after a match.&lt;/p&gt;

&lt;p&gt;I scored a &lt;a href="https://sports-pulse.apps.serpapi.com/players" rel="noopener noreferrer"&gt;watchlist&lt;/a&gt; of 39 hand-picked players rather than the 1,248 players spread across the 48 squads. Scoring all of them means measuring hundreds of players nobody searched for, which buries the signal in noise. So I picked the players most likely to draw attention, based on their profiles going in, minutes played, and how far their team went. Less data, better data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp9tp62udkzsg1x1wkvo4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp9tp62udkzsg1x1wkvo4.png" alt="The 39-player watchlist" width="800" height="921"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The 39-player watchlist&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading the Board
&lt;/h2&gt;

&lt;p&gt;The board does not rank the best players at the World Cup. It ranks who moved the most while it was happening, and the players at the top got there in completely different ways.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Top Six
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp53kslojmhdd3txyteer.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp53kslojmhdd3txyteer.png" alt="The top six by attention score" width="800" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The top six by attention score&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Lamine Yamal
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://sports-pulse.apps.serpapi.com/players/6a5521e96bb307ecf24ec737" rel="noopener noreferrer"&gt;Yamal&lt;/a&gt; finishes first with a score of 73.6, and he is the only player on the board who is strong in all three signals at once. The highest search interest of the tournament, 727 articles, and 13.7 million new followers across Spain's eight-match run to the title.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1zwsylze1kwpnjreehyn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1zwsylze1kwpnjreehyn.png" alt="Yamal's page in Sports Pulse" width="799" height="261"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Yamal's page in Sports Pulse&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That is the sanity check. A measure of tournament attention that did not pull Yamal near the top would be measuring something else or completely wrong. What makes him unusual is not the total; it is that he has no weak column.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vozinha
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://sports-pulse.apps.serpapi.com/players/6a5521eb6bb307ecf24ece46" rel="noopener noreferrer"&gt;Vozinha&lt;/a&gt; finishes fourth with an attention score of 56.4, across four matches.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fghaffkj11ig1cf1zjwu7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fghaffkj11ig1cf1zjwu7.png" alt="Vozinha's page Sports Pulse" width="800" height="260"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Vozinha's page Sports Pulse&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;He gained 29.5 million followers during the window, the largest movement in the field by a distance nobody else is close to. His whole score rests in one column, and that is the pattern a scoreboard cannot show you and a raw follower count cannot contextualize, because a follower count on its own has no field to compare against.&lt;/p&gt;

&lt;p&gt;The per-match Instagram follower graph makes it concrete. The Spain match added 14.2 million followers; the Argentina match in the final added 11.8 million new followers to the Vozinha account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fexg68ss1ejsnj1apzfcu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fexg68ss1ejsnj1apzfcu.png" alt="Vozinha follower growth by match" width="800" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Vozinha follower growth by match&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Lionel Messi
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://sports-pulse.apps.serpapi.com/players/6a5521e96bb307ecf24ec5c4" rel="noopener noreferrer"&gt;Messi&lt;/a&gt; is the most useful player on this watchlist for understanding what the score actually measures.&lt;/p&gt;

&lt;p&gt;He has the most news coverage of anyone at the tournament with 783 articles covering him, more than Yamal. His search interest is the second highest on the watchlist. And his follower growth scores exactly zero.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F98rmjmidm7jtdt4d672p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F98rmjmidm7jtdt4d672p.png" alt="Messi page Sports Pulse" width="799" height="261"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Messi page Sports Pulse&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The zero is not missing data, and it is not because he stood still. Messi gained 8.9 million followers during the tournament, more than most players on the watchlist. But on a base of 515 million that is a 0.5% move, and in a field where Vozinha's following multiplied more than a thousand times over, a 0.5% move lands below the middle of the pack and scores nothing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6nhmqorx5m0wd1fhkv4v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6nhmqorx5m0wd1fhkv4v.png" alt="Messi's follower growth by match" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Messi's follower growth by match&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That is the metric behaving exactly as designed and it still looks strange written down. Messi finishing sixth is not a claim that five players had a bigger tournament than him. It is a claim that five players moved more than he did, which is a different sentence, and the difference is the whole point of the exercise.&lt;/p&gt;

&lt;h3&gt;
  
  
  Haaland and Olise
&lt;/h3&gt;

&lt;p&gt;Vozinha's pattern is not a one-off. &lt;a href="https://sports-pulse.apps.serpapi.com/players/6a5521e96bb307ecf24ec4bb" rel="noopener noreferrer"&gt;Haaland&lt;/a&gt; finishes second after gaining 32.8 million followers across six matches.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbvdy2pt8plbvdljzsk8f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbvdy2pt8plbvdljzsk8f.png" alt="Haaland page Sports Pulse" width="800" height="634"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Haaland page Sports Pulse&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And &lt;a href="https://sports-pulse.apps.serpapi.com/players/6a5521e96bb307ecf24ec4f2" rel="noopener noreferrer"&gt;Olise&lt;/a&gt; finishes fifth with 6 million gained from a far smaller base. Both maxed out the same follower signal Vozinha did.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhesqn5zdn07ge6wb0ef8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhesqn5zdn07ge6wb0ef8.png" alt="Olise page Sports Pulse" width="799" height="638"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Olise page Sports Pulse&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Three of the top five got there mostly on follower growth, and that is a finding about tournaments, not about the metric. While the competition is running, the audience moves faster than the press does. Reporters filed a few hundred articles about Vozinha over four weeks. Tens of millions of people tapped follow. His story shows up in follower counts first and everywhere else later.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Attention Turned Into
&lt;/h2&gt;

&lt;p&gt;The attention score stops at the tournament window. Vozinha's story did not.&lt;/p&gt;

&lt;p&gt;Within weeks of the final he signed with Colo Colo, one of the biggest clubs in Chile, and reports linked him with offers from several other teams, including rumors of a move to Inter Miami to share a locker room with Messi. Sponsorship offers came after. And searches for &lt;a href="https://sports-pulse.apps.serpapi.com/teams/6a5521e76bb307ecf24ec2a0" rel="noopener noreferrer"&gt;Cape Verde&lt;/a&gt; itself climbed alongside its goalkeeper, a country of half a million people that most of the new audience could not have placed on a map in May.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7j70wkbvwqypigml20ss.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7j70wkbvwqypigml20ss.png" alt="Cape Verde search interest" width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cape Verde search interest&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;All of that happened to a 40-year-old goalkeeper, at an age when most careers are already over. The data in this post cannot tell you what caused any of it. What it can show is the moment the audience arrived, tens of millions of people in two match windows, and everything above followed while the world was watching.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Cannot Tell You
&lt;/h2&gt;

&lt;p&gt;Three honest limits, so the numbers above are read as what they are.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It does not explain why.&lt;/strong&gt; The score measures attention during the tournament. A player whose following grew after a strong performance grew after a strong performance. What produced that growth is outside anything these APIs can see.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It only knows 39 players.&lt;/strong&gt; Every score is relative to that hand-picked field and would change if the field changed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It measures attention, not merit.&lt;/strong&gt; A player can have an outstanding tournament in near silence. The score would show a low number, and it would be right about attention and say nothing about football.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How We Measured This
&lt;/h2&gt;

&lt;p&gt;Everything above comes from one pipeline built on four SerpApi engines. The &lt;a href="https://serpapi.com/google-sports-api" rel="noopener noreferrer"&gt;Google Sports API&lt;/a&gt; supplies the skeleton, the tournament's dates, the squads, and all 104 matches, so nobody maintains a match list by hand. On top of that skeleton, three signals are measured for every player on the watchlist over a window taken from the tournament's own dates. The &lt;a href="https://serpapi.com/google-trends-api" rel="noopener noreferrer"&gt;Google Trends API&lt;/a&gt; gives search interest, the &lt;a href="https://serpapi.com/google-news-api" rel="noopener noreferrer"&gt;Google News API&lt;/a&gt; gives coverage volume, and the &lt;a href="https://serpapi.com/instagram-profile-api" rel="noopener noreferrer"&gt;Instagram Profile API&lt;/a&gt; gives follower growth rather than raw totals, which is the difference between measuring who is already famous and measuring who is becoming famous.&lt;/p&gt;

&lt;p&gt;The three signals arrive in three incompatible units, so each is converted to the same scale before combining into a single 0 to 100 attention score. A player with a gap in one signal is scored on the signals that exist rather than punished with a zero.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg7wns2zkfm4wb44z0qvr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg7wns2zkfm4wb44z0qvr.png" alt="How the attention score is measured" width="799" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How the attention score is measured&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;How the conversion works and how each engine is queried in practice is a story of its own, and it did not fit here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pointing It at the Next Tournament
&lt;/h2&gt;

&lt;p&gt;Nothing in the pipeline knows it is looking at football. The window comes from the event's dates, the player list from the event's structure, and the score from comparing whoever is on the watchlist. Swap the event and the watchlist, and the same three signals work for the Champions League, the NBA, the NFL, and other sports events.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Yamal topped the board by being strong everywhere. Messi put up two of the biggest signals at the tournament next to a zero. And a 40-year-old goalkeeper from a country of half a million people finished fourth on a single column because tens of millions of people went looking for him at once.&lt;/p&gt;

&lt;p&gt;One blended number would have flattened all of that into a rank. Keeping the three signals visible is what lets you say why a player is on the board, and in Vozinha's case the why is the entire story.&lt;/p&gt;

&lt;p&gt;The dashboard is live at &lt;a href="https://sports-pulse.apps.serpapi.com/" rel="noopener noreferrer"&gt;Sports Pulse&lt;/a&gt;, with the full board, per player pages with the follower and search curves, per-match breakdowns, and a page that walks through the calculation on real data. I would start with Vozinha's page. The curve is the entire reason this exists.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Scrape Google Maps Autocomplete</title>
      <dc:creator>Noraina Nordin</dc:creator>
      <pubDate>Thu, 06 Aug 2026 09:56:15 +0000</pubDate>
      <link>https://dev.to/serpapi/how-to-scrape-google-maps-autocomplete-226</link>
      <guid>https://dev.to/serpapi/how-to-scrape-google-maps-autocomplete-226</guid>
      <description>&lt;p&gt;Google Maps Autocomplete creates a faster and smoother experience when users search for an address, place, or business location. The same as-you-type suggestions developers know from Google Places Autocomplete. Whether you're building a food delivery app, travel platform, store locator, CRM, or local search tool, the Google Maps Autocomplete helps users find the right location with fewer keystrokes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdo26nzlq16px3yzhnfao.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdo26nzlq16px3yzhnfao.png" alt="Google Maps Autocomplete" width="800" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Maps Autocomplete&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Does Google Maps Autocomplete API Do
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://serpapi.com/google-maps-autocomplete-api" rel="noopener noreferrer"&gt;Google Maps Autocomplete API&lt;/a&gt; by SerpApi allows developers to retrieve autocomplete suggestions from Google Maps with a simple API request. Because each place suggestion comes back with its street address attached, it doubles as an address autocomplete API for any app where users need to find a place or street quickly.&lt;/p&gt;

&lt;p&gt;Instead of managing browser automation or reverse engineering Google's autocomplete responses, you receive structured JSON that can be integrated directly into your application. No key juggling, no CAPTCHAs, no proxy pool. You send a query and a location, and you get back the same suggestions Google Maps would show, ready to drop into a search box, an address form, or a data pipeline.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fufq0ut8cgy7eedj7s65l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fufq0ut8cgy7eedj7s65l.png" alt="SerpApi's Google Maps Autocomplete API documentation" width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;SerpApi's Google Maps Autocomplete API documentation&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this tutorial, you'll learn how to scrape the autocomplete suggestions from Google Maps using a simple API with cURL, Python, and JavaScript, how to customize requests, and what data you can retrieve.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does the Google Maps Autocomplete API Work
&lt;/h2&gt;

&lt;p&gt;The API takes a partial query (&lt;code&gt;q&lt;/code&gt;) and a set of GPS coordinates (&lt;code&gt;ll&lt;/code&gt;) and returns the list of suggestions Google Maps would show for that input from that location. Some suggestions are plain keyword completions, some are specific places, and those come enriched with an address, latitude and longitude, and a &lt;code&gt;data_id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That &lt;code&gt;data_id&lt;/code&gt; is the part worth paying attention to. It's the same identifier the rest of the Google Maps family uses, so an autocomplete suggestion is an entry point, not a dead end. Pick a place from the suggestions, and you can pass its &lt;code&gt;data_id&lt;/code&gt; straight to the &lt;a href="https://serpapi.com/google-maps-reviews-api" rel="noopener noreferrer"&gt;Google Maps Reviews API&lt;/a&gt; or &lt;a href="https://serpapi.com/google-maps-photos-api" rel="noopener noreferrer"&gt;Google Maps Photos API&lt;/a&gt; to pull everything Google knows about it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://serpapi.com/playground?engine=google_maps_autocomplete" rel="noopener noreferrer"&gt;Try it out in the playground&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What data you can extract
&lt;/h2&gt;

&lt;p&gt;Each suggestion in the response can include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;value:&lt;/strong&gt; the suggested keyword or place name&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;type:&lt;/strong&gt; either &lt;code&gt;keyword&lt;/code&gt; (a search completion) or &lt;code&gt;place&lt;/code&gt; (a specific location)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;subtext:&lt;/strong&gt; for places, typically the street address&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;latitude/longitude:&lt;/strong&gt; coordinates of the place&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;data_id:&lt;/strong&gt; the place identifier, reusable across the Maps, Reviews, and Photos APIs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;reviews_serpapi_link:&lt;/strong&gt; a ready-made link to that place's reviews&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;photos_serpapi_link:&lt;/strong&gt; a ready-made link to that place's photos&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;maps_serpapi_link&lt;/strong&gt; : a ready-made link to that place's full Google Maps listing&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to use the Autocomplete API
&lt;/h2&gt;

&lt;p&gt;Here's the quickest way to see the data before writing any code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Open the playground
&lt;/h3&gt;

&lt;p&gt;Head to the &lt;a href="https://serpapi.com/playground?engine=google_maps_autocomplete" rel="noopener noreferrer"&gt;Google Maps Autocomplete playground&lt;/a&gt;. No sign-up is needed to run a first search.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Enter a query and coordinates
&lt;/h3&gt;

&lt;p&gt;Set &lt;code&gt;q&lt;/code&gt; to the partial term a user might type, let's say &lt;code&gt;cafe&lt;/code&gt; and set &lt;code&gt;ll&lt;/code&gt; to the location the search should originate from, in the format &lt;code&gt;@latitude,longitude,zoom&lt;/code&gt;, for example &lt;code&gt;@40.7455096,-74.0083012,14z&lt;/code&gt;. The zoom value ranges from &lt;code&gt;3z&lt;/code&gt; (fully zoomed out) to &lt;code&gt;21z&lt;/code&gt; (fully zoomed in). If you need to find coordinates for a place, our guide on &lt;a href="https://serpapi.com/blog/how-to-find-the-gps-coordinates-of-any-place-with-google-maps/" rel="noopener noreferrer"&gt;how to find the GPS coordinates of any place&lt;/a&gt; walks through it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1p1fa02usd0zfft90i0m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1p1fa02usd0zfft90i0m.png" alt="SerpApi's Google Maps Autocomplete Playground" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;SerpApi's Google Maps Autocomplete Playground&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Run the search
&lt;/h3&gt;

&lt;p&gt;The response comes back as JSON, with keyword completions and nearby places interleaved the way Google Maps returns them. A trimmed example for &lt;code&gt;q=cafe&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"suggestions"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"cafè"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"serpapi_link"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"https://serpapi.com/search.json?engine=google_maps_autocomplete&amp;amp;ll=%4040.7455096%2C-74.0083012%2C14z&amp;amp;q=caf%C3%A8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"maps_serpapi_link"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"https://serpapi.com/search.json?engine=google_maps&amp;amp;google_domain=google.com&amp;amp;hl=en&amp;amp;ll=%4040.7455096%2C-74.0083012%2C14z&amp;amp;q=caf%C3%A8&amp;amp;type=search"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"keyword"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Cafe Paradiso"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"serpapi_link"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"https://serpapi.com/search.json?engine=google_maps_autocomplete&amp;amp;ll=%4040.7455096%2C-74.0083012%2C14z&amp;amp;q=Cafe+Paradiso"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"subtext"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"West 65th Street, New York, NY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"place"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"latitude"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;40.7733834&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"longitude"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;-73.9835585&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"data_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"0x89c2596625484969:0xdcf19d6c26e407c2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"reviews_serpapi_link"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"https://serpapi.com/search.json?data_id=0x89c2596625484969%3A0xdcf19d6c26e407c2&amp;amp;engine=google_maps_reviews&amp;amp;hl=en"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"photos_serpapi_link"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"https://serpapi.com/search.json?data_id=0x89c2596625484969%3A0xdcf19d6c26e407c2&amp;amp;engine=google_maps_photos&amp;amp;hl=en"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"maps_serpapi_link"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"https://serpapi.com/search.json?data=%214m5%213m4%211s0x89c2596625484969%3A0xdcf19d6c26e407c2%218m2%213d40.7733834%214d-73.9835585&amp;amp;engine=google_maps&amp;amp;google_domain=google.com&amp;amp;hl=en&amp;amp;ll=%4040.7455096%2C-74.0083012%2C14z&amp;amp;q=Cafe+Paradiso&amp;amp;type=place"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  cURL
&lt;/h2&gt;

&lt;p&gt;The quickest way to call the API from the command line is a single &lt;code&gt;GET&lt;/code&gt; request. Pass your query in &lt;code&gt;q&lt;/code&gt;, the origin coordinates in &lt;code&gt;ll&lt;/code&gt;, and your &lt;a href="https://serpapi.com/manage-api-key" rel="noopener noreferrer"&gt;API key&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--get&lt;/span&gt; &lt;span class="s2"&gt;"https://serpapi.com/search"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"google_maps_autocomplete"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;q&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"cafe"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;ll&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"@40.7455096,-74.0083012,14z"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"YOUR_SERPAPI_API_KEY"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response is the same structured JSON shown above. From here, the Python and JavaScript examples below wrap the same request so you can parse the suggestions in your app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Python tutorial
&lt;/h2&gt;

&lt;p&gt;First install the SerpApi client library (&lt;a href="https://github.com/serpapi/serpapi-python" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;serpapi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then set your &lt;a href="https://serpapi.com/manage-api-key" rel="noopener noreferrer"&gt;API key&lt;/a&gt; and run the search:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;serpapi&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;serpapi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_SERPAPI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;engine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;google_maps_autocomplete&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;q&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cafe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ll&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@40.7455096,-74.0083012,14z&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get the suggestions and their type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;suggestion&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;suggestions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;suggestion&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;suggestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To keep only the place suggestions and their &lt;code&gt;data_id&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;places&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;suggestions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;place&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;place&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;places&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;place&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;place&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;subtext&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;place&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj4kkulskora6jfs02k2y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fj4kkulskora6jfs02k2y.png" alt="Results from the Python script" width="799" height="181"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Results from the Python script&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  JavaScript tutorial
&lt;/h2&gt;

&lt;p&gt;Install the package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install serpapi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getJson&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;serpapi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;API_KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// https://serpapi.com/manage-api-key&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getSuggestions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;google_maps_autocomplete&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;q&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;ll&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@40.7455096,-74.0083012,14z&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;gl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;us&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;hl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;suggestions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getSuggestions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cafe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get the suggestions and their type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;suggestions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getSuggestions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cafe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;suggestion&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;suggestions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;suggestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;suggestion&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To keep only the place suggestions and their &lt;code&gt;data_id&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;places&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;suggestions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;place&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;place&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;places&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;place&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;place&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subtext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;place&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data_id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since every place suggestion carries a &lt;code&gt;data_id&lt;/code&gt;, you can pass it straight to the &lt;a href="https://serpapi.com/google-maps-reviews-api" rel="noopener noreferrer"&gt;Reviews&lt;/a&gt; or &lt;a href="https://serpapi.com/google-maps-photos-api" rel="noopener noreferrer"&gt;Photos API&lt;/a&gt; to pull that place's reviews or photos, with no separate request to look it up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common use cases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Search-as-you-type place pickers.&lt;/strong&gt; Feed the suggestions straight into an autocomplete dropdown so users can select a business or landmark as they type, with coordinates already attached.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Address and location entry.&lt;/strong&gt; Speed up checkout, sign-up, and booking forms with location suggestions, without standing up and metering your own Places Autocomplete key.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Seeding data pipelines.&lt;/strong&gt; Use autocomplete as the first step in a scrape. Resolve a partial name into a concrete &lt;code&gt;data_id&lt;/code&gt;, then pull the full place, its reviews, and its photos from the rest of the Maps APIs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local keyword and place discovery.&lt;/strong&gt; Vary the &lt;code&gt;ll&lt;/code&gt; coordinates to see which places and completions Google surfaces from different locations, useful for local research and coverage checks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is the Google Maps Autocomplete API free?
&lt;/h3&gt;

&lt;p&gt;SerpApi's free plan includes 250 searches per month with no credit card required, which is enough to build and test an integration before you commit to a plan.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need to pass coordinates?
&lt;/h3&gt;

&lt;p&gt;Yes. The &lt;code&gt;ll&lt;/code&gt; parameter is required, since autocomplete results depend on where the search originates. The &lt;code&gt;gl&lt;/code&gt; and &lt;code&gt;hl&lt;/code&gt; parameters for country and language are optional.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use it as an address autocomplete API?
&lt;/h3&gt;

&lt;p&gt;Yes. Because each place suggestion comes back with its street address attached, it works as an address autocomplete API for address forms, checkout pages, and any interface where users need address suggestions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I get full place details from a suggestion?
&lt;/h3&gt;

&lt;p&gt;Yes. Each place suggestion includes a &lt;code&gt;data_id&lt;/code&gt; you can pass to the &lt;a href="https://serpapi.com/google-maps-api" rel="noopener noreferrer"&gt;Google Maps API&lt;/a&gt;, &lt;a href="https://serpapi.com/google-maps-reviews-api" rel="noopener noreferrer"&gt;Reviews API&lt;/a&gt;, or &lt;a href="https://serpapi.com/google-maps-photos-api" rel="noopener noreferrer"&gt;Photos API&lt;/a&gt; to retrieve ratings, hours, reviews, photos, and more.&lt;/p&gt;

&lt;h3&gt;
  
  
  How is this different from Google Places Autocomplete?
&lt;/h3&gt;

&lt;p&gt;Google Places Autocomplete is Google's own service. The difference is operational: with SerpApi, there's no Google Cloud project, API key, or billing to set up, and no session tokens to manage. Every place suggestion chains directly into SerpApi's other Google Maps endpoints for reviews, photos, and full place details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Documentation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/google-maps-autocomplete-api" rel="noopener noreferrer"&gt;Google Maps Autocomplete API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/google-maps-api" rel="noopener noreferrer"&gt;Google Maps API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/google-maps-reviews-api" rel="noopener noreferrer"&gt;Google Maps Reviews API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/google-maps-photos-api" rel="noopener noreferrer"&gt;Google Maps Photos API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a broader look at pulling place data, ratings, and reviews from Google Maps, see our &lt;a href="https://serpapi.com/blog/google-maps-scraper/" rel="noopener noreferrer"&gt;Google Maps Scraper&lt;/a&gt; guide. If you're after search keyword suggestions rather than places, our guide on &lt;a href="https://serpapi.com/blog/how-to-scrape-google-autocomplete-results/" rel="noopener noreferrer"&gt;how to scrape Google Autocomplete results&lt;/a&gt; covers the Google Search side.&lt;/p&gt;

&lt;p&gt;You can reach us at &lt;a href="mailto:contact@serpapi.com"&gt;contact@serpapi.com&lt;/a&gt; for any questions.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Build an AI Event Discovery Agent That Adds Events to Your Calendar in One Click</title>
      <dc:creator>Sonika Arora</dc:creator>
      <pubDate>Tue, 04 Aug 2026 01:42:20 +0000</pubDate>
      <link>https://dev.to/serpapi/build-an-ai-event-discovery-agent-that-adds-events-to-your-calendar-in-one-click-55dk</link>
      <guid>https://dev.to/serpapi/build-an-ai-event-discovery-agent-that-adds-events-to-your-calendar-in-one-click-55dk</guid>
      <description>&lt;p&gt;AI and software professionals often miss valuable conferences, meetups, and webinars because relevant events are scattered across dozens of websites. Instead of manually searching and comparing listings every week, an AI agent can continuously discover events that match your interests, location, and schedule, and then even add them directly to your calendar.&lt;/p&gt;

&lt;p&gt;In this tutorial, we'll build an AI-powered Event Discovery Agent using SerpApi MCP and Claude that takes care of discovery and recommendation. You'll be able to give the agent instructions, using which it will discover events and produce a clean markdown report with recommended events.&lt;/p&gt;

&lt;p&gt;Follow along and by the end, you'll have built a personalized AI event concierge.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We'll Build
&lt;/h2&gt;

&lt;p&gt;The goal is to be able to ask Claude:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Find upcoming AI conferences, meetups, and webinars.

My preferences:
- Located within an hour from San Francisco
- Interested in AI agents, MCP, RAG, and developer tools
- Budget under $500
- Prefer in-person events
- Within the next 90 days

Generate a Markdown report and provide Google Calendar links.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude will use SerpApi MCP to search Google events and gather structured event data. Then, it will rank events by relevance, create calendar links and generate a final markdown report.&lt;/p&gt;

&lt;p&gt;Example output we aim to see:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvm1b9v26wol5c2ouze9l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvm1b9v26wol5c2ouze9l.png" width="800" height="896"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create a SerpApi Account
&lt;/h3&gt;

&lt;p&gt;For this tutorial, we're going to use &lt;a href="https://serpapi.com/google-events-api" rel="noopener noreferrer"&gt;SerpApi's Google Events API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To begin scraping data, create a&amp;nbsp;&lt;a href="https://serpapi.com/users/sign_up" rel="noopener noreferrer"&gt;free account on serpapi.com&lt;/a&gt;. You'll receive 250 free search credits each month to explore the API. Get your SerpApi API key here:&amp;nbsp;&lt;a href="https://serpapi.com/manage-api-key" rel="noopener noreferrer"&gt;https://serpapi.com/manage-api-key&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Install Claude Code
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 You'll need to create an account with Claude in case you don't have one yet. You can do that here:&amp;nbsp;&lt;a href="https://claude.ai/login" rel="noopener noreferrer"&gt;https://claude.ai/login&lt;/a&gt;&lt;br&gt;&lt;br&gt;
To access Claude Code, you'll need a Claude Pro, Max, or Team &lt;a href="https://www.anthropic.com/pricing" rel="noopener noreferrer"&gt;subscription&lt;/a&gt; OR you can pay per usage via&amp;nbsp;&lt;a href="https://www.anthropic.com/pricing#api" rel="noopener noreferrer"&gt;Claude API&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Install Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @anthropic-ai/claude-code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the installation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see the installed version printed in your terminal.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure SerpApi MCP
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/serpapi/serpapi-mcp" rel="noopener noreferrer"&gt;SerpApi's MCP server&lt;/a&gt; allows AI assistants to perform live searches using your SerpApi subscription without requiring custom tool implementation. Claude Code can connect to external MCP Servers like SerpApi's to perform searches.&lt;/p&gt;

&lt;p&gt;We'll add the SerpApi MCP server to Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; http serpapi https://mcp.serpapi.com/YOUR_SERPAPI_API_KEY/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once configured, Claude Code can access SerpApi tools directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verify the MCP Connection
&lt;/h3&gt;

&lt;p&gt;Run the following command in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see output similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Configured MCP servers:

✓ serpapi
  URL: https://serpapi.com/...
  Status: Connected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the &lt;code&gt;serpapi&lt;/code&gt; server appears in the list, Claude Code has successfully detected the MCP server and can use SerpApi tools during your session. If you don't see the server listed, double-check your MCP configuration and API key, then rerun the setup command.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 If you need to remove an incorrectly configured serpapi MCP server, use this command to remove it before rerunning the setup command: &lt;code&gt;claude mcp remove serpapi&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Create a Project Directory
&lt;/h3&gt;

&lt;p&gt;Create a workspace for the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;event-discovery-agent
&lt;span class="nb"&gt;cd &lt;/span&gt;event-discovery-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll store generated reports here.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;event-discovery-agent/
├── events.md
└── prompts.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The events.md file will be generated by Claude.&lt;/p&gt;

&lt;h2&gt;
  
  
  Define the Agent's Instructions
&lt;/h2&gt;

&lt;p&gt;Here, we provide instructions describing the events we want. This step is important because we're not just searching. We're defining decision criteria.&lt;/p&gt;

&lt;p&gt;Think of this as the equivalent of giving requirements to a human assistant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Without requirements&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Find AI events.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;With requirements&lt;/strong&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Find AI events focused on developers,
exclude expensive conferences,
prioritize in-person networking opportunities.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second prompt produces dramatically better results.&lt;/p&gt;

&lt;p&gt;Let's create a file called &lt;code&gt;prompts.md&lt;/code&gt; in the &lt;code&gt;event-discovery-agent/&lt;/code&gt; directory and add a detailed prompt there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Use SerpApi MCP to find upcoming conferences, meetups, and webinars related to AI agents, MCP, RAG, and developer tooling.

Requirements:
&lt;span class="p"&gt;-&lt;/span&gt; Within 100 miles of San Francisco
&lt;span class="p"&gt;-&lt;/span&gt; Budget under $500
&lt;span class="p"&gt;-&lt;/span&gt; Next 90 days
&lt;span class="p"&gt;-&lt;/span&gt; Prefer in-person events

Create a file called events.md.

For each event include:
&lt;span class="p"&gt;-&lt;/span&gt; Event title
&lt;span class="p"&gt;-&lt;/span&gt; Date
&lt;span class="p"&gt;-&lt;/span&gt; Location
&lt;span class="p"&gt;-&lt;/span&gt; Event URL
&lt;span class="p"&gt;-&lt;/span&gt; Why it matches my interests
&lt;span class="p"&gt;-&lt;/span&gt; Google Calendar link
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prompt is the agent's operating instructions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run the Event Discovery Agent
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Start Claude Code
&lt;/h3&gt;

&lt;p&gt;Head over to the &lt;code&gt;event-discovery-agent/&lt;/code&gt; directory and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first time you run it, Claude Code will prompt you to log in. Once you're logged in, you'll see an interactive prompt similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now chat with Claude Code directly. By default, Claude Code will have access to all files in the &lt;code&gt;event-discovery-agent/&lt;/code&gt; directory.&lt;/p&gt;

&lt;h3&gt;
  
  
  Send Claude the prompt file
&lt;/h3&gt;

&lt;p&gt;Now simply give Claude Code the prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Read prompts.md and &lt;span class="nb"&gt;complete &lt;/span&gt;the task.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude will follow the instructions in &lt;code&gt;prompts.md&lt;/code&gt; and the final output file &lt;code&gt;events.md&lt;/code&gt; (with a curated list of events) will be created in the same directory once Claude finishes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Claude may ask you to confirm if it can perform certain searches. In that case, you must respond with yes so it can complete the task successfully.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Behind the Scenes of the Agent
&lt;/h2&gt;

&lt;p&gt;A software script works great to filter events by date or location. But the agent can evaluate relevance.&lt;/p&gt;

&lt;p&gt;For example, suppose an event description contains:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Enterprise AI&lt;br&gt;&lt;br&gt;
Agent Frameworks&lt;br&gt;&lt;br&gt;
RAG Systems&lt;br&gt;&lt;br&gt;
MCP Integrations&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Claude can recognize that the event strongly matches the user's interests.&lt;/p&gt;

&lt;p&gt;Another event may contain:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Academic Research&lt;br&gt;&lt;br&gt;
AI neural network Theory&lt;br&gt;&lt;br&gt;
Graduate Student Workshop&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even if it technically matches the keyword "AI", Claude may determine that it is less relevant for a software engineer.&lt;/p&gt;

&lt;p&gt;The agent thinks about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is this event relevant?&lt;/li&gt;
&lt;li&gt;How strongly does it align with preferences?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This reasoning step is what makes the output valuable. Rather than simply listing events, Claude also explains why each one was selected. This is another place where AI adds value beyond simple search results..&lt;/p&gt;

&lt;p&gt;Once events have been evaluated, Claude ranks them. Rather than dumping twenty search results into a report, the agent highlights the most useful opportunities first. This makes the final report feel curated rather than generated.&lt;/p&gt;

&lt;p&gt;For each event, Claude generates a Google Calendar URL. These URLs contain all event information such as event title, date/time, location etc. When users click the link, Google Calendar opens with a pre-filled event draft. The event can be added to your schedule in one click.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample Response
&lt;/h2&gt;

&lt;p&gt;Claude created an &lt;code&gt;events.md&lt;/code&gt; file after multiple SerpApi requests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs5p60tw5qdsmnokft9vh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs5p60tw5qdsmnokft9vh.png" width="800" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's the final result in &lt;code&gt;events.md&lt;/code&gt; at the end of Claude's research:&lt;/p&gt;

&lt;blockquote&gt;
&lt;h4&gt;
  
  
  &lt;code&gt;events.md&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Upcoming AI / Developer Events near San Francisco&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Search focus:&lt;/strong&gt; AI agents, MCP, RAG, and developer tooling&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Filters applied:&lt;/strong&gt; within ~100 miles of San Francisco · budget under $500 · next 90 days (Jul 14 – Oct 12, 2026) · in-person preferred&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Source:&lt;/strong&gt; SerpApi Google Events engine (searched 2026-07-14), with ticket pricing spot-checked via web search.&lt;/p&gt;

&lt;p&gt;Note on budget: meetups below are free or low-cost. For the multi-day conferences, ticket tiers vary — I've flagged which ones can stay under $500 (early-bird / expo tiers) and which typically exceed it. Always confirm the current price on the registration page before booking.&lt;/p&gt;

&lt;p&gt;✅ Best matches (in-person, near SF, next 90 days, likely under $500)1. Data for AI: One AI, Every Data Model&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Date:&lt;/strong&gt; Wednesday, July 22, 2026, 5:30–8:30 PM&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Location:&lt;/strong&gt; AWS Builder Loft, 525 Market St, San Francisco, CA&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event URL:&lt;/strong&gt; &lt;a href="https://datastrato.ai/events/data-for-ai-one-ai-every-data-model" rel="noopener noreferrer"&gt;https://datastrato.ai/events/data-for-ai-one-ai-every-data-model&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it matches:&lt;/strong&gt; An evening builder session on constructing a single AI layer over every data model — directly relevant to RAG and the data-infrastructure side of agentic apps. Hosted at the AWS Builder Loft, hands-on developer audience, and free to attend (well under budget).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Calendar:&lt;/strong&gt; &lt;a href="https://calendar.google.com/calendar/render?action=TEMPLATE&amp;amp;text=Data%20for%20AI%3A%20One%20AI%2C%20Every%20Data%20Model&amp;amp;dates=20260722T173000/20260722T203000&amp;amp;ctz=America/Los_Angeles&amp;amp;location=AWS%20Builder%20Loft%2C%20525%20Market%20St%2C%20San%20Francisco%2C%20CA&amp;amp;details=https%3A%2F%2Fdatastrato.ai%2Fevents%2Fdata-for-ai-one-ai-every-data-model" rel="noopener noreferrer"&gt;https://calendar.google.com/calendar/render?action=TEMPLATE&amp;amp;text=Data for AI%3A One AI%2C Every Data Model&amp;amp;dates=20260722T173000/20260722T203000&amp;amp;ctz=America/Los_Angeles&amp;amp;location=AWS Builder Loft%2C 525 Market St%2C San Francisco%2C CA&amp;amp;details=https%3A%2F%2Fdatastrato.ai%2Fevents%2Fdata-for-ai-one-ai-every-data-model&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;19th San Jose Hardware Meetup — AI/ML in Lab Automation&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Date:&lt;/strong&gt; Tuesday, July 21, 2026, 6:00–9:00 PM&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Location:&lt;/strong&gt; BigHat Biosciences, 1900 Alameda de las Pulgas, Ste 400, San Mateo, CA&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event URL:&lt;/strong&gt; &lt;a href="https://somo.social/e/19th-san-jose-hardware-meetup-722" rel="noopener noreferrer"&gt;https://somo.social/e/19th-san-jose-hardware-meetup-722&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it matches:&lt;/strong&gt; A free, in-person developer/ML community meetup exploring applied AI and ML pipelines (here, in lab automation). Good for the developer-tooling and applied-ML side of your interests, and a strong local-network opportunity in the Peninsula.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Calendar:&lt;/strong&gt; &lt;a href="https://calendar.google.com/calendar/render?action=TEMPLATE&amp;amp;text=19th%20San%20Jose%20Hardware%20Meetup%3A%20AI%2FML%20in%20Lab%20Automation&amp;amp;dates=20260721T180000/20260721T210000&amp;amp;ctz=America/Los_Angeles&amp;amp;location=BigHat%20Biosciences%2C%201900%20Alameda%20de%20las%20Pulgas%20Ste%20400%2C%20San%20Mateo%2C%20CA&amp;amp;details=https%3A%2F%2Fsomo.social%2Fe%2F19th-san-jose-hardware-meetup-722" rel="noopener noreferrer"&gt;https://calendar.google.com/calendar/render?action=TEMPLATE&amp;amp;text=19th San Jose Hardware Meetup%3A AI%2FML in Lab Automation&amp;amp;dates=20260721T180000/20260721T210000&amp;amp;ctz=America/Los_Angeles&amp;amp;location=BigHat Biosciences%2C 1900 Alameda de las Pulgas Ste 400%2C San Mateo%2C CA&amp;amp;details=https%3A%2F%2Fsomo.social%2Fe%2F19th-san-jose-hardware-meetup-722&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;API World 2026 (with AI TechWorld)&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Date:&lt;/strong&gt; Tuesday–Thursday, September 1–3, 2026&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Location:&lt;/strong&gt; Santa Clara Convention Center, 5001 Great America Pkwy, Santa Clara, CA (~45 mi from SF)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event URL:&lt;/strong&gt; &lt;a href="https://apiworld.co/" rel="noopener noreferrer"&gt;https://apiworld.co/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it matches:&lt;/strong&gt; Billed as the world's largest API conference &amp;amp; expo, co-located with AI TechWorld — squarely in the developer-tooling space (APIs, integrations, agent tooling). Choose the &lt;strong&gt;free Expo pass or the OPEN tier (early-bird ~$299–$399)&lt;/strong&gt; to stay under $500; PRO/PREMIUM passes run higher, so avoid those to honor the budget.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Calendar:&lt;/strong&gt; &lt;a href="https://calendar.google.com/calendar/render?action=TEMPLATE&amp;amp;text=2026%20API%20World%20%26%20AI%20TechWorld&amp;amp;dates=20260901/20260904&amp;amp;ctz=America/Los_Angeles&amp;amp;location=Santa%20Clara%20Convention%20Center%2C%205001%20Great%20America%20Pkwy%2C%20Santa%20Clara%2C%20CA&amp;amp;details=https%3A%2F%2Fapiworld.co%2F" rel="noopener noreferrer"&gt;https://calendar.google.com/calendar/render?action=TEMPLATE&amp;amp;text=2026 API World %26 AI TechWorld&amp;amp;dates=20260901/20260904&amp;amp;ctz=America/Los_Angeles&amp;amp;location=Santa Clara Convention Center%2C 5001 Great America Pkwy%2C Santa Clara%2C CA&amp;amp;details=https%3A%2F%2Fapiworld.co%2F&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚠️ Strong topic match, but tickets typically exceed $500&lt;/p&gt;

&lt;p&gt;These are excellent for AI agents / RAG / dev-tooling content and are in-person near SF within the window, but standard passes generally run above the $500 budget. Listed for awareness — check for free expo passes, community/scholarship tickets, or day passes that might fit.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;GenAI Summit SF 2026 (co-located with AGI Summit — "The Rise of Agentic Intelligence")&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Date:&lt;/strong&gt; Saturday–Sunday, July 18–19, 2026&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Location:&lt;/strong&gt; Palace of Fine Arts, 3301 Lyon St, San Francisco, CA&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event URL:&lt;/strong&gt; &lt;a href="https://www.eventbrite.com/e/genai-summit-sf-2026-tickets-1985545163032" rel="noopener noreferrer"&gt;https://www.eventbrite.com/e/genai-summit-sf-2026-tickets-1985545163032&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it matches:&lt;/strong&gt; Large generative-AI gathering; the paired AGI Summit track focuses explicitly on agentic intelligence. Great for AI-agents content — but full passes typically exceed $500 (look for an early-bird code or expo/hackathon pass to fit budget).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Calendar:&lt;/strong&gt; &lt;a href="https://calendar.google.com/calendar/render?action=TEMPLATE&amp;amp;text=GenAI%20Summit%20SF%202026&amp;amp;dates=20260718/20260720&amp;amp;ctz=America/Los_Angeles&amp;amp;location=Palace%20of%20Fine%20Arts%2C%203301%20Lyon%20St%2C%20San%20Francisco%2C%20CA&amp;amp;details=https%3A%2F%2Fwww.eventbrite.com%2Fe%2Fgenai-summit-sf-2026-tickets-1985545163032" rel="noopener noreferrer"&gt;https://calendar.google.com/calendar/render?action=TEMPLATE&amp;amp;text=GenAI Summit SF 2026&amp;amp;dates=20260718/20260720&amp;amp;ctz=America/Los_Angeles&amp;amp;location=Palace of Fine Arts%2C 3301 Lyon St%2C San Francisco%2C CA&amp;amp;details=https%3A%2F%2Fwww.eventbrite.com%2Fe%2Fgenai-summit-sf-2026-tickets-1985545163032&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;The AI Conference 2026&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Date:&lt;/strong&gt; Tuesday–Thursday, September 29 – October 1, 2026&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Location:&lt;/strong&gt; Pier 48 (Sheds A &amp;amp; B), San Francisco, CA&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event URL:&lt;/strong&gt; &lt;a href="https://aiconference.com/" rel="noopener noreferrer"&gt;https://aiconference.com/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it matches:&lt;/strong&gt; Applied-AI conference with a dedicated &lt;strong&gt;agentic AI&lt;/strong&gt; track plus LLMs and infrastructure — 120+ speakers, builder-heavy. Highly on-topic; standard passes generally run ~$1,000+, so only fits budget via a discounted/early team ticket.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Calendar:&lt;/strong&gt; &lt;a href="https://calendar.google.com/calendar/render?action=TEMPLATE&amp;amp;text=The%20AI%20Conference%202026&amp;amp;dates=20260929/20261002&amp;amp;ctz=America/Los_Angeles&amp;amp;location=Pier%2048%2C%20San%20Francisco%2C%20CA&amp;amp;details=https%3A%2F%2Faiconference.com%2F" rel="noopener noreferrer"&gt;https://calendar.google.com/calendar/render?action=TEMPLATE&amp;amp;text=The AI Conference 2026&amp;amp;dates=20260929/20261002&amp;amp;ctz=America/Los_Angeles&amp;amp;location=Pier 48%2C San Francisco%2C CA&amp;amp;details=https%3A%2F%2Faiconference.com%2F&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Salesforce Dreamforce 2026&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Date:&lt;/strong&gt; Tuesday–Thursday, September 15–17, 2026&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Location:&lt;/strong&gt; Moscone Center, 747 Howard St, San Francisco, CA&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event URL:&lt;/strong&gt; &lt;a href="https://www.salesforce.com/dreamforce/" rel="noopener noreferrer"&gt;https://www.salesforce.com/dreamforce/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it matches:&lt;/strong&gt; Heavy focus on Agentforce and enterprise AI agents. Relevant to the AI-agents theme, but the full pass (~$1,999) is well over budget — included only if a free/community or expo pass becomes available.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google Calendar:&lt;/strong&gt; &lt;a href="https://calendar.google.com/calendar/render?action=TEMPLATE&amp;amp;text=Salesforce%20Dreamforce%202026&amp;amp;dates=20260915/20260918&amp;amp;ctz=America/Los_Angeles&amp;amp;location=Moscone%20Center%2C%20747%20Howard%20St%2C%20San%20Francisco%2C%20CA&amp;amp;details=https%3A%2F%2Fwww.salesforce.com%2Fdreamforce%2F" rel="noopener noreferrer"&gt;https://calendar.google.com/calendar/render?action=TEMPLATE&amp;amp;text=Salesforce Dreamforce 2026&amp;amp;dates=20260915/20260918&amp;amp;ctz=America/Los_Angeles&amp;amp;location=Moscone Center%2C 747 Howard St%2C San Francisco%2C CA&amp;amp;details=https%3A%2F%2Fwww.salesforce.com%2Fdreamforce%2F&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notes &amp;amp; tips&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Closest topic fit found:&lt;/strong&gt;"Graph Exchange — Agentic AI Memory" (GraphRAG + AI agents, AWS Builder Loft SF) and "AI Loves Data SF: GenAI &amp;amp; Intelligent Agents" are near-perfect matches but fall on &lt;strong&gt;Nov 5 &amp;amp; Nov 18, 2026&lt;/strong&gt; — just outside the 90-day window. Worth setting a reminder to register when they open.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For free, on-topic meetups on short notice&lt;/strong&gt; , watch the AWS Builder Loft (525 Market St) calendar and lu.ma / Meetup groups for "AI agents," "MCP," and "RAG" — these tend to be posted only 2–4 weeks ahead, so re-run this search monthly.&lt;/li&gt;
&lt;li&gt;Google Calendar links are pre-filled with title, date, location, and the event URL. Times are set to America/Los_Angeles; multi-**day conferences are added as all-day spans.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Sources:&lt;/em&gt; &lt;a href="https://serpapi.com/" rel="noopener noreferrer"&gt;&lt;em&gt;SerpApi Google Events&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href="https://apiworld.co/" rel="noopener noreferrer"&gt;&lt;em&gt;API World&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href="https://www.eventbrite.com/e/genai-summit-sf-2026-tickets-1985545163032" rel="noopener noreferrer"&gt;&lt;em&gt;GenAI Summit (Eventbrite)&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href="https://aiconference.com/" rel="noopener noreferrer"&gt;&lt;em&gt;The AI Conference&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because Claude Code can create files directly, the output becomes a reusable artifact rather than a temporary chat response. Every week or month, you can rerun the workflow and generate an updated report.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this project, we used Claude Code and SerpApi MCP to build an AI-powered Event Discovery Agent. Through a single prompt, Claude was able to discover conferences and meetups using SerpApi, evaluate each event against user-defined preferences, generate Google Calendar links, and compile the results into a clean Markdown report.&lt;/p&gt;

&lt;p&gt;I hope you found this useful. If you have any questions, feel free to reach out at&amp;nbsp;&lt;a href="mailto:contact@serpapi.com"&gt;contact@serpapi.com&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Relevant Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/google-events-api" rel="noopener noreferrer"&gt;SerpApi's Google Events API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/playground?engine=google_events" rel="noopener noreferrer"&gt;Explore Google Events API in playground&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.claude.com/docs/en/quickstart" rel="noopener noreferrer"&gt;Claude Code Quickstart Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Related Blog Posts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/build-an-ai-agent-with-claude-agent-sdk/" rel="noopener noreferrer"&gt;Build an AI Agent with the Claude Agent SDK (Tutorial 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/top-5-practical-use-cases-for-serpapi-mcp-server-in-ai-agents/" rel="noopener noreferrer"&gt;Top 5 Practical Use Cases for SerpApi MCP Server in AI Agents&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/introducing-serpapis-claude-code-plugin/" rel="noopener noreferrer"&gt;Introducing SerpApi’s Claude Code Plugin&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Google Search Parameters (2026 Guide)</title>
      <dc:creator>Noraina Nordin</dc:creator>
      <pubDate>Mon, 03 Aug 2026 09:36:47 +0000</pubDate>
      <link>https://dev.to/serpapi/google-search-parameters-2026-guide-1cnk</link>
      <guid>https://dev.to/serpapi/google-search-parameters-2026-guide-1cnk</guid>
      <description>&lt;p&gt;The Google Search URL parameters are important to understand whether you are maximizing the conversion rate in your ad groups and optimizing your cost per click(CPC) rates in Google Analytics for your ad campaigns, improving your SEO(Search Engine Optimization) metrics for your e-commerce business, or collecting data for your social media project. Using custom parameters for your search will affect the Search Engine Result Page (SERP) data significantly in your favor. &lt;a href="https://serpapi.com" rel="noopener noreferrer"&gt;SerpApi&lt;/a&gt; unlocks the power of SERP data to you with minimal effort, the fastest response times, and in the most complete form.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://serpapi.com/users/sign_up" rel="noopener noreferrer"&gt;Register to claim free credits&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this blog post, we will explore some of the Google search parameters with their corresponding attributions in &lt;a href="https://serpapi.com/search-api" rel="noopener noreferrer"&gt;SerpApi Documentation&lt;/a&gt;. You can head to &lt;a href="https://serpapi.com/playground" rel="noopener noreferrer"&gt;SerpApi Playground&lt;/a&gt; to test all of the information you will read below.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Google Search parameters?
&lt;/h2&gt;

&lt;p&gt;Google Search parameters are like special codes you can add to the web address (URL) when you search on Google. They help you control and customize your search results. For example, you can use them to specify the language or location for your search.&lt;/p&gt;

&lt;p&gt;Here's how they work: When you type a search query into Google, it creates a URL with your search terms. You can then add parameters to this URL using an ampersand (&amp;amp;) followed by the parameter name and value. These parameters, often called "params" for short, tell Google how you want your search results to be customized.&lt;/p&gt;

&lt;p&gt;For instance, if you want to search for "cats" in Spanish, you could add &lt;code&gt;"hl=es"&lt;/code&gt; to the end of the URL. This tells Google to show results in Spanish. Once you've added all the parameters you want, you have your final URL ready for tailoring your tracking template. When you open this URL in your web browser, Google will show you search results based on the parameters you've specified.&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;q&lt;/code&gt; parameter
&lt;/h2&gt;

&lt;p&gt;It represents the search query submitted to Google. For example, in &lt;code&gt;"q=Coffee"&lt;/code&gt;, "Coffee" is the query you're searching for. It can also be used with special commands for filtering specific file types, filtering keywords in URLs and bodies, etc. giving you more exact matches. Some of these advanced search operators include filetype, inurl, intitle, intext, inanchor, allinurl, allinanchor, allintitle, allintext. You can check out &lt;a href="https://serpapi.com/blog/ultimate-guide-to-google-search-operators-2023-guide/" rel="noopener noreferrer"&gt;Ultimate Guide to Google Search Operators&lt;/a&gt; for detailed, and up-to-date information on how to use Google search operators.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8g0uwx3mngd89ofmy5nr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8g0uwx3mngd89ofmy5nr.jpg" alt="q" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google search with q parameter&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://serpapi.com/search-api#api-parameters-search-query-q" rel="noopener noreferrer"&gt;Reference in SerpApi Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;'oq'&lt;/code&gt; parameter of Google represents the query typed into the Google search box.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F24txdrjdy5wvf422zire.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F24txdrjdy5wvf422zire.jpg" alt="oq" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google search with oq parameter&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;hl&lt;/code&gt; parameter
&lt;/h2&gt;

&lt;p&gt;It stands for a ' &lt;strong&gt;host language&lt;/strong&gt;', and it determines the language used for the search. There are different versions of the &lt;code&gt;'hl'&lt;/code&gt; parameter you can pass to a Google Search. The two-letter version is for all languages supported by Google.&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;"hl=en"&lt;/code&gt; searches in English. There are also two-letter versions followed by a hyphen and two-letter or three-digit versions representing dialects. Examples of this kind are &lt;code&gt;"hl=en-gb"&lt;/code&gt; representing British English, or &lt;code&gt;"hl=es-419"&lt;/code&gt; representing Latin American Spanish.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1beddy7vo4vz5maaujba.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1beddy7vo4vz5maaujba.jpg" alt="hl" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Search with hl parameter&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://serpapi.com/search-api#api-parameters-localization-hl" rel="noopener noreferrer"&gt;Reference in SerpApi Documentation&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;gl&lt;/code&gt; parameter
&lt;/h2&gt;

&lt;p&gt;It represents ' &lt;strong&gt;geolocation&lt;/strong&gt;', which can be used to personalize search results based on the region. It is a two-letter country code. For example, &lt;code&gt;"gl=us"&lt;/code&gt; will serve results for the United States. It's recommended to be used with the 'location' parameter for more consistent country-specific filtering.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiwnmpkoz4dfqfjibjtdi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiwnmpkoz4dfqfjibjtdi.jpg" alt="gl" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Search with gl parameter&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://serpapi.com/search-api#api-parameters-localization-gl" rel="noopener noreferrer"&gt;Reference in SerpApi Documentation&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;lr&lt;/code&gt; parameter
&lt;/h2&gt;

&lt;p&gt;It stands for ' &lt;strong&gt;language restriction&lt;/strong&gt;', it's used to limit your search results to webpages in a specific language or languages. It is a two-letter language code preceded by the word lang and an underscore. Multiple languages can be passed using a bar symbol.&lt;/p&gt;

&lt;p&gt;For example &lt;code&gt;"lr=lang_en|lang_fr"&lt;/code&gt; will restrict the results to websites with only English and French languages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo1rr4spa3iduf2up9gdm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo1rr4spa3iduf2up9gdm.jpg" alt="lr" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Search with lr parameter&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://serpapi.com/search-api#api-parameters-localization-lr" rel="noopener noreferrer"&gt;Reference in SerpApi Documentation&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;cr&lt;/code&gt; parameter
&lt;/h2&gt;

&lt;p&gt;It represents ' &lt;strong&gt;country restriction&lt;/strong&gt;', it refines results based on preferred region. It is a two-letter uppercase country code preceded by the word country. Multiple countries can be passed using a bar symbol.&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;"cr=countryUS|countryFR"&lt;/code&gt; will restrict the results pages to the United States and France.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0j93vhxbm7nmafyivg5l.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0j93vhxbm7nmafyivg5l.jpg" alt="cr" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Search with lr parameter&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://serpapi.com/search-api#api-parameters-localization-cr" rel="noopener noreferrer"&gt;Reference in SerpApi Documentation&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;tbs&lt;/code&gt; parameter
&lt;/h2&gt;

&lt;p&gt;It stands for ' &lt;strong&gt;to be searched&lt;/strong&gt;', it can be used for various purposes (it's optional), for example, to filter results by a specific date or a date range (e.g., past week, past month).&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;"tbs=qdr:h"&lt;/code&gt; will serve only the results from the last hour.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkd54gccoikunmz9g709v.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkd54gccoikunmz9g709v.jpg" alt="tbs" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Search with tbs parameter&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://serpapi.com/search-api#api-parameters-advanced-filters-tbs" rel="noopener noreferrer"&gt;Reference in SerpApi Documentation&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;source&lt;/code&gt; parameter
&lt;/h2&gt;

&lt;p&gt;It &lt;strong&gt;indicates the source of your search&lt;/strong&gt; , such as the Google homepage or a referral from another website.&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;"source=hp"&lt;/code&gt; means that the page was accessed through the homepage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft1g9ov1amabphx8g8mi3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft1g9ov1amabphx8g8mi3.jpg" alt="source" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Search with search parameter&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;ei&lt;/code&gt; parameter
&lt;/h2&gt;

&lt;p&gt;It possibly stands for &lt;strong&gt;engine identifier&lt;/strong&gt; , a unique identifier assigned to each search, likely used for internal tracking by Google. Its decoded form consists of four numbers. The first two are a Unix timestamp and microseconds of that timestamp respectively. The last two are undisclosed and unknown.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb3jxwzuoqgajckm0gm14.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb3jxwzuoqgajckm0gm14.jpg" alt="ei" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Search with ei parameter&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;ved&lt;/code&gt; parameter
&lt;/h2&gt;

&lt;p&gt;It is used for internal tracking of links and elements. Apart from the link itself, the element index and type can be gathered by decoding the ved value.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fouaehaoi35mh93ni68hm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fouaehaoi35mh93ni68hm.jpg" alt="ved" width="799" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Search with ved parameter&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/serpapi/ved_decoder" rel="noopener noreferrer"&gt;Open Source Repository for Decoding the ved values&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;gs_lp&lt;/code&gt; parameter
&lt;/h2&gt;

&lt;p&gt;Not much is disclosed about this parameter. It contains the search query and search client.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx1rvnnhniv3905qj6hgt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx1rvnnhniv3905qj6hgt.jpg" alt="gs_lp" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Search with gs_lp parameter&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;iflsig&lt;/code&gt; parameter
&lt;/h2&gt;

&lt;p&gt;This parameter isn't disclosed. It is speculated to be about internal redirects. Other assumptions include relations to parsing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8rt95p05h00w19guf4sf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8rt95p05h00w19guf4sf.jpg" alt="iflsig" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Search with iflsig parameter&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;ibp&lt;/code&gt; parameter
&lt;/h2&gt;

&lt;p&gt;It is responsible for rendering elements differently than their usual format. For example, when used with the ludocid parameter (unique id for a Google Business listing) in a mobile view, &lt;code&gt;"ibp=gwp;0,7&amp;amp;ludocid=1663467585083384531"&lt;/code&gt;, the 'ibp' parameter can give full page views of the listing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa02xpswrz41ux6bylwc9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa02xpswrz41ux6bylwc9.jpg" alt="ibp" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Search with ibp parameter&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://serpapi.com/search-api#api-parameters-advanced-google-parameters-ibp" rel="noopener noreferrer"&gt;Reference in SerpApi Documentation&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;kgmid&lt;/code&gt; parameter
&lt;/h2&gt;

&lt;p&gt;The parameter is responsible for &lt;strong&gt;serving elements saved by Google including knowledge graph&lt;/strong&gt;. It can override the &lt;code&gt;'q'&lt;/code&gt; (query) parameter.&lt;/p&gt;

&lt;p&gt;For example &lt;code&gt;"kgmid=/m/07gyp7"&lt;/code&gt; will get results for McDonald's with a knowledge graph regardless of the query parameter. The parameter is likely acting as a cached version of the Google advanced search parameters.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx133h0zapm3ncty4gtdc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx133h0zapm3ncty4gtdc.jpg" alt="kgmid" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Search with kgmid parameter&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://serpapi.com/search-api#api-parameters-advanced-google-parameters-kgmid" rel="noopener noreferrer"&gt;Reference in SerpApi Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We write a detailed tutorial on how to find the Google Knowledge Graph ID (kgmid) for anything in the post below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/blog/how-to-find-google-knowledge-graph-id-kgmid/" rel="noopener noreferrer"&gt;How to find the Google Knowledge Graph ID (kgmid) for anything&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;si&lt;/code&gt; parameter
&lt;/h2&gt;

&lt;p&gt;It is used to serve knowledge graph tabs alongside other tasks (it's an optional parameter).&lt;/p&gt;

&lt;p&gt;For example, in the example below, the &lt;code&gt;'si'&lt;/code&gt; parameter is responsible for serving the Google search results with the 'Music Groups' tab of the knowledge graph for Jimi Hendrix.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv7mx9hylaxpgdm5gi507.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv7mx9hylaxpgdm5gi507.jpg" alt="si" width="800" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Search with si parameter&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://serpapi.com/search-api#api-parameters-advanced-google-parameters-si" rel="noopener noreferrer"&gt;Reference in SerpApi Documentation&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 For some searches, &lt;code&gt;'si'&lt;/code&gt; may override all other parameters except &lt;code&gt;'start'&lt;/code&gt;, and &lt;code&gt;'num'&lt;/code&gt; parameters.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;sxsrf&lt;/code&gt; parameter
&lt;/h2&gt;

&lt;p&gt;It is possibly an internal token for security. The 'sxsrf' consists of an encoded token probably for security purposes, and a unix timestamp.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft8plbw7i2jr0w2rsyqya.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft8plbw7i2jr0w2rsyqya.jpg" alt="sxsrf" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Search with sxsrf parameter&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;uule&lt;/code&gt; parameter
&lt;/h2&gt;

&lt;p&gt;It is used to specify a location for a search. The 'uule' parameter has two types. The first type is an encoded form of the canonical name of a place in &lt;a href="https://developers.google.com/google-ads/api/data/geotargets" rel="noopener noreferrer"&gt;Google Ads API Geo Targets&lt;/a&gt;. The second type is an encoded form of the GPS coordinates alongside other data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6nbc3m69pzdsc9zp3etd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6nbc3m69pzdsc9zp3etd.jpg" alt="uule" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Search with uule parameter&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://serpapi.com/search-api#api-parameters-geographic-location-uule" rel="noopener noreferrer"&gt;Reference in SerpApi Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We write more details about the different types of UULE in the post below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/blog/gps-targeted-local-serp/" rel="noopener noreferrer"&gt;Real World Example of GPS Targeted Local SERP&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;❗ The &lt;code&gt;'uule'&lt;/code&gt; and location parameters can't be used together.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;sclient&lt;/code&gt; parameter
&lt;/h2&gt;

&lt;p&gt;It stands for search client. For example &lt;code&gt;"sclient=gws-wiz"&lt;/code&gt; means Google Web Search Wizard is used for the search.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1vbmgp88t1v5iavpf5fq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1vbmgp88t1v5iavpf5fq.jpg" alt="sclient" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Search with sclient parameter&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;tbm&lt;/code&gt; parameter
&lt;/h2&gt;

&lt;p&gt;It stands for " &lt;strong&gt;to be matched&lt;/strong&gt;". This parameter is optional and it specifies the type of content that the user is searching for, allowing Google to tailor the search results accordingly.&lt;/p&gt;

&lt;p&gt;For instance, &lt;code&gt;"tbm=isch"&lt;/code&gt; indicates that the search is intended for image search, while &lt;code&gt;"tbm=nws"&lt;/code&gt; directs Google to prioritize results from Google News. By using this parameter, users can fine-tune their searches to precisely start finding pages, sites, or specific content types using Google's sophisticated algorithm.&lt;/p&gt;

&lt;p&gt;Additionally, users can specify whether they want to search within meta information, anchor text, or other elements through the appropriate parameters. This level of customization empowers users to efficiently navigate the vast expanse of information accessible through Google's search bar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3akbx0qa7n8fdvukhzne.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3akbx0qa7n8fdvukhzne.jpg" alt="tbm" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Search with tbm parameter&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://serpapi.com/search-api#api-parameters-search-type-tbm" rel="noopener noreferrer"&gt;Reference in SerpApi Documentation&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the &lt;code&gt;safe&lt;/code&gt; parameter to filter explicit results
&lt;/h2&gt;

&lt;p&gt;If your application is designed for general audiences, the safe parameter helps ensure family-friendly results.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;safe=active&lt;/code&gt; — filters out explicit content.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;safe=off&lt;/code&gt; — shows all results without filtering.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is particularly helpful for educational or public-facing dashboards using SerpApi.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpsgv7nt9haia5zuis6z3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpsgv7nt9haia5zuis6z3.png" alt="Screenshot 2025-11-03 at 11.51.19 AM.png" width="800" height="544"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Search with safe parameter&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimize for freshness with the &lt;code&gt;filter&lt;/code&gt; and &lt;code&gt;tbs&lt;/code&gt; combo
&lt;/h2&gt;

&lt;p&gt;While &lt;code&gt;tbs=qdr:h&lt;/code&gt; limits results to the last hour, pairing it with &lt;code&gt;filter=0&lt;/code&gt; ensures that similar pages are not clustered together—revealing the most recent, diverse results.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2fe8e2c8h4wc5my4pkoj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2fe8e2c8h4wc5my4pkoj.png" alt="Screenshot 2025-11-03 at 12.03.47 PM.png" width="800" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Search with filter and tbs combination&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This combination is perfect for trend monitoring or social sentiment analysis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I would like to thank the reader for their attention. I hope this writing could shed some light on how Google search parameters work. For more up-to-date information about web scraping, SERP data, and more related topics, you may visit the &lt;a href="https://serpapi.com/blog" rel="noopener noreferrer"&gt;SerpApi Blog&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>DataForSEO vs. SerpApi</title>
      <dc:creator>Noraina Nordin</dc:creator>
      <pubDate>Sun, 02 Aug 2026 09:30:23 +0000</pubDate>
      <link>https://dev.to/serpapi/dataforseo-vs-serpapi-2bif</link>
      <guid>https://dev.to/serpapi/dataforseo-vs-serpapi-2bif</guid>
      <description>&lt;p&gt;If you're comparing SEO platforms to choose where your search data comes from, whether it's for rank tracking, dashboards, or a Google search ranking API integrated into your product, both &lt;strong&gt;DataForSEO&lt;/strong&gt; and &lt;strong&gt;SerpApi&lt;/strong&gt; are strong options. At a quick glance, they seem similar, but they have important differences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Live Search Data vs SEO Platform
&lt;/h2&gt;

&lt;p&gt;Despite the overlap on Google SERP data, &lt;strong&gt;SerpApi and DataForSEO are built around two different priorities.&lt;/strong&gt; Which option fits best depends more on your priorities than on any single line item. Price is part of it, and we'll be straight about it further down.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DataForSEO&lt;/strong&gt; is a broad, pay-as-you-go SEO data platform. Beyond SERPs, it provides backlinks, keywords, on-page, domain analytics, and more, all billed per request from a prepaid balance. Its strongest selling point is low-cost data at scale. It's the raw layer that many SEO dashboards are built on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SerpApi&lt;/strong&gt; is a real-time web search API. You make a call, and it returns structured JSON of what a search engine shows for that query. The results include AI overviews, organic results, ads, featured snippets, People Also Ask, the local pack, Shopping, and more than &lt;a href="https://serpapi.com/search-engine-apis" rel="noopener noreferrer"&gt;100 SERP feature types&lt;/a&gt;. Its best features are speed, coverage, and developer experience.&lt;/p&gt;

&lt;p&gt;DataForSEO is optimized to be the most cost-effective way to store search data. SerpApi is optimized to be the fastest, most complete way to query it in real time. Picking between them is really about which of those two jobs is yours.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgt3u7d6pj05qawr22kn1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgt3u7d6pj05qawr22kn1.png" alt="SerpApi vs DataForSEO illustration" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;SerpApi vs DataForSEO illustration&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Freshness
&lt;/h2&gt;

&lt;p&gt;The most consequential difference between SerpApi and DataForSEO is how the results reach you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr8s48d1e648ja30gwfyt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr8s48d1e648ja30gwfyt.png" alt="Search Result Timeline Diagram" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Search Result Timeline Diagram&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;DataForSEO's default model is a queue. You submit a task, wait, and retrieve the result later. On the Standard Queue, turnaround is typically around 5 minutes (a Priority Queue cuts it to about 1 minute, and a synchronous Live Mode runs at a higher rate). For batch rank tracking that runs overnight, where five minutes is insignificant, the queue is perfectly suited.&lt;/p&gt;

&lt;p&gt;But if your application is &lt;strong&gt;customer-facing or agent-driven,&lt;/strong&gt; where a user types a query and waits, or an LLM that needs search results mid-response, five minutes is a non-starter, and even one minute is. For those workloads, the queue isn't an option. You're choosing between DataForSEO's Live Mode and SerpApi. And "live" doesn't mean equally fast: in &lt;a href="https://serpapi.com/blog/who-has-the-fastest-google-search-api/" rel="noopener noreferrer"&gt;our own reproducible benchmark&lt;/a&gt;, SerpApi averaged 0.73 seconds per query, compared to 3.57 seconds for DataForSEO's fastest option, and the worst-case gap was wider still, with a p99 of 1.45 seconds versus 13.31 seconds. DataForSEO's own comparison points in the same direction, measuring its live mode at around 6 seconds. For an AI agent making several search calls in a single chain, that difference compounds quickly.&lt;/p&gt;

&lt;p&gt;SerpApi is synchronous by default. Every call returns live results in roughly a second, and with &lt;a href="https://serpapi.com/ludicrous-speed" rel="noopener noreferrer"&gt;Ludicrous Speed&lt;/a&gt; / &lt;a href="https://serpapi.com/ludicrous-speed-max" rel="noopener noreferrer"&gt;Ludicrous Speed Max&lt;/a&gt; you can push median response times well below that. We benchmarked response times across providers in &lt;a href="https://serpapi.com/blog/who-has-the-fastest-google-search-api/" rel="noopener noreferrer"&gt;who has the fastest Google Search API&lt;/a&gt;. There’s no queue to manage, no task-polling loop to construct. The optional &lt;a href="https://serpapi.com/search-archive-api" rel="noopener noreferrer"&gt;Search Archive API&lt;/a&gt; is available if you want to re-fetch past searches; it's for convenience, not a required step. For real-time workloads, fast processing determines whether you can deliver the feature or not.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do you actually need real-time data?
&lt;/h3&gt;

&lt;p&gt;It's worth meeting the strongest version of the other side head-on because DataForSEO-leaning comparisons have highlighted that most SEO work is batch-based, so you're paying a premium for speed you'll never use. For pure scheduled SEO, such as overnight rank tracking or weekly content-gap reports, that's fair. If nothing is waiting on the result, the queue is the right call.&lt;/p&gt;

&lt;p&gt;The argument breaks down on two points. First, the number of applications requiring real-time results is growing rapidly. &lt;a href="https://www.gartner.com/en/newsroom/press-releases/2025-08-26-gartner-predicts-40-percent-of-enterprise-apps-will-feature-task-specific-ai-agents-by-2026-up-from-less-than-5-percent-in-2025" rel="noopener noreferrer"&gt;Gartner estimates&lt;/a&gt; that 40% of enterprise applications will have task-specific AI agents integrated by the end of 2026, up from under 5% in 2025. Agents, RAG pipelines, in-product search, and live AI-Overview / GEO monitoring all need a result in a single request. The moment a human or an agent is waiting, the comparison becomes Live Mode at ~ $2.00/1K versus SerpApi. That's a much smaller gap than the headline numbers suggest, and part of it buys back real engineering time. With a synchronous API, there's no poll-and-retrieve layer to build, debug, and maintain.&lt;/p&gt;

&lt;p&gt;Second, when DataForSEO-leaning comparisons concede that the queue can't serve real-time use cases, the workaround they tend to suggest is to pair it with Google's Custom Search JSON API for live queries. That pairing doesn't hold up. The Custom Search API is capped at low daily volume, returns a restricted custom-search index rather than the live public SERP, and omits most SERP features and verticals. Offering it as the real-time answer mostly confirms that it's the queue being defended, not your latency needs being met.&lt;/p&gt;

&lt;p&gt;The real question is simpler than "batch or real-time": &lt;strong&gt;does anything wait on the result?&lt;/strong&gt; If so, compare SerpApi against Live Mode, and count the poll-and-retrieve layer you won't have to build.&lt;/p&gt;

&lt;p&gt;Let's take a look at two scenarios that show how this plays out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For the SaaS team,&lt;/strong&gt; the queue is fine for weekly rank reports that can be processed in batches. But AI Overview citations aren't. They appear, vanish, and swap sources far faster than bluelinks move, and being cited for the "&lt;em&gt;best &amp;lt;your category&amp;gt; software&lt;/em&gt;" is the new position #1. Monitoring on day-old snapshots means learning you lost the citation days after a competitor's page replaced yours. Checking live means alerting the content team while the cause is still identifiable and answerable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For an e-commerce team&lt;/strong&gt; , the gap is larger because automation acts directly on the data. Google Shopping positions are reshuffled in response to competitor price changes, sometimes hourly. So a repricing engine or Minimum Advertised Price (MAP) violation monitor running on 5-minute-old queue data can act on prices that no longer exist. A human reading a stale report adds judgment before acting. An automated repricer doesn't get that chance.&lt;/p&gt;

&lt;h2&gt;
  
  
  DataForSEO pricing vs. SerpApi pricing
&lt;/h2&gt;

&lt;p&gt;If you're sizing up SerpApi as a DataForSEO alternative, the prices only make sense once you know which speed tier you'd actually use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DataForSEO is pure pay-as-you-go.&lt;/strong&gt; No monthly subscription. You prepay a balance (a $50 minimum deposit, with a $1 free trial credit to test first) and draw it down per request. For the SERP API, the same query costs a different amount depending on how fast you need it:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;DataForSEO SERP API tier&lt;/th&gt;
&lt;th&gt;Price per 1,000 SERPs&lt;/th&gt;
&lt;th&gt;Delivery&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Standard Queue&lt;/td&gt;
&lt;td&gt;~ $0.60&lt;/td&gt;
&lt;td&gt;Queued, ~ 5 min turnaround&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Priority Queue&lt;/td&gt;
&lt;td&gt;~ $1.20&lt;/td&gt;
&lt;td&gt;Queued, ~ 1 min turnaround&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Live Mode&lt;/td&gt;
&lt;td&gt;~ $2.00&lt;/td&gt;
&lt;td&gt;Real-time, synchronous&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;(Base price covers the first 10 results. Since Google removed its &lt;code&gt;num=100&lt;/code&gt; parameter in late 2025, deeper result pages are billed per additional page budget for that if you paginate.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SerpApi is subscription-based&lt;/strong&gt; , priced on a monthly bucket of successful searches:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SerpApi Plan&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Searches/Month&lt;/th&gt;
&lt;th&gt;Price per 1,000 Searches&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Starter&lt;/td&gt;
&lt;td&gt;$25&lt;/td&gt;
&lt;td&gt;1,000&lt;/td&gt;
&lt;td&gt;$25.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Developer&lt;/td&gt;
&lt;td&gt;$75&lt;/td&gt;
&lt;td&gt;5,000&lt;/td&gt;
&lt;td&gt;$15.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Production&lt;/td&gt;
&lt;td&gt;$150&lt;/td&gt;
&lt;td&gt;15,000&lt;/td&gt;
&lt;td&gt;$10.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Big Data&lt;/td&gt;
&lt;td&gt;$275&lt;/td&gt;
&lt;td&gt;30,000&lt;/td&gt;
&lt;td&gt;~ $9.17&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Plans scale up to 1,000,000+ searches/month, and an Enterprise tier offers reserved and on-demand pricing for high volume. Only fully successful searches count. While cached, errored, blocked, and CAPTCHA requests are free, unused searches don't roll over.&lt;/p&gt;

&lt;p&gt;Look at those two tables side by side, and the takeaway is simple: at the same volume, DataForSEO's price is lower, and it is the better fit for latency-tolerant batch work. SerpApi is the premium option. That's what you get for the &lt;strong&gt;real-time speed, one-call integration, wider search-surface coverage, human support, and legal cover&lt;/strong&gt; , which is what the rest of this comparison walks through.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ease of Integration
&lt;/h2&gt;

&lt;p&gt;This one rarely makes the spec sheet but shows up on day one of building.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;SerpApi&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;With one API key, you get synchronous request and structured JSON back. Plus, &lt;a href="https://serpapi.com/integrations" rel="noopener noreferrer"&gt;official libraries&lt;/a&gt; are available for Python, Ruby, JavaScript, Go, PHP, Java, .NET, Rust, and more, plus an &lt;a href="https://serpapi.com/integrations/mcp" rel="noopener noreferrer"&gt;MCP integration&lt;/a&gt; for AI assistants.&lt;/p&gt;

&lt;p&gt;For quick testing, the &lt;a href="https://serpapi.com/playground" rel="noopener noreferrer"&gt;playground&lt;/a&gt; lets you run a search query with zero code, and one thing I really like about it is that it shows a &lt;strong&gt;visual preview of the SERP&lt;/strong&gt; on the same page you'd see in a regular browser, side by side with the JSON response. When I'm tracing where a field comes from ("which box on the page is this &lt;code&gt;organic_results&lt;/code&gt; object?"), I can see the element and its parsed data side by side. DataForSEO's output is JSON only, so mapping a field back to what actually appeared on the page requires opening a browser and reconstructing the SERP yourself. It sounds small. But it stops being small the first time you debug why a value isn't where you expected it to be.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2h0zvlgc6akd2fyoaruc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2h0zvlgc6akd2fyoaruc.png" alt="SerpApi Google Search Playground" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;SerpApi Google Search Playground&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  DataForSEO
&lt;/h3&gt;

&lt;p&gt;The authentication uses a login-plus-API-password credential pair, and the queued endpoints follow a task-based pattern. You POST a task, then either poll for results or wait for a callback to retrieve them. It's well-documented and fine once built, but it really involves more work than a single synchronous GET. (DataForSEO also ships an MCP server, so for AI-assistant workflows, both options exist.)&lt;/p&gt;

&lt;p&gt;For solo developers or small teams trying to ship faster, integration friction creates real costs, even if it doesn't appear on the invoice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coverage
&lt;/h2&gt;

&lt;p&gt;"Which one covers more?" depends on more of what.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On SERP engines and Google verticals, SerpApi is wider.&lt;/strong&gt; DataForSEO's SERP API spans roughly 8 engines (Google, Bing, Yahoo, Baidu, Yandex, Naver, Seznam, YouTube). SerpApi &lt;a href="https://serpapi.com/search-engine-apis" rel="noopener noreferrer"&gt;supports 100+ APIs&lt;/a&gt; across Google Search, Maps, Shopping, Scholar, Trends, Flights, Hotels, Lens, Jobs, News, Patents, and more, as well as Bing, Baidu, Yandex, Naver, DuckDuckGo, Amazon, eBay, Walmart, YouTube, Yelp, Tripadvisor, and others. If your roadmap touches multiple search surfaces, that range matters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In terms of SEO data types, DataForSEO offers a broader range.&lt;/strong&gt; Backlinks, a historical keyword database, on-page audits, domain analytics, and its API list go well beyond SERPs. SerpApi doesn't support these features because its main focus is on the web search API rather than an SEO data suite. If you need backlink graphs or a keyword-volume database alongside SERPs, DataForSEO consolidates that in one account.&lt;/p&gt;

&lt;p&gt;In short, SerpApi provides the depth and freshness of live search results parsing across many search engines, while DataForSEO provides a wider range of raw SEO datasets in one place.&lt;/p&gt;

&lt;h3&gt;
  
  
  SerpApi Endpoints That Affect SEO Decisions
&lt;/h3&gt;

&lt;p&gt;Several endpoints return the exact signals that SEO teams call on. A few worth knowing, covered by both SerpApi and DataForSEO:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://serpapi.com/pixel-position" rel="noopener noreferrer"&gt;&lt;strong&gt;Pixel Position&lt;/strong&gt;&lt;/a&gt;: the real-browser X/Y coordinates of each result. Nominal "rank #1" can sit well below the fold once ads, an AI Overview, and a featured snippet stack above it. Pixel Position reports actual above-the-fold visibility, per device, so you can tell which rankings are worth defending and which are wins only on paper.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/google-ai-overview-api" rel="noopener noreferrer"&gt;&lt;strong&gt;Google AI Overview&lt;/strong&gt;&lt;/a&gt; and &lt;a href="https://serpapi.com/google-ai-mode-api" rel="noopener noreferrer"&gt;&lt;strong&gt;AI Mode&lt;/strong&gt;&lt;/a&gt;: whether your content is cited in Google's AI answers, and which domains are. This is the core AEO/GEO decision of 2026: track AI visibility the way you track bluelink rank. We've written about what AI Overviews change for rank tracking in depth.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/rank-tracking-in-the-age-of-ai-overviews-whats-changed/" rel="noopener noreferrer"&gt;Rank Tracking in the Age of AI Overviews: What’s Changed&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/google-related-questions-api" rel="noopener noreferrer"&gt;&lt;strong&gt;Related Questions&lt;/strong&gt;&lt;/a&gt; (People Also Ask): the questions Google attaches to a query, which map straight to content gaps, FAQ blocks, and subheadings worth writing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/google-autocomplete-api" rel="noopener noreferrer"&gt;&lt;strong&gt;Autocomplete&lt;/strong&gt;&lt;/a&gt;: the long-tail variations real users actually type, for keyword discovery grounded in live suggestions rather than a static database.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/google-trends-api" rel="noopener noreferrer"&gt;&lt;strong&gt;Google Trends&lt;/strong&gt;&lt;/a&gt;: demand direction and seasonality, so you prioritize topics that are rising rather than fading.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/google-local-api" rel="noopener noreferrer"&gt;&lt;strong&gt;Google Local&lt;/strong&gt;&lt;/a&gt;: local-pack results by location, for tracking visibility, where the map results, not the organic ones, win the click.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some endpoints currently lack DataForSEO equivalents, such as the &lt;a href="https://serpapi.com/google-forums-api" rel="noopener noreferrer"&gt;Google Forums API&lt;/a&gt; (covering the "Discussions and forums" SERP block where Reddit visibility appears), &lt;a href="https://serpapi.com/google-short-videos-api" rel="noopener noreferrer"&gt;Google Short Videos&lt;/a&gt;, and Bing's vertical results beyond organic &lt;a href="https://serpapi.com/bing-copilot-api" rel="noopener noreferrer"&gt;Copilot&lt;/a&gt;, Images, Maps, News, and Shopping, where DataForSEO only covers organic Bing results.&lt;/p&gt;

&lt;p&gt;The key difference is that SerpApi returns the results in a single, real-time call, parsing them in a structured JSON format. This introduces the same real-time versus queued trade-off mentioned earlier, but specifically applied to the signals that inform SEO decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature Comparison
&lt;/h2&gt;

&lt;p&gt;Here's the full picture in one place with everything we covered so far, plus a few dimensions that haven't come up yet:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;SerpApi&lt;/th&gt;
&lt;th&gt;DataForSEO&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Core model&lt;/td&gt;
&lt;td&gt;Real-time search API (subscription)&lt;/td&gt;
&lt;td&gt;SEO data platform (pay-as-you-go)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default delivery&lt;/td&gt;
&lt;td&gt;Synchronous, ~1 sec&lt;/td&gt;
&lt;td&gt;Queued (Standard/Priority); Live mode synchronous&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pricing&lt;/td&gt;
&lt;td&gt;From $25/mo (1K searches); free tier 250/mo&lt;/td&gt;
&lt;td&gt;From $0.60/1K (queued) to ~$2.00/1K (live); $50 min deposit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SERP engines&lt;/td&gt;
&lt;td&gt;100+ APIs incl. many Google verticals&lt;/td&gt;
&lt;td&gt;~8 SERP engines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Other SEO data&lt;/td&gt;
&lt;td&gt;SERP-focused (no backlinks/keyword DB)&lt;/td&gt;
&lt;td&gt;Backlinks, keyword DB, on-page, domain analytics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SERP feature parsing&lt;/td&gt;
&lt;td&gt;100+ feature types as structured objects&lt;/td&gt;
&lt;td&gt;Rich features via "Advanced" result type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Integration&lt;/td&gt;
&lt;td&gt;Single API key, sync request&lt;/td&gt;
&lt;td&gt;Login + API password, task-based queue workflow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Legal&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://serpapi.com/us-legal-shield" rel="noopener noreferrer"&gt;U.S. Legal Shield&lt;/a&gt; assumes scraping liability for you&lt;/td&gt;
&lt;td&gt;No Legal Shield&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Transparency&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://serpapi.com/status" rel="noopener noreferrer"&gt;Public status page&lt;/a&gt; + &lt;a href="https://github.com/serpapi/public-roadmap" rel="noopener noreferrer"&gt;public roadmap&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;Status page; private roadmap&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best fit&lt;/td&gt;
&lt;td&gt;Real-time apps, AI agents, multi-engine SEO tools&lt;/td&gt;
&lt;td&gt;High-volume batch data, cost-sensitive pipelines, full SEO suites&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Main differentiators
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Legal posture.&lt;/strong&gt; These aren't the same promise. DataForSEO states that scraping publicly available SERP data isn't a CFAA/DMCA violation. i.e., &lt;em&gt;we believe this is legal&lt;/em&gt;. SerpApi's &lt;a href="https://serpapi.com/us-legal-shield" rel="noopener noreferrer"&gt;U.S. Legal Shield&lt;/a&gt; goes further: on recurring paid plans, SerpApi contractually assumes liability for scraping and parsing on your behalf (short of genuinely illegal use). If legal risk transfer is something your company needs in writing, that's a SerpApi-specific feature, not a line item in the price.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Transparency.&lt;/strong&gt; SerpApi publishes a &lt;a href="https://serpapi.com/status" rel="noopener noreferrer"&gt;public status page&lt;/a&gt; with 30-day average response times filterable by engine, and a &lt;a href="https://github.com/serpapi/public-roadmap" rel="noopener noreferrer"&gt;public roadmap&lt;/a&gt; where anyone can see bugs and file feature requests consistent with the company's "painful honesty" value. For the infrastructure you're betting a product on, being able to inspect reliability before you commit is worth weighing.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to choose each
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Choose DataForSEO when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unit cost is your binding constraint, and you're operating at high volume.&lt;/li&gt;
&lt;li&gt;Your workload is batch and latency-tolerant, such as overnight rank tracking and bulk SERP snapshots.&lt;/li&gt;
&lt;li&gt;Your usage is spiky, and you'd rather pay only for what you consume than fit into a monthly bucket.&lt;/li&gt;
&lt;li&gt;You need backlinks, a keywords database, or on-page data in the same account as your SERPs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Choose SerpApi when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your app is customer-facing, or agent-driven, and results need to be real-time.&lt;/li&gt;
&lt;li&gt;You want the simplest possible integration: one key, one synchronous call.&lt;/li&gt;
&lt;li&gt;You need a broad engine and Google-vertical coverage with high-fidelity SERP-feature parsing.&lt;/li&gt;
&lt;li&gt;Legal liability transfer, public transparency, and responsive support are part of the decision.&lt;/li&gt;
&lt;li&gt;You'd rather not build and maintain a task-queue retrieval layer.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Is DataForSEO actually cheaper than SerpApi?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;On headline per-query price, yes, especially on the Standard Queue (~$0.60/1K vs. SerpApi's $25/1K entry rate). The gap narrows when you need real-time results, since you'd use DataForSEO's Live Mode (~$2.00/1K). And it narrows further once you price in integration time, latency requirements, and whether you need legal cover. Cheapest-per-query isn't the same as cheapest-for-your-project.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Can DataForSEO do real-time?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Yes, via Live Mode, which is synchronous but priced higher than its queued tiers. SerpApi is real-time by default across all plans.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Which has more search engines?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;SerpApi, by a wide margin on SERP such as Google, Bing, DuckDuckGo, Baidu, Yandex, Naver, Yahoo, YouTube, Yelp, Tripadvisor, Amazon, eBay, Walmart and more (&lt;a href="https://serpapi.com/search-engine-apis" rel="noopener noreferrer"&gt;100+ APIs&lt;/a&gt;). DataForSEO covers more SEO &lt;em&gt;data types&lt;/em&gt; (backlinks, keyword DB, on-page) but fewer SERP engines.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Can I use both?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Plenty of teams do. DataForSEO for cheap, high-volume batch collection, SerpApi for the real-time and multi-engine paths. They're not mutually exclusive.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Which is the best SERP tracking tool, SerpApi or DataForSEO?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Neither is a turnkey rank tracker. Both are API layers you'd build a SERP-tracking tool on top of. For tracking that runs on a schedule, DataForSEO's queue is cost-efficient, but for tracking that updates on demand or inside a user-facing dashboard, SerpApi's real-time responses are the better fit. Pick the data layer that matches how your tool refreshes.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Is SerpApi a good DataForSEO alternative?&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;If your use case is real-time or spans multiple search engines, yes — SerpApi covers the SERP side with lower latency and simpler integration. But if you also rely on backlinks, a keyword database, or on-page audits, SerpApi won't replace those parts of DataForSEO. In that case, the answer to "what's the best DataForSEO alternative" is often SerpApi plus a dedicated tool for the rest, rather than a single swap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related comparisons
&lt;/h2&gt;

&lt;p&gt;Weighing SerpApi against other providers? We've broken down the trade-offs in each of these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/blog/serpapi-vs-brave-search-api/" rel="noopener noreferrer"&gt;SerpApi vs. Brave Search API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/blog/serpapi-vs-exa-ai/" rel="noopener noreferrer"&gt;SerpApi vs. Exa AI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://serpapi.com/blog/serpapi-vs-firecrawl/" rel="noopener noreferrer"&gt;SerpApi vs. Firecrawl&lt;/a&gt;: search intelligence vs. website content&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/blog/compare-serpapi-with-the-alternatives-serper-and-searchapi/" rel="noopener noreferrer"&gt;SerpApi vs. Serper vs. ValueSERP vs. SearchApi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/blog/who-has-the-fastest-google-search-api/" rel="noopener noreferrer"&gt;Who has the fastest Google Search API?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The bottom line
&lt;/h2&gt;

&lt;p&gt;DataForSEO and SerpApi appear to be competitors because both provide Google SERP data. But you're choosing between a pay-as-you-go data warehouse and a real-time search API, and the right answer falls out of one question: &lt;strong&gt;is your bottleneck unit cost, or latency, coverage, integration speed, or legal cover?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're warehousing search data at scale on a tight budget and can tolerate a queue, DataForSEO's prices are definitely lower. If you're building something where results need to arrive now, such as an AI agent, a customer-facing product, a multi-engine SEO tool, and you'd rather ship than build retrieval plumbing, that's exactly what SerpApi is for.&lt;/p&gt;

&lt;p&gt;The good news: you don't have to take anyone's word for the trade-offs. SerpApi's &lt;a href="https://serpapi.com/status" rel="noopener noreferrer"&gt;status page&lt;/a&gt; and &lt;a href="https://github.com/serpapi/public-roadmap" rel="noopener noreferrer"&gt;roadmap&lt;/a&gt; are public, and the &lt;a href="https://serpapi.com/users/sign_up?plan=free" rel="noopener noreferrer"&gt;free plan&lt;/a&gt; includes 250 searches per month to test real responses against your own queries.&lt;/p&gt;

&lt;p&gt;Try a query in the &lt;a href="https://serpapi.com/playground" rel="noopener noreferrer"&gt;playground&lt;/a&gt; and compare the JSON for yourself! If you have questions, reach us at &lt;a href="mailto:contact@serpapi.com"&gt;contact@serpapi.com&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Why is Ruby on Rails a great fit for AI agents</title>
      <dc:creator>Josef Strzibny</dc:creator>
      <pubDate>Sat, 01 Aug 2026 09:24:07 +0000</pubDate>
      <link>https://dev.to/serpapi/why-is-ruby-on-rails-a-great-fit-for-ai-agents-39e4</link>
      <guid>https://dev.to/serpapi/why-is-ruby-on-rails-a-great-fit-for-ai-agents-39e4</guid>
      <description>&lt;p&gt;What makes a programming framework good for autonomous AI agents? It's how well the language and APIs communicates intent within the tight constraints that LLMs operate under. Agents need to read code, understand it, and generate more of it, all within a finite context window.&lt;/p&gt;

&lt;p&gt;That means three things matter most: &lt;strong&gt;token efficiency&lt;/strong&gt; (how much meaning fits in how few tokens), &lt;strong&gt;predictability&lt;/strong&gt; (how consistently code is structured so the model doesn't have to guess), and &lt;strong&gt;ecosystem ergonomics&lt;/strong&gt; (how pleasant and productive the tooling is for iterative agent workflows).&lt;/p&gt;

&lt;p&gt;Ruby on Rails happens to excel at all three.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1on44iyiomou9dhpquvm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1on44iyiomou9dhpquvm.png" alt="Ruby on Rails logo" width="500" height="189"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Ruby on Rails logo&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What are AI agents?
&lt;/h2&gt;

&lt;p&gt;Traditional AI usage like running a single ChatGPT prompt is mostly linear and reactive. You ask a question and receive an answer. An autonomous agent is dynamic by contrast. It can break a task into steps, follow them one by one, recover from errors, and adjust their behavior based on new information.&lt;/p&gt;

&lt;p&gt;Agents are processes with access to tools and memory to orchestrate complex work. Tools let agents do things beyond the usual text APIs like running code or searching the web. Memory allows agensts to keep track of context across individual steps or even across sessions. Control logic defines how they decide what to do next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Token efficiency for both humans and robots
&lt;/h2&gt;

&lt;p&gt;When it comes to AI efficiency, most will bring up tokens. But what are tokens anyway? When it comes to large language models (LLMs), &lt;strong&gt;tokens&lt;/strong&gt; are the basic units of text that model either reads or generates. They are processable text chunks that don't always map to words but which these models understand.&lt;/p&gt;

&lt;p&gt;A token can be a whole word, part of a word, punctuation, or special characters. A word &lt;em&gt;unbelievable&lt;/em&gt; might be split into &lt;em&gt;un&lt;/em&gt;, &lt;em&gt;believ&lt;/em&gt;, and &lt;em&gt;able&lt;/em&gt;. Different models rely on different tokenization rules, so these chunks are not always the same. The process of turning raw text into these chunks is called &lt;strong&gt;tokenization&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Context windows
&lt;/h3&gt;

&lt;p&gt;LLMs currently cannot process unlimited amount of text. The amount of data models can process is limited by computer memory which significantly increases with bigger &lt;strong&gt;context length&lt;/strong&gt;. We call the maximum length a model can work with at a given time a &lt;strong&gt;context window&lt;/strong&gt; and we measure it in tokens.&lt;/p&gt;

&lt;p&gt;This memory constrain includes the entire prompt, system instructions, conversation history, and the model's response. Less tokens as input enables longer answers and vice versa. When it comes to programming, the usage compounds between source files being read, changes being applied, and diffs being reviewed.&lt;/p&gt;

&lt;p&gt;Token windows significantly increased from the GPT-3.5 era of 4096 tokens and are now approching numbers higher than 1 million with models like Opus 4.6 and Sonnet 4.6. But even today the efficiency factor is significant when it comes to entire codebases. We are still spending energy, prolonging response times, and increasing cost.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ruby token efficiency
&lt;/h3&gt;

&lt;p&gt;Different programming languages means different token efficiency and context windows. This is where Ruby stands out. Martin Alderson, a co-founder of CatchMetrics, made a bit of a fuss lately with a post titled &lt;a href="https://martinalderson.com/posts/which-programming-languages-are-most-token-efficient/" rel="noopener noreferrer"&gt;Which programming languages are most token-efficient?&lt;/a&gt;. You might not know Martin, but his writing was previously praised by OpenAI co-founder Andrej Karpathy and his posts put him to top 100 most highest-ranking personal blogs on Hacker News for 2025.&lt;/p&gt;

&lt;p&gt;In his post, Alderson looks at tasks from the RosettaCode project that have implementation across all 19 most popular mainstream languages. He then ran them through the GPT-4 tokenizer to get the number of tokens required for the solution. The results showed up to &lt;strong&gt;2.6x gap&lt;/strong&gt; between the most efficient and least efficient languages from the list. That’s pretty significant difference as it's the result between one to almost three files in the context window. Have a look yourself:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1v10361qn2gtfybou38f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1v10361qn2gtfybou38f.png" alt="Martin Alderson's graph of most token-efficient languages" width="799" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Martin Alderson's graph of most token-efficient languages&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The updated post also features a mention of the J language which could get efficiency around the half of Closure which dominates the graph. Looks like array languages can be extremely token-efficient. Ruby isn't first on this list, but it is number one when only the major languages are considered.&lt;/p&gt;

&lt;p&gt;As the author of Rails, &lt;strong&gt;David Heinemeier Hansson&lt;/strong&gt; (DHH), has said many times &lt;em&gt;"Rails wouldn't exist without Ruby."&lt;/em&gt; Ruby was always putting the human experience of writing and reading above other metrics. No, not just the reading part like many others. Writing too. And it's interesting to realize that coming close to English language isn't just helpful for people, but also just as effective for AI.&lt;/p&gt;

&lt;p&gt;Language models got increasingly better in working with larger context windows over time, but the numbers of exchanged tokens still play a vital role in their practicality. More tokens means smaller available context, slower responses, and higher cost to run. As DHH &lt;a href="https://x.com/dhh/status/2013611188651794611" rel="noopener noreferrer"&gt;puts it&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The answer is (of course) agentic workflows. If you've used coding agents for any length of time, you'll quickly reach a point where you hit the dreaded 'compaction' stage. Compaction is the process most agents use when they reach the limit of the context window. It condenses earlier parts of the conversation - preserving recent context and key artifacts but losing a lot of the detail from earlier in the session.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Rails token efficiency
&lt;/h3&gt;

&lt;p&gt;Of course, Rails is more than Ruby, and lots of people will point out that the framework is large with lots of project generated files and other ceremony. There are not wrong, but is that a problem? Well, a software engineer and researcher Felipe Maciel Ramos Vieira tried to answer this question in his comparative view called &lt;a href="https://felipemrvieira.github.io/SyntaxTax/dashboard/" rel="noopener noreferrer"&gt;SyntaxTax&lt;/a&gt; that prioritizes the most context-efficient web stacks&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwjuo5yp5gkgi6p3n3rap.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwjuo5yp5gkgi6p3n3rap.png" alt="SyntaxTax report of popular web frameworks" width="800" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;SyntaxTax report of popular web frameworks&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Felipe's report implement the same API features in different stacks and compare how many tokens the handwritten code consumes. The Rails framework won at lowest handwritten costs and it was second as lowest total cost. When we talk about big opinionated frameworks it was also first in total efficiency #1&lt;br&gt;&lt;br&gt;
primary handwritten efficiency.&lt;/p&gt;

&lt;p&gt;While neither report is detailed and comprehensive enough to be considered scientific there are definitely indicators that being compact, terse, and expressive might as well mean token efficient.&lt;/p&gt;
&lt;h2&gt;
  
  
  Less ambiguity for the model
&lt;/h2&gt;

&lt;p&gt;Ruby's brevity is a good start but can mean very little without the generated tokens being correct. Modern LLMs can write valid code in almost any language. Agents don't fail at syntax, but they may struggle with ambiguity. They have harder time with architectural decisions. They must ask questions like &lt;em&gt;Where should this logic go?&lt;/em&gt;, &lt;em&gt;What pattern should I follow?&lt;/em&gt;, and &lt;em&gt;How does this connect to the rest of the system?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Very flexible frameworks leave these questions wide open, and every unanswered question is a chance for the agent to do guess work. Not in Rails. These questions tend to be already answered at the start because of the Rails' &lt;em&gt;Convention over Configuration&lt;/em&gt; approach to building applications. An approach that had already lifted a lot of weight from people teams finds its new value in agentic workflows.&lt;/p&gt;
&lt;h3&gt;
  
  
  Convention over Configuration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Rails conventions&lt;/strong&gt; act as implicit instructions. If there's a &lt;code&gt;resource :posts&lt;/code&gt; route, there's a &lt;code&gt;PostsController&lt;/code&gt; controller with CRUD action. If there's a &lt;code&gt;PostsController&lt;/code&gt;, there is likely a &lt;code&gt;Post&lt;/code&gt; model with user business logic and persistance conveniently provided by Active Record. If there's a &lt;code&gt;has_many&lt;/code&gt; relationship, there is a foreign key of a certain name.&lt;/p&gt;

&lt;p&gt;Naming things, structure of files, configuration (or lack of). These are building stones that an agent can rely on. Just a simple thing as agreeing on singular vs plural naming saves a lot of overhead. It also makes things consistent. Consistency was good for humans and is equally helpful now with robots.&lt;/p&gt;
&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Convention over Configuration&lt;/strong&gt; means less need for writing configuration files, although default configuration files exist in Rails. And funnily enough, they also follow &lt;em&gt;Convention over Configuration&lt;/em&gt; by specifying predefined environment like &lt;em&gt;development&lt;/em&gt; or &lt;em&gt;production&lt;/em&gt;, and standardizing how Rails components or gems accept configuration.&lt;/p&gt;

&lt;p&gt;Rails projects start with many files by default so it seems as if Rails cannot compete with micro frameworks on that minimalism front. However, that's deliberate choice with its own benefits and if we only really cared for the size, we can build a single file application as Greg Molnar &lt;a href="https://greg.molnar.io/blog/a-single-file-rails-application/" rel="noopener noreferrer"&gt;shows us&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# frozen_string_literal: true&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'bundler/inline'&lt;/span&gt;

&lt;span class="n"&gt;gemfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="s1"&gt;'https://rubygems.org'&lt;/span&gt;

  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'rails'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'~&amp;gt; 7.0.4'&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'sqlite3'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rails/all'&lt;/span&gt;
&lt;span class="n"&gt;database&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'development.sqlite3'&lt;/span&gt;

&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'DATABASE_URL'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"sqlite3:&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;establish_connection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;adapter: &lt;/span&gt;&lt;span class="s1"&gt;'sqlite3'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;database: &lt;/span&gt;&lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;STDOUT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;create_table&lt;/span&gt; &lt;span class="ss"&gt;:posts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;force: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;create_table&lt;/span&gt; &lt;span class="ss"&gt;:comments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;force: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;integer&lt;/span&gt; &lt;span class="ss"&gt;:post_id&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;__dir__&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;consider_all_requests_local&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;secret_key_base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'i_am_a_secret'&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;active_storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;service_configurations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'local'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'service'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Disk'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'root'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'./storage'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="s1"&gt;'welcome#index'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WelcomeController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActionController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;
    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;inline: &lt;/span&gt;&lt;span class="s1"&gt;'Hi!'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;App&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize!&lt;/span&gt;

&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="no"&gt;App&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this kind of minimalism is only helpful in micro examples. Typical applications will inevitably grow, so this is less of a concern. Generating more files at the beginning shows where we want things to live. It complements all of the other important design choices in Rails.&lt;/p&gt;

&lt;h3&gt;
  
  
  Effortlessly RESTful
&lt;/h3&gt;

&lt;p&gt;A big part of any web application, be it something user facing or just an &lt;a href="https://serpapi.com" rel="noopener noreferrer"&gt;API&lt;/a&gt;, is its RESTful interface, coming from Representational State Transfer (REST) coined by Roy Fielding in 2000. There is lot of plumbing in representing state and data, and it's something that's practically solved since the Rails early days.&lt;/p&gt;

&lt;p&gt;When it comes to implementing Rails applications, you don't need to prompt &lt;em&gt;"Create a RESTful controller with standard CRUD actions, following the naming convention…"&lt;/em&gt; — you just say &lt;em&gt;"Add posts to this app"&lt;/em&gt;, and the agent can fill in the rest correctly, because the conventions tell it everything it needs to know. These conventions fundamentally changes how agents behave. Instead of guessing, they can infer. Instead of generating plausible-but-wrong code, they land on the idiomatic solution from the start.&lt;/p&gt;

&lt;p&gt;Less decision-making means &lt;strong&gt;better performance&lt;/strong&gt;. Agents are not creative problem solvers in the human sense; they are pattern completion systems. Every extra decision you force them to make increases the chance of incorrect structure, inconsistent naming, or broken integration. Rails removes entire categories of these decisions this way. The result is more reliable code generation, faster iteration loops, and fewer corrections by humans.&lt;/p&gt;

&lt;h2&gt;
  
  
  Baked-in features
&lt;/h2&gt;

&lt;p&gt;Rails packs a lot of functionality out of the box. This is by design as the framework has always believed that Convention over Configuration isn't just about file structure, it's about shipping defaults that are genuinely production-ready. Rails is extracted, not designed. There is no committee adding imaginary nice-to-have features. New features are extracted from real world applications.  &lt;/p&gt;

&lt;p&gt;As an example, I was thinking about using Django early in my career and followed its releases over the years. Perhaps it's not entirely fair given the smaller team and different commercial attention, but Django always missed things Rails already had. Many things were added over time to Django as well, but Rails continues to have opinionated answers to almost anything. Django still largely leaves these as "pick your own adventure."  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rails is a framework of frameworks.&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;When you create a Rails application, you're not starting with a router and a blank slate. You're getting Active Record, Action Mailer, Active Job, Action Cable, Active Storage, and more. All integrated, all following the same conventions, all tested together, and on top supported by Hotwire and Solid libraries, which expand on these core frameworks even further.&lt;/p&gt;

&lt;p&gt;Some of these main frameworks are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Active Record&lt;/strong&gt; is the database layer. Models map to tables, associations are declared with one line (has_many, belongs_to), and queries are chainable Ruby instead of raw SQL. Migrations version your schema alongside your code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active Model&lt;/strong&gt; handles model's validations, serialization, type casting, dirty tracking, and more even without full database-backed Active Record so you can use it in your own plain Ruby objects modeling your domain layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action View&lt;/strong&gt; is the templating layer. ERB templates, partials, layouts, helpers, and form builders. Form helpers handle CSRF tokens, URL generation, and type-appropriate inputs automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action Controller&lt;/strong&gt; &amp;amp; &lt;strong&gt;Action Dispatch&lt;/strong&gt; are the HTTP layer. Controllers handle requests, dispatch routes them. You declare routes in one file (routes.rb) and they map to controller actions. Action Dispatch also handles middleware and request/response objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action Mailer&lt;/strong&gt; brings email as controllers. Each mailer is a class with methods that correspond to email templates. You call &lt;code&gt;UserMailer.welcome(user).deliver_later&lt;/code&gt; and get templated HTML/text email with the same layout system as your views.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active Job&lt;/strong&gt; is the common interface for background jobs. You define a job class with a perform method, call MyJob.perform_later(args), and Rails queues it. It works with many adapters from Sidekiq, to Solid Queue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action Cable&lt;/strong&gt; is the Rails WebSockets integration. Channels work like controllers for persistent connections. You subscribe to channels and broadcast data from anywhere in your application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action Mailbox&lt;/strong&gt; routes inbound emails to mailbox classes, similar to how Action Controller routes HTTP requests to controllers. Handles ingestion from Postmark, Sendgrid, Mailgun, or raw SMTP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active Storage&lt;/strong&gt; handles upload, storage, URL generation, transformations, and variants of your model's file attachments. It comes with swappable backends and supports direct uploads to S3/GCS/Azure in production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action Text&lt;/strong&gt; brings rich text content editing to your application backed by the editor of your choice (defaults to Lexxy). It's an abstraction for your rich text fields that integrates with Active Storage for embedded attachments. This tight integration is unique to Rails.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All and more is available to your agents in a single package. Take just the storage for example. It's not just that you can attach a file to your model, you can immediately use a form helper for that, make it a direct upload, create more efficient variants, use it later in a background job or WYSIWYG editor.&lt;/p&gt;

&lt;p&gt;This kind of internal standardization can make complex features feel easy during agentic programming as it's the experience of our Engineering Director &lt;a href="https://x.com/ilyazub_" rel="noopener noreferrer"&gt;Illia Zub&lt;/a&gt; when it came to &lt;a href="https://x.com/ilyazub_/status/2079573049586663923" rel="noopener noreferrer"&gt;using Rails Engines&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I asked &lt;a href="https://x.com/GitHubCopilot" rel="noopener noreferrer"&gt;@GitHubCopilot&lt;/a&gt; to research the options and propose a plan. Then I kept reviewing it and writing, "Nah, I feel this can be simpler and more consistent." After several rounds of feedback to the plan, it landed on a Rails engine (...) The result is a whole new feature in only a handful of files. It reuses our existing controller directly instead of making a separate API call, which is super nice.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And that's not all.&lt;/p&gt;

&lt;h3&gt;
  
  
  Solid Trifecta
&lt;/h3&gt;

&lt;p&gt;Another example of this philosophy is the so-called Solid Trifecta stack: &lt;strong&gt;Solid Cache&lt;/strong&gt; , &lt;strong&gt;Solid Queue&lt;/strong&gt; , and &lt;strong&gt;Solid Cable&lt;/strong&gt;. These three libraries let you replace Redis and other external services with your primary database, either with MySQL, PostgreSQL or SQLite.&lt;/p&gt;

&lt;p&gt;Solid Trifecta is designed to reduce complexity. Even if they are not technically part of the Rails code directly, Rails ships with all three as defaults in new applications. Most frameworks would tell you to figure out your own message queue and caching layer, but Rails has one.&lt;/p&gt;

&lt;p&gt;They all plug into to a higher level APIs like Active Job which still lets you replace them with alternatives at any moment while keeping the same API interface. The new directions around SQLite is especially interesting given how much simplification you can do to your architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing
&lt;/h3&gt;

&lt;p&gt;Even the default test suite reflects this philosophy. &lt;strong&gt;Minitest&lt;/strong&gt; , the Rails' default testing framework, supports parallel test execution leveraging multiple cores with a single configuration line. You don't need to reach for a separate gem or configure a CI matrix differently. It's there, it works, and it's fast. The assumption is that your tests should run quickly on the hardware you already have.&lt;/p&gt;

&lt;p&gt;On the other hand, lots of applications (including SerpApi) still choose &lt;strong&gt;RSpec&lt;/strong&gt; , mainly for its DSL syntax focused on specifying behavior. Since it's a more popular option, it's also a great alternative for agentic coding. Rails usually gives you something out of the box, but still makes choosing an alternative easy.&lt;/p&gt;

&lt;p&gt;The alternatives in Rails are usually limited to a few of options, like here with RSpec being the only common alternative to Minitest, but that's a good thing. Coding agents do better with things that are well used and understood.&lt;/p&gt;

&lt;h2&gt;
  
  
  Training data
&lt;/h2&gt;

&lt;p&gt;The Rails predictable nature and long list of features are great, but it's the real world use that makes the training possible. Rails is what I call &lt;strong&gt;the OG&lt;/strong&gt; of all modern web frameworks; one that brought MVC and Active Record patterns to the masses, and inspired a whole generation of frameworks since that. Laravel author Taylor Otwell mentioned &lt;a href="https://www.friendly.show/2278525/episodes/15825442-taylor-otwell-how-rails-inspired-laravel-live-from-rails-world-2024" rel="noopener noreferrer"&gt;several times&lt;/a&gt; how he got inspired by Rails, namely by Active Record, to create Eloquent ORM.&lt;/p&gt;

&lt;p&gt;This kind of history and pedigree helped Rails accumulate a list of famous open source projects with well-structured codebases. Some of the projects you might heard about include Spree (eCommerce), Redmine (project management), GitLab (DevOps), Diaspora (social network), Discourse (forums), Maybe (finance), and Chatwoot (customer support).&lt;/p&gt;

&lt;p&gt;But it's not just the grand past. Recently, 37signals specifically made many of its applications source available. Campfire, Writebook, and Fizzy sources are now available for LLM training as well. The Rails foundation even started to publish this kind of applications as a small directory directly on the web as &lt;a href="https://rubyonrails.org/docs/reference-apps" rel="noopener noreferrer"&gt;Reference Apps&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgvv78nfd7f4gztz7nzxy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgvv78nfd7f4gztz7nzxy.png" alt="The new Rails apps showcase" width="800" height="603"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The new Rails apps showcase&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The Rails documentation, namely the part called &lt;strong&gt;Rails Guides&lt;/strong&gt; , also stands out as a source on how to write Rails code. Since Rails applications tend to look similar, models get better generalizing patterns they can follow for writing new code or refactoring. Rails Guides are also coming through a bit of an update now, with completely new guides being written like the one on &lt;a href="https://github.com/rails/rails/pull/57293" rel="noopener noreferrer"&gt;Accessibility&lt;/a&gt; made by &lt;em&gt;a blind programmer&lt;/em&gt; Bruno Prieto.&lt;/p&gt;

&lt;p&gt;Ruby also had an agent-friendly documentation long before we heard about AI agents. Apart from RDoc, the usual documentation generator, Ruby has a tool called &lt;a href="https://ruby.github.io/rdoc/RI_md.html" rel="noopener noreferrer"&gt;RI&lt;/a&gt; which is a command line interface documentation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ri Hash             &lt;span class="c"&gt;# Document for class Hash.&lt;/span&gt;
ri Array#sort       &lt;span class="c"&gt;# Document for instance method sort in class Array.&lt;/span&gt;
ri &lt;span class="nb"&gt;read&lt;/span&gt;             &lt;span class="c"&gt;# Documents for methods ::read and #read in all classes and modules.&lt;/span&gt;
ri ruby:dig_methods &lt;span class="c"&gt;# Document for page dig_methods.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By passing the &lt;code&gt;--no-pager&lt;/code&gt; option, we get results printed directly to the terminal.&lt;/p&gt;

&lt;p&gt;Today's agents are powerful enough to fetch even HTML documentation, but it's nice to have this option, especially for completely local development.&lt;/p&gt;

&lt;h2&gt;
  
  
  World-class libraries
&lt;/h2&gt;

&lt;p&gt;I think that originally lots of people thought that with all LLM training happening in other languages, Ruby could felt behind. That's no longer true. The thing is that Ruby doesn't need to have the best ecosystem for LLM training. Very few companies can afford to train a model from scratch anyways.&lt;/p&gt;

&lt;p&gt;On the other hand, every developer wants to take advantage of calling LLM, embedding data, fine tune models, and run their own agents. Using agents to build AI features might look like a scene from Inception, but it's actually our reality. And that's where both Ruby and Rails have a lot to offer today.&lt;/p&gt;

&lt;h3&gt;
  
  
  The RubyLLM revolution
&lt;/h3&gt;

&lt;p&gt;The things started to look better with an unofficial &lt;a href="https://github.com/alexrudall/ruby-openai" rel="noopener noreferrer"&gt;ruby-openai&lt;/a&gt; gem for integrating ChatGPT, today also with an option to use the official &lt;a href="https://github.com/openai/openai-ruby" rel="noopener noreferrer"&gt;openai-ruby&lt;/a&gt; library from &lt;strong&gt;OpenAI&lt;/strong&gt;. But a small revolution started with &lt;a href="https://rubyllm.com" rel="noopener noreferrer"&gt;RubyLLM&lt;/a&gt; which brought the most beautiful API for Ruby chat interfaces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;chat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;RubyLLM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt; &lt;span class="ss"&gt;model: &lt;/span&gt;&lt;span class="s2"&gt;"gpt-4o-mini"&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ask&lt;/span&gt; &lt;span class="s2"&gt;"What's the day today?"&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;content&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple chat is just the beginning. RubyLLM's elegance really shows as you reach for more advanced features. Need to analyze an image, a PDF, or an audio file? It's the same interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ask&lt;/span&gt; &lt;span class="s2"&gt;"What's in this image?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;with: &lt;/span&gt;&lt;span class="s2"&gt;"ruby_conf.jpg"&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ask&lt;/span&gt; &lt;span class="s2"&gt;"Summarize this document"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;with: &lt;/span&gt;&lt;span class="s2"&gt;"contract.pdf"&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ask&lt;/span&gt; &lt;span class="s2"&gt;"Describe this meeting"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;with: &lt;/span&gt;&lt;span class="s2"&gt;"meeting.wav"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Want to stream a response in real time? Pass a block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ask&lt;/span&gt; &lt;span class="s2"&gt;"Tell me a story about Ruby"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;content&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;RubyLLM doesn't stop with an interface to text models. Even image generation, transcribing audio, and embeddings follow the same pattern of radical simplicity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Generate images&lt;/span&gt;
&lt;span class="no"&gt;RubyLLM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;paint&lt;/span&gt; &lt;span class="s2"&gt;"a sunset over mountains in watercolor style"&lt;/span&gt;

&lt;span class="c1"&gt;# Transcribe audio to text&lt;/span&gt;
&lt;span class="no"&gt;RubyLLM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transcribe&lt;/span&gt; &lt;span class="s2"&gt;"meeting.wav"&lt;/span&gt;

&lt;span class="c1"&gt;# Create embedding&lt;/span&gt;
&lt;span class="no"&gt;RubyLLM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;embed&lt;/span&gt; &lt;span class="s2"&gt;"Ruby is elegant and expressive"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These calls will use image, speech-to-text, and embedding models instead, but the DSL is similar.&lt;/p&gt;

&lt;p&gt;The problem with simple model calls is that they are not complete systems. They understand intent well, but are not that good at executing arbitrary tasks. That's why early tools like &lt;strong&gt;LangChain&lt;/strong&gt; came with a way to abstract tools which is something that's already offered by all leading LLM companies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools&lt;/strong&gt; enable models to interact with external tools by outputting JSON objects that specify functions and their arguments. This allows models to retrieve live data, something they otherwise lack as they are trained on existing data.&lt;/p&gt;

&lt;p&gt;Imagine you need for a model to help you with &lt;strong&gt;Search Engine Optimization&lt;/strong&gt; (SEO). You can now write a tool to get live Google search results using SerpApi and provide it to your chat context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SearchGoogle&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;RubyLLM&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Tool&lt;/span&gt;
  &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="s2"&gt;"Search Google and return top organic results for a query"&lt;/span&gt;

  &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="ss"&gt;:query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"The search query"&lt;/span&gt;
    &lt;span class="n"&gt;integer&lt;/span&gt; &lt;span class="ss"&gt;:num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;description: &lt;/span&gt;&lt;span class="s2"&gt;"Number of results to return (max 100, default 10)"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="ss"&gt;num: &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;SerpApi&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;engine: &lt;/span&gt;&lt;span class="s2"&gt;"google"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;api_key: &lt;/span&gt;&lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"SERPAPI_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;q: &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;num: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:organic_results&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;position: &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:position&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;title: &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;url: &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:link&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;snippet: &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:snippet&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;chat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;RubyLLM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;model: &lt;/span&gt;&lt;span class="s2"&gt;"gpt-4o-mini"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;with_tools&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;SearchGoogle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ask&lt;/span&gt; &lt;span class="s2"&gt;"What are the top 5 Google results for 'ruby on rails'?"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Want a reusable agent with its own personality and tools? Then you can define the above tool-augmented chat as its own agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SeoAgent&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;RubyLLM&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Agent&lt;/span&gt;
  &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="s2"&gt;"gpt-4o-mini"&lt;/span&gt;

  &lt;span class="n"&gt;instructions&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;~&lt;/span&gt;&lt;span class="no"&gt;PROMPT&lt;/span&gt;&lt;span class="sh"&gt;
    You are an SEO research assistant. You help users investigate Google search rankings,
    analyze competitors, and review historical position data for the sites and keywords.
    Use the tools available to you whenever a question requires live search data.
&lt;/span&gt;&lt;span class="no"&gt;  PROMPT&lt;/span&gt;

  &lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="no"&gt;CheckKeywordPosition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;SearchGoogle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;FindCompetitors&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;SeoAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"What are the top 5 Google results for 'ruby on rails'?"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your application has agents with access to internal and external tools to do their best work. The DSL for that is small, compact, and beautiful. Yes, it's just an abstraction really. These agents aren't autonomous agents that writes your code.&lt;/p&gt;

&lt;p&gt;Abstractions do matter though. Good abstractions will DRY your code and become the predictable patterns for your code writing agents. If you want to see another example, go read my previous post &lt;a href="https://serpapi.com/blog/how-to-implement-rubyllm-agents/" rel="noopener noreferrer"&gt;How to implement AI agents in Rails with RubyLLM&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  RubyLLM and Rails
&lt;/h3&gt;

&lt;p&gt;RubyLLM isn't just a Ruby library, it comes with a first-class ActiveRecord integration. A single &lt;code&gt;acts_as_chat&lt;/code&gt; declaration gives you a persistent, database-backed chat complete with message history, tool calls, and model switching:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SeoChat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;acts_as_chat&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;chat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create!&lt;/span&gt; &lt;span class="ss"&gt;model: &lt;/span&gt;&lt;span class="s2"&gt;"claude-sonnet-4"&lt;/span&gt;
&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ask&lt;/span&gt; &lt;span class="s2"&gt;"What's onpage SEO?"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even better, we can now update our agent to also have persistence using this model by declaring &lt;code&gt;chat_model&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SeoAgent&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;RubyLLM&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Agent&lt;/span&gt;
  &lt;span class="n"&gt;chat_model&lt;/span&gt; &lt;span class="no"&gt;SeoChat&lt;/span&gt;
  &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="s2"&gt;"gpt-4o-mini"&lt;/span&gt;
  &lt;span class="n"&gt;instructions&lt;/span&gt; &lt;span class="s2"&gt;"You are an SEO research assistant..."&lt;/span&gt;
  &lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="no"&gt;CheckKeywordPosition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;SearchGoogle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;FindCompetitors&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare all of this to the usual experience where you configure clients, define message schemas, manage request formats and write case statements for provider-specific quirks.&lt;/p&gt;

&lt;h3&gt;
  
  
  MCPs
&lt;/h3&gt;

&lt;p&gt;Model Context Protocol (MCP) is making AI-assisted Rails development far more practical by giving agents structured access to application context instead of forcing them to rely on massive prompts. Rather than pasting files into a chat window, developers can expose tools that let agents inspect routes, models, database schemas, controllers, jobs, and other parts of an app directly.  &lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/maquina-app/rails-mcp-server" rel="noopener noreferrer"&gt;rails-mcp-server&lt;/a&gt; project brings this idea to Rails by exposing application internals through MCP-compatible tooling. This allows AI agents such as Claude Code, Cursor, or terminal-based assistants to query the application in a much more targeted and reliable way, similarly as they would do for SerpApi API using the &lt;a href="https://serpapi.com/blog/introducing-serpapis-mcp-server/" rel="noopener noreferrer"&gt;SerpApi MCP&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;Another interesting project is &lt;a href="https://github.com/crisnahine/rails-ai-context" rel="noopener noreferrer"&gt;rails-ai-context&lt;/a&gt;, which focuses on automatically generating structured Rails context for AI tools. Instead of manually curating prompts, the gem helps agents understand relationships between routes, models, Stimulus controllers, validations, and other parts of the stack.&lt;/p&gt;

&lt;h3&gt;
  
  
  More tools
&lt;/h3&gt;

&lt;p&gt;The RubyLLM and MCP tooling are excellent additions to an already rich ecosystem of gems handling anything from agentic workflows (like&lt;br&gt;&lt;br&gt;
&lt;a href="https://activeagents.ai/" rel="noopener noreferrer"&gt;Active Agent&lt;/a&gt;) and authorization (like &lt;a href="https://github.com/palkan/action_polic" rel="noopener noreferrer"&gt;Action Policy&lt;/a&gt;), to analytics (like &lt;a href="https://github.com/ankane/ahoy" rel="noopener noreferrer"&gt;Ahoy&lt;/a&gt;) and search (like &lt;a href="https://github.com/ankane/searchkick" rel="noopener noreferrer"&gt;Searchkick&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnnyi7mxxqwxjp1hins4g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnnyi7mxxqwxjp1hins4g.png" alt="Rails also comes with admin panels like Active Admin or Avo" width="800" height="575"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Rails also comes with admin panels like Active Admin or Avo&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kamal-deploy.org" rel="noopener noreferrer"&gt;Kamal&lt;/a&gt;, the recent addition to the default Rails application Gemfile, is especially interesting given the agents can now use it to deploy your application on your own terms. This simple deploy tool comes with built-in gapless deployments, local Docker registry, or SSL/TLS support. Your agents now only need something like a Digital Ocean or Hetzner token for handling everything.&lt;/p&gt;

&lt;p&gt;Rails doesn't always come with many gem alternatives given the relatively smaller community, but the libraries it has are usually of a higher quality and the consolidation of choices once again benefit the training and output of coding agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future
&lt;/h2&gt;

&lt;p&gt;What about the future? Can Rails still keep up? Luckily, it seems that Rails is well positioned for a successful future thanks to its leadership and the Rails Foundation which now heavily invests in the documentation and ecosystem. We are now getting new guides and improvements every day.&lt;/p&gt;

&lt;p&gt;37signals, the company DHH co-founded, and the one that's constantly giving back to Rails is on the trajectory to adopt agents in their apps, be it with agent skills or the new CLIs. This adoption is important, because DHH and 37signals still remain the stewardship of Rails. In one of the latest piece &lt;a href="https://world.hey.com/dhh/promoting-ai-agents-3ee04945" rel="noopener noreferrer"&gt;Promoting AI agents&lt;/a&gt;, DHH shares his optimistic view on the progress in agent coding:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But with these autonomous agents, the experience is very different. It's more like working on a team and less like working with an overly-zealous pair programmer who can't stop stealing the keyboard to complete the code you were in the middle of writing. With a team of agents, they're doing their work autonomously, and I just review the final outcome, offer guidance when asked, and marvel at how this is possible at all.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;DHH seems to have a healthy view on AI, continuously adopting new ways of working with it and reevaluating the status quo.&lt;/p&gt;

&lt;p&gt;Similarly, the new Rails documentation work aimed &lt;a href="https://github.com/rails/rails/blob/main/AGENTS.md" rel="noopener noreferrer"&gt;directly at AI agents&lt;/a&gt; is also another step forward. Better machine-readable documentation combined with MCP tooling gives agents access to authoritative framework knowledge and paves the way for agents to work on the Rails codebase itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fin
&lt;/h2&gt;

&lt;p&gt;It's not that Rails is the winner in every single category we could consider for agentic coding. There are more token-efficient languages than Ruby, they are frameworks that are more popular, more minimal, with a faster runtime, and with project leaders more bullish on AI. But the thing with Rails is that it ranks high enough in all these categories, from token efficiency to high quality guides.&lt;/p&gt;

&lt;p&gt;Considering all of that, Rails is the most attractive framework for robots today, just as it once was for humans. At SerpApi we continue to bet on Rails to build the world-class SERP API and we invest in its thriving ecosystem and community. We joined the Rails foundation, we are sponsoring the upcoming Rails World in Austin, and we continue to work on our Open Source projects like &lt;a href="https://serpapi.com/blog/introducing-serptrail-self-hosted-search-rank-tracker/" rel="noopener noreferrer"&gt;SerpTrail&lt;/a&gt; and &lt;a href="https://github.com/serpapi/nokolexbor" rel="noopener noreferrer"&gt;Nokolexbor&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Join us in our effort to make Rails better.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Connect Sakana AI (Fugu) with Web Search API</title>
      <dc:creator>Hilman Ramadhan</dc:creator>
      <pubDate>Thu, 30 Jul 2026 02:50:51 +0000</pubDate>
      <link>https://dev.to/serpapi/connect-sakana-ai-fugu-with-web-search-api-oki</link>
      <guid>https://dev.to/serpapi/connect-sakana-ai-fugu-with-web-search-api-oki</guid>
      <description>&lt;p&gt;Sakana AI’s Fugu introduces a new way to work with AI models: instead of relying on a single model for every task, Fugu serves as a multi-agent system that coordinates specialized AI agents via a single OpenAI-compatible API.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sakana.ai/fugu/" rel="noopener noreferrer"&gt;Sakana Fugu — Multi-agent System as A Model&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That makes it especially useful for workflows that need more than static model knowledge. When you connect Fugu with &lt;a href="https://serpapi.com/use-cases/web-search-api" rel="noopener noreferrer"&gt;Web Search API&lt;/a&gt;, you can give your AI application access to real-time search data from Google and other search engines, then use Fugu to reason over that data, summarize it, compare results, or generate useful outputs.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use the Sakana AI API
&lt;/h2&gt;

&lt;p&gt;The Sakana AI API is OpenAI-compatible. We can use it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;base_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.sakana.ai/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FUGU_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fugu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Create a sarcastic poem for vibe coder&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't forget to export your FUGU_API_KEY on the terminal&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export FUGU_API_KEY=YOUR_SAKANA_FUGU_API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The poem result, hope no one is offended 😄&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq5c29k4va9523xba6fxy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq5c29k4va9523xba6fxy.png" alt="basic response API call for Sakana AI" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;basic response API call for Sakana AI&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Streaming&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can also stream the results with a simple tweak&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fugu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Explain why vibe coding is useful in three short bullets.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response.output_text.delta&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Full response object assembled from the stream.
&lt;/span&gt;    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_final_response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Two available models
&lt;/h3&gt;

&lt;p&gt;We have two options to use as the model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fugu: for balancing performance and low latency. Can be used for common problems or tasks.&lt;/li&gt;
&lt;li&gt;Fugu Ultra: for more complicated tasks. It will use a deeper pool of expert AI agents. It costs more and takes a longer time to finish.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F754q02mtzc09cj8bp8dx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F754q02mtzc09cj8bp8dx.png" alt="Benchmark from sakana.ai website" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Benchmark from sakana.ai website&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Give real-time data to Sakana AI
&lt;/h2&gt;

&lt;p&gt;Not just the simple &lt;code&gt;completion&lt;/code&gt; or &lt;code&gt;response&lt;/code&gt; &lt;a href="https://developers.openai.com/api/docs/guides/tools" rel="noopener noreferrer"&gt;built-in tools that available on OpenAI&lt;/a&gt; is also available here, except the advance options.&lt;/p&gt;

&lt;p&gt;First, let's ask Sakana what the recent World Cup score is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fugu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s the recent FIFA men&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s world cup score?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhmga9by7xiia24gpzfm4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhmga9by7xiia24gpzfm4.png" alt="Sakana AI has no real-time data access" width="798" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Sakana AI has no real-time data access&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As we know, world cup 2026 is currently running in USA, clearly the AI don't have access to recent information.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Web Search tool
&lt;/h3&gt;

&lt;p&gt;Let's connect with the built-in search tool&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fugu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;web_search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt; &lt;span class="c1"&gt;# one line addition
&lt;/span&gt;    &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s the recent FIFA men&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s world cup score?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we have the update from today's match (when this blog is written)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxfghdx76m3ov5icrt38i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxfghdx76m3ov5icrt38i.png" alt="collect real-time news on Sakana AI" width="800" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;collect real-time news on Sakana AI&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Advanced Web Search Tool
&lt;/h3&gt;

&lt;p&gt;What if we ask more complicated questions that can't be answered with a simple Google search?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s the ticket price for this weekend from Toronto to Los Angeles? one way trip&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The program got stuck or just took a very long time (I waited for 3 minutes). So, I'm trying something else. Maybe if I stream it, I can get the thought process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fugu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;web_search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt; 
    &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s the recommended gift for Argentina football fans? share a link and the price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response.output_text.delta&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Full response object assembled from the stream.
&lt;/span&gt;    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_final_response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, I don't see anything and had to wait ~3 minutes before I stopped the program&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8tjz6r6dd5p7ns4xqkt1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8tjz6r6dd5p7ns4xqkt1.png" alt="Sakana AI error on hard question that need real-time data" width="770" height="167"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Sakana AI error on hard question that need real-time data&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The issue and the solution&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Similar to the OpenAI native web search tool, there are still some limitations. To solve this issue, we can connect the AI with &lt;a href="https://serpapi.com/search-engine-apis" rel="noopener noreferrer"&gt;SerpApi - search engine APIs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sample project&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
I'm going to ask the AI to return a recommended items alongside real time pricing and shopping link.&lt;/p&gt;

&lt;p&gt;Sample usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s a good gaming laptop under $1000?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="nf"&gt;run_shopping_assistant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sample result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkym0a2h1pir9g7c02z2f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkym0a2h1pir9g7c02z2f.png" alt="Sample result when Sakana AI has access to live e-commerce data" width="800" height="701"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Sample result when Sakana AI has access to live e-commerce data&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Preparation&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ensure you register at &lt;a href="https://serpapi.com/" rel="noopener noreferrer"&gt;serpapi.com&lt;/a&gt; to get your free API key.&lt;/li&gt;
&lt;li&gt;Understand the basics of function calling on OpenAI, as we'll build a custom function to call an API&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/guides/function-calling" rel="noopener noreferrer"&gt;Function calling | OpenAI API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to try it directly, here is the source code link:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/serpapi/tutorials/tree/master/python_projects/sakana-fugu-web-search" rel="noopener noreferrer"&gt;tutorials/python_projects/sakana-fugu-web-search at master · serpapi/tutorials&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Code implementation&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, let's load everything: OpenAI API key, SerpApi API Key, and the required packages
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;

&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;base_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.sakana.ai/v1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FUGU_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;SERPAPI_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SERPAPI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Define the tool structure we're going to use
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;google_shopping_search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Search for products on Google Shopping using SerpApi&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;parameters&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;object&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;properties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The product search query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;required&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;additionalProperties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;strict&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can add more if we need to access multiple APIs.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Define the actual search function
Now, we're going to call the API, in this case, the Google Shopping API
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;google_shopping_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Simple Google Shopping search using SerpApi
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🔎 Checking SerpApi key...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;SERPAPI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Missing SERPAPI_API_KEY environment variable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🌐 Requesting Google Shopping results from SerpApi for: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api_key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SERPAPI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;engine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;google_shopping&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;q&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://serpapi.com/search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🌐 SerpApi responded with HTTP &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;📦 Parsing SerpApi response JSON...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;shopping_results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shopping_results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

        &lt;span class="c1"&gt;# Format results
&lt;/span&gt;        &lt;span class="n"&gt;formatted_results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;shopping_results&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
            &lt;span class="n"&gt;formatted_item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;N/A&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;link&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;product_link&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rating&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rating&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;N/A&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reviews&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reviews&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;formatted_results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;formatted_item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;formatted_results&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total_results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shopping_results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exceptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestException&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;API Error: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, I'm getting the first 5 items from the &lt;a href="https://serpapi.com/google-shopping-api" rel="noopener noreferrer"&gt;Google Shopping API&lt;/a&gt; response.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Helper function&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To maintain the readability of the code, let's break down some helper functions. First, to help us see the results in a readable format. You can skip this if you don't need it on your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;print_shopping_results&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Print SerpApi shopping results in a readable format.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;📊 Found &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;total_results&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; products:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;. &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;   Price: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;   Source: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;source&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rating&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;N/A&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;   Rating: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rating&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; ⭐ (&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;reviews&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; reviews)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;   Link: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;link&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;   Error: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, to send the actual request to Fugu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Create a non-streaming Fugu response.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🤖 Sending request to Fugu...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fugu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;input_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Last one, to handle the tool call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_tool_call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool_call&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Execute a Responses API function_call item.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tool_call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;google_shopping_search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unknown tool: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tool_call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;tool_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool_call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arguments&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSONDecodeError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;tool_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid tool arguments: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;🔧 Calling function: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tool_call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;   Query: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tool_input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;google_shopping_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool_input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="nf"&gt;print_shopping_results&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tool call failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function_call_output&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;call_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tool_call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;output&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Running the program&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, is the actual function that triggers the whole thing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_shopping_assistant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_query&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Run the shopping assistant with Sakana AI Fugu
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FUGU_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Missing FUGU_API_KEY environment variable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;input_messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user_query&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🧠 Asking Fugu whether a tool is needed...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_messages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;✅ Fugu response received.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;max_iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;iteration&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_iterations&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🔁 Processing response step &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;iteration&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;max_iterations&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;input_messages&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;

        &lt;span class="n"&gt;tool_calls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function_call&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;tool_calls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;✅ No tool calls requested. Done.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_text&lt;/span&gt;

        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🛠️ Fugu requested &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool_calls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; tool call(s).&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;tool_outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;handle_tool_call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool_call&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tool_call&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tool_calls&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;input_messages&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;tool_outputs&lt;/span&gt;

        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🤖 Recommendation:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🧠 Sending tool results back to Fugu...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_messages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;✅ Fugu follow-up response received.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Reached maximum tool-calling iterations&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Example usage
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Example 1
&lt;/span&gt;        &lt;span class="n"&gt;query1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s a good gaming laptop under $1000?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="nf"&gt;run_shopping_assistant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;RuntimeError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;❌ Error: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Make sure you have a .env file with:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  FUGU_API_KEY=...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  SERPAPI_API_KEY=...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Sakana AI for Coding
&lt;/h2&gt;

&lt;p&gt;Want to use Fugu, the new Sakana AI model, as your coding partner? Here is an example from our Vibe Coding series on YouTube:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/embed/YfGbtyVnGnE?feature=oembed" rel="noopener noreferrer"&gt;https://www.youtube.com/embed/YfGbtyVnGnE?feature=oembed&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here is &lt;a href="https://console.sakana.ai/get-started" rel="noopener noreferrer"&gt;the official guideline on using Sakana in Codex&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ on Sakana AI
&lt;/h2&gt;

&lt;p&gt;Some frequently asked questions:  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is Sakana AI popular?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Sakana AI is popular because it takes a different approach to AI by focusing on systems that can combine and coordinate multiple models. Its Fugu model is especially interesting because it works through an OpenAI-compatible API and can orchestrate specialized AI agents for more complex tasks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is Sakana AI - Fugu model free?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
It's not free. Fugu is available through paid subscription and pay-as-you-go plans, so you’ll need to check the Sakana AI Console for the latest pricing, available models, and usage limits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to use Sakana AI?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
To use Sakana AI, sign in to the Sakana AI Console and connect to it using its OpenAI-compatible API. You can also combine it with SerpApi to give your AI app access to real-time search data from Google and other search engines.  &lt;/p&gt;

&lt;p&gt;If you want to use it as your coding partner, you can install &lt;code&gt;codex-fugu&lt;/code&gt; to use it just like codex CLI.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Loop Engineering Visualized: A World Cup Fan Journey with SerpApi and Codex</title>
      <dc:creator>Magenta Qin</dc:creator>
      <pubDate>Wed, 29 Jul 2026 18:50:38 +0000</pubDate>
      <link>https://dev.to/serpapi/loop-engineering-visualized-a-world-cup-fan-journey-with-serpapi-and-codex-2p7d</link>
      <guid>https://dev.to/serpapi/loop-engineering-visualized-a-world-cup-fan-journey-with-serpapi-and-codex-2p7d</guid>
      <description>&lt;p&gt;Prompt Engineering focuses on shaping a model call, while Loop Engineering focuses on what happens after that call: how an agent observes the result, updates its state, chooses the next action, and decides whether to continue.&lt;/p&gt;

&lt;p&gt;The difference sounds simple. But it is hard to feel until you build something where the model has to keep going:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fljjfingq43ch2diz9n70.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fljjfingq43ch2diz9n70.png" alt="A conceptual Loop Engineering loop, from trigger and state to tools, observations, memory updates, and the stop condition." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A conceptual Loop Engineering loop, from trigger and state to tools, observations, memory updates, and the stop condition.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The easiest way to understand a loop is to watch one unfold.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So I built a small World Cup fan demo with Codex and SerpApi to make Loop Engineering visible.&lt;/p&gt;

&lt;p&gt;The product idea is intentionally simple: a fan starts with one match, and the agent follows the journey from there. It identifies an interesting player, discovers related matches, searches for highlights, reads fan debates, and keeps deciding what to explore next.&lt;/p&gt;

&lt;p&gt;Eventually, it produces a trace showing how the entire journey unfolded. But under the surface, this is not just a football app. &lt;strong&gt;The fan journey is the agent loop.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every discovery becomes a new context. Every action changes the state. And every result influences what the agent does next.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Demo
&lt;/h2&gt;

&lt;p&gt;The demo is called &lt;strong&gt;World Cup Fan Journey&lt;/strong&gt; , and the full source code is available in the &lt;a href="https://github.com/serpapi/world-cup-loop-engineering" rel="noopener noreferrer"&gt;Github repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F312ip78mwmqv544i3ggo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F312ip78mwmqv544i3ggo.png" alt="The World Cup Fan Journey starts with a natural-language match request and turns it into an interactive path through matches, players, highlights, and fan discussions." width="799" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The World Cup Fan Journey starts with a natural-language match request and turns it into an interactive path through matches, players, highlights, and fan discussions.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The journey starts with a simple natural-language request:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Show me France vs Morocco&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;or in Chinese:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;我想看挪威对法国的比赛&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The app interprets the request, identifies the football matchup, and initializes the first journey state. From there, the agent starts building a fan pack around the match:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Live match context and upcoming games&lt;/li&gt;
&lt;li&gt;Highlights and social content&lt;/li&gt;
&lt;li&gt;Fan debates and trending stories&lt;/li&gt;
&lt;li&gt;Related players and AI-generated match analysis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5wsf160o6hk8d8cw6thy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5wsf160o6hk8d8cw6thy.png" alt="The first iteration turns a match request into a fan pack grounded in live sports data, videos, news, trends, and AI-generated analysis." width="800" height="537"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The first iteration turns a match request into a fan pack grounded in live sports data, videos, news, trends, and AI-generated analysis.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The important interaction is what happens after the user clicks a player.&lt;/p&gt;

&lt;p&gt;For example, if the user follows Kylian Mbappé, the goal changes. The app no longer needs to explain only France vs Morocco. It now needs to explore Mbappé’s football trail: recent matches, videos, debates, memes, and related players.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhfasjnq4piw2zedjwrs3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhfasjnq4piw2zedjwrs3.png" alt="Following a player starts a new iteration: the goal shifts from exploring one match to building that player’s wider football trail." width="799" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Following a player starts a new iteration: the goal shifts from exploring one match to building that player’s wider football trail.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The player clicks to update the goal. From there, the agent enters another loop: it searches, observes the results, updates the journey state, and decides what to retrieve next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7j9l2z52je3lkq47uwyo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7j9l2z52je3lkq47uwyo.png" alt="Following Mbappé changes the goal and expands the journey into three new match trails, each with fresh content and new players the user can follow into the next iteration." width="800" height="567"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Following Mbappé changes the goal and expands the journey into three new match trails, each with fresh content and new players the user can follow into the next iteration.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The user chooses the direction. The loop handles the exploration.&lt;/p&gt;

&lt;p&gt;Finally, when the user clicks &lt;strong&gt;Generate my football graph&lt;/strong&gt; , the demo stops exploring and turns the accumulated journey into a &lt;strong&gt;Loop Engineering trace&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That final output is not meant to be a normal social graph. It is meant to answer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What did the agent know, what did it observe, what did it do next, and why?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Pipeline vs Loop
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frrvo1xm233y3yjw39sgo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frrvo1xm233y3yjw39sgo.png" alt="A pipeline follows a predefined sequence, while this demo loops through goal, planning, search, observation, and state updates until the user chooses the next direction." width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A pipeline follows a predefined sequence, while this demo loops through goal, planning, search, observation, and state updates until the user chooses the next direction.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A normal pipeline follows a predefined path:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Fetch the match → fetch videos → fetch players → render the page.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The next step is already known. However, this demo works differently.&lt;/p&gt;

&lt;p&gt;The agent starts with a goal and builds a journey state around it. Search results introduce new matches, debates, and related players. These observations expand the state and create new directions the journey can take.&lt;/p&gt;

&lt;p&gt;If the user follows Mbappé, the goal changes. The agent plans which of Mbappé's matches to explore, retrieves related football content, and adds new players and observations to the journey. The user can then follow another player, changing the goal again.&lt;/p&gt;

&lt;p&gt;The loop continues:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Goal → Plan → Search → Observe → Update State → Choose Next Direction → Goal Changes → Plan Again&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a human-in-the-loop agent loop. The agent handles planning and exploration, while the user decides which direction is worth following.&lt;/p&gt;

&lt;p&gt;A pipeline says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Do A, then B, then C.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This loop asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Given the current goal and journey state, what should we explore next?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Mapping the Demo to the Loop
&lt;/h2&gt;

&lt;p&gt;The easiest way to map the demo to the loop is to follow it iteration by iteration.&lt;/p&gt;

&lt;p&gt;Each iteration starts with a trigger and a goal. The agent plans what to explore, calls tools, observes the results, and updates the journey state.&lt;/p&gt;

&lt;p&gt;In this demo, the next iteration begins when the user chooses a new direction.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Trigger → Goal → Plan → Tools → Observe → Update State → Next Trigger&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F69nxsouj8kn7pb1ucy3e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F69nxsouj8kn7pb1ucy3e.png" alt="The demo unfolds as a human-in-the-loop journey: each user choice changes the goal and starts another iteration, while the same loop structure repeats underneath." width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The demo unfolds as a human-in-the-loop journey: each user choice changes the goal and starts another iteration, while the same loop structure repeats underneath.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Iteration 1: Start with a Match
&lt;/h3&gt;

&lt;p&gt;The first trigger is the user's search:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Show me France vs Morocco.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The goal is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Build a fan pack for France vs Morocco.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The app parses the request and uses sports, YouTube, news, trends, and player data to assemble the first fan journey.&lt;/p&gt;

&lt;p&gt;The resulting observations include the match status, score, available videos, discussions, and related players. Those results become the current journey state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;At the end of the first iteration, the system has not just rendered a page. It has created possible directions for the next iteration.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Iteration 2: Following Mbappé Changes the Goal
&lt;/h3&gt;

&lt;p&gt;The user clicks &lt;strong&gt;Follow Kylian Mbappé&lt;/strong&gt;. That click becomes the next trigger. In the code, this action starts a new planning step:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flx1qsn78o37z7fa4eq7l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flx1qsn78o37z7fa4eq7l.png" alt="The followPlayer() flow turns a user click into a new plan, enriches the selected matches, and expands the current journey state." width="799" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The followPlayer() flow turns a user click into a new plan, enriches the selected matches, and expands the current journey state.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The LLM decides which three recent or trending matches are worth exploring:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F011c7lk0fot5jm5ygcwx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F011c7lk0fot5jm5ygcwx.png" alt="planPlayerExpansion() asks the LLM to select three recent or trending matches for the followed player and return them as a structured exploration plan." width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;planPlayerExpansion() asks the LLM to select three recent or trending matches for the followed player and return them as a structured exploration plan.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The plan is then grounded with external search data by SerpApi. It retrieves the surrounding sports results, videos, news, and trends.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxvdk6x93frgeqzkogemv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxvdk6x93frgeqzkogemv.png" alt="enrichPlannedMatch() grounds the LLM’s plan with sports results, videos, and discussions from SerpApi before adding the new match trail to the journey state." width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;enrichPlannedMatch() grounds the LLM’s plan with sports results, videos, and discussions from SerpApi before adding the new match trail to the journey state.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The agent observes three new match trails and discovers more related players. The state expands. Now the user has another set of possible directions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The user chooses the direction. The agent explores it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Iteration 3: The Loop Continues
&lt;/h3&gt;

&lt;p&gt;Suppose the user follows Erling Haaland.&lt;/p&gt;

&lt;p&gt;The same loop structure runs again, but with a different goal and a different state.&lt;/p&gt;

&lt;p&gt;The agent plans Haaland's match trail, retrieves new context, observes the results, and adds new match and player nodes to the journey.&lt;/p&gt;

&lt;p&gt;This is why the demo is not a fixed pipeline. The structure repeats, but &lt;strong&gt;the content of each iteration depends on the current goal and accumulated state.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Iteration 4: Another Direction, Same Loop
&lt;/h3&gt;

&lt;p&gt;The user follows Martin Odegaard.&lt;/p&gt;

&lt;p&gt;Again:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;New trigger → new goal → new plan → new observations → expanded state&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The loop structure stays stable. The journey does not.&lt;/p&gt;

&lt;p&gt;By this point, the system has accumulated multiple player trails, discovered matches, and possible next actions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Iteration: Stop and Generate the Trace
&lt;/h3&gt;

&lt;p&gt;The user clicks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Generate my football graph.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This becomes the stop condition.&lt;/p&gt;

&lt;p&gt;The agent stops exploring and turns the accumulated journey into a Loop Engineering trace.&lt;/p&gt;

&lt;p&gt;The final output shows how each iteration changed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the goal&lt;/li&gt;
&lt;li&gt;the current state&lt;/li&gt;
&lt;li&gt;the tools used&lt;/li&gt;
&lt;li&gt;the observations&lt;/li&gt;
&lt;li&gt;the memory carried forward&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The graph is therefore not just a record of which players the user followed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;It is a visualization of how the loop changed from one iteration to the next.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxnci8e5sm5007jbp6zyu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxnci8e5sm5007jbp6zyu.png" alt="The final trace reveals how each user action changed the goal, expanded the state, and started the next iteration." width="799" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The final trace reveals how each user action changed the goal, expanded the state, and started the next iteration.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why SerpApi is Useful
&lt;/h2&gt;

&lt;p&gt;For this demo, SerpApi acts as the observation layer. The LLM can plan what to explore, but the football world keeps changing: match status and scores change, new videos appear, and news and fan discussions evolve.&lt;/p&gt;

&lt;p&gt;The loop needs a way to observe that external world.&lt;/p&gt;

&lt;p&gt;SerpApi provides that context through several search APIs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://serpapi.com/google-sports-api" rel="noopener noreferrer"&gt;&lt;strong&gt;Google Sports API&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;:&lt;/strong&gt; match scores, status, stage, venue, and time&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://serpapi.com/youtube-search-api" rel="noopener noreferrer"&gt;&lt;strong&gt;YouTube Search API&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;:&lt;/strong&gt; highlights and shorts&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://serpapi.com/google-news-api" rel="noopener noreferrer"&gt;&lt;strong&gt;Google News API&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;and&lt;/strong&gt; &lt;a href="https://serpapi.com/google-trends-api" rel="noopener noreferrer"&gt;&lt;strong&gt;Google Trends API&lt;/strong&gt;&lt;/a&gt;: debates, narratives, and rising topics&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://serpapi.com/instagram-profile-api" rel="noopener noreferrer"&gt;&lt;strong&gt;Instagram Profile API&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;:&lt;/strong&gt; player profile context&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://serpapi.com/google-images-api" rel="noopener noreferrer"&gt;&lt;strong&gt;Google Images API&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;:&lt;/strong&gt; player photos and visual fallbacks&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The LLM decides what to explore. SerpApi gives the loop fresh context from the outside world.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Building It with Codex
&lt;/h2&gt;

&lt;p&gt;I built this demo with Codex, but the hardest part was not writing the code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;At the beginning, even the product goal was vague.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I knew I wanted to build a World Cup demo that made Loop Engineering visible. I did not yet know what that experience should look like.&lt;/p&gt;

&lt;p&gt;The first version reflected that uncertainty.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjp2j48msm2igjpxqqmu1.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjp2j48msm2igjpxqqmu1.jpeg" alt="The first version exposed the loop as an engineering dashboard, making the architecture visible but the user experience difficult to understand." width="799" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The first version exposed the loop as an engineering dashboard, making the architecture visible but the user experience difficult to understand.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It exposed almost every engineering concept directly: loop state, observations, memory, constraints, tool calls, validators, and a replay timeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technically, the ideas were there. But as a product, it was painful to use.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A user had to understand Loop Engineering before they could understand the demo. The interface was explaining the architecture instead of letting the user experience it.&lt;/p&gt;

&lt;p&gt;So the development process became iterative.&lt;/p&gt;

&lt;p&gt;I would inspect the UI, explain what felt confusing, and ask Codex to change the product around that observation. Codex would read the existing codebase, make a targeted change, run the build, and give me another version to react to.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Build → Observe → Rethink the goal → Patch → Verify → Repeat&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After several iterations, the product idea became much clearer.&lt;/p&gt;

&lt;p&gt;Instead of showing the loop as an engineering dashboard, the demo would hide most of the machinery behind a simple fan journey:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Start with a match. Follow a player. Discover another match. Follow another player.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The user experiences the loop first.&lt;/p&gt;

&lt;p&gt;Only at the end does the app reveal the Loop Engineering trace and show how each action changed the goal, state, observations, and next iteration.&lt;/p&gt;

&lt;p&gt;That shift changed the entire interface.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxmkkl7w8esg5v7gktw7z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxmkkl7w8esg5v7gktw7z.png" alt="The redesigned interface hides the engineering machinery behind a simple fan journey, letting users experience the loop before revealing the trace underneath it." width="799" height="522"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The redesigned interface hides the engineering machinery behind a simple fan journey, letting users experience the loop before revealing the trace underneath it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The interesting part is that Codex was not simply implementing a finished specification. The specification itself became clearer through the implementation loop.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Every version gave me a new observation. Those observations changed what I asked Codex to build next.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The workflow itself became loop-shaped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two Failures That Made the Loop Clearer
&lt;/h2&gt;

&lt;p&gt;The most useful lessons came from the parts that did not work. Some were ordinary UI bugs. Others exposed weaknesses in how I was thinking about the loop itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The First Graph Showed Relationships, Not Iterations
&lt;/h3&gt;

&lt;p&gt;My first version ended with a graph of players and matches. It showed that Mbappé, Haaland, and Ødegaard were connected to different matches, but it did not explain why the journey moved from one player to the next.&lt;/p&gt;

&lt;p&gt;It showed relationships, but not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What triggered each iteration&lt;/li&gt;
&lt;li&gt;How the goal changed&lt;/li&gt;
&lt;li&gt;What the agent observed&lt;/li&gt;
&lt;li&gt;What state was carried forward&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It was a relationship graph, not a loop trace.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuxpt063qxyij7gtlfe9a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuxpt063qxyij7gtlfe9a.png" width="800" height="721"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So I redesigned the final output around iterations. The new trace shows the goal, current state, tools, observations, and memory for each step.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2t49rf3mc8qbcslvmnvq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2t49rf3mc8qbcslvmnvq.png" alt="The redesigned trace organizes the journey by iteration, revealing how each trigger changed the goal, state, observations, and memory carried into the next step." width="800" height="642"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The redesigned trace organizes the journey by iteration, revealing how each trigger changed the goal, state, observations, and memory carried into the next step.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A visualization should explain the concept, not just decorate the data.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This change also clarified the product itself. The fan journey was only the surface. The real output was the sequence of state transitions underneath it.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Search Relevance Is Not Factual Correctness
&lt;/h3&gt;

&lt;p&gt;At one point, a video title implied that Mbappé had scored in a match where he had not.&lt;/p&gt;

&lt;p&gt;The player-trail search included his name:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;findYoutubeVideo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;planned&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; shorts memes`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;short&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That made sense for retrieval. The goal was to find content related to Mbappé. But a relevant title could still imply incorrect facts, such as the wrong score or a goal he never scored.&lt;/p&gt;

&lt;p&gt;The bug was simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The application treated search-derived copy as verified sports data.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I added a deterministic fact guard before displaying those titles. Sports data verifies the score and match events; search and the LLM only shape how the content is presented.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Sports data owns the facts. Search and the LLM shape the narrative.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The broader Loop Engineering lesson is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A relevant observation is not always trustworthy enough to update factual state.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What I Would Improve Next
&lt;/h2&gt;

&lt;p&gt;The demo makes the loop visible, but it is still a prototype. If I wanted to harden it, I would focus on three things.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Unify the Loop State Model
&lt;/h3&gt;

&lt;p&gt;The demo currently has two state models because the product evolved in stages.&lt;/p&gt;

&lt;p&gt;The earlier replay-mode prototype derives a display snapshot from &lt;code&gt;SessionState&lt;/code&gt; and &lt;code&gt;PersistentMemory&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;snapshot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;buildLoopStateSnapshot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final fan journey uses &lt;code&gt;RabbitHoleState&lt;/code&gt; as its main application state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RabbitHoleState&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This split reflects the development history: the replay dashboard came first, and the fan journey came later.&lt;/p&gt;

&lt;p&gt;If I hardened the project, I would unify both flows around one sequence of loop-state transitions. The fan UI, execution logic, and final trace should all read from the same underlying history instead of adapting between separate representations.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The trace should come from the loop that actually ran, not from a parallel model built to explain it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That would make each iteration easier to inspect, persist, and replay.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Add Production Guardrails
&lt;/h3&gt;

&lt;p&gt;The demo mostly relies on the user to decide when to stop.&lt;/p&gt;

&lt;p&gt;A production loop should also enforce operational limits, including maximum iterations, API timeouts, retry budgets, and graceful fallback behavior when a tool fails.&lt;/p&gt;

&lt;p&gt;Instead of retrying forever, the loop should be able to stop and return the best partial result available.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A stop condition is also a reliability boundary.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. Persist the Journey Across Sessions
&lt;/h3&gt;

&lt;p&gt;Right now, the fan journey is mainly session-based.&lt;/p&gt;

&lt;p&gt;I would persist followed players, expanded trails, accepted content, and other useful memory so that a new session does not start from zero. That would let the loop carry context across a longer fan journey, rather than only across interactions on one page.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Main Takeaway
&lt;/h2&gt;

&lt;p&gt;Everyone is talking about Loop Engineering right now, but people do not always mean exactly the same thing. Some use the term to describe the iteration inside a single AI agent: observe, update state, choose the next action, and repeat. Others use it at a higher level to describe systems that coordinate multiple agent runs over time.&lt;/p&gt;

&lt;p&gt;Neither view is necessarily wrong. They are looking at the same idea from different levels of abstraction.&lt;/p&gt;

&lt;p&gt;In this demo, I focused on the &lt;strong&gt;micro view&lt;/strong&gt;. The loop is human-in-the-loop: the user chooses a direction, the agent explores it, new observations expand the state, and the next user action starts another iteration.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The hard part is not making the model act once. It is designing how goals, observations, state, and decisions evolve from one iteration to the next.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That was also why football turned out to be such a useful example. The outside world keeps changing. A match moves from upcoming to live to full-time. Scores change. New videos appear. News and fan discussions evolve. The model cannot simply remember that world correctly. The loop has to be observed again.&lt;/p&gt;

&lt;p&gt;For this demo, SerpApi's &lt;a href="https://serpapi.com/google-sports-api" rel="noopener noreferrer"&gt;&lt;strong&gt;Google Sports API&lt;/strong&gt;&lt;/a&gt;became the main source of match state: scores, match status, teams, schedules, and other sports context. That fresh data could then be written back into the loop state before the next iteration continued.&lt;/p&gt;

&lt;p&gt;Calling a tool is not enough. The result has to become a new observation, and that observation has to update the state the next iteration will use.&lt;/p&gt;

&lt;p&gt;If you are building an AI agent or workflow around live sports data, try the SerpApi Google Sports API and see what kind of loop you can build around changing match state.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Introducing SerpApi’s Hermes Agent Plugin</title>
      <dc:creator>Adarsh D</dc:creator>
      <pubDate>Wed, 29 Jul 2026 02:46:53 +0000</pubDate>
      <link>https://dev.to/serpapi/introducing-serpapis-hermes-agent-plugin-595f</link>
      <guid>https://dev.to/serpapi/introducing-serpapis-hermes-agent-plugin-595f</guid>
      <description>&lt;p&gt;&lt;a href="https://hermes-agent.nousresearch.com/" rel="noopener noreferrer"&gt;Hermes Agent&lt;/a&gt;&amp;nbsp;is an open-source AI&amp;nbsp;agent from Nous Research that can work from the terminal,&amp;nbsp;desktop,&amp;nbsp;and messaging&amp;nbsp;platforms.&amp;nbsp;You can learn more in the&amp;nbsp;&lt;a href="https://hermes-agent.nousresearch.com/docs/" rel="noopener noreferrer"&gt;Hermes Agent documentation&lt;/a&gt;&amp;nbsp;or&amp;nbsp;explore its source code on&amp;nbsp;&lt;a href="https://github.com/NousResearch/hermes-agent" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Today,&amp;nbsp;we are releasing the open-source&amp;nbsp;&lt;a href="https://github.com/serpapi/serpapi-hermes-plugin" rel="noopener noreferrer"&gt;SerpApi plugin for Hermes Agent&lt;/a&gt;.&amp;nbsp;It connects Hermes's built-in web search to SerpApi and adds dedicated tools for&amp;nbsp;local places,&amp;nbsp;current news,&amp;nbsp;and product research.&amp;nbsp;The plugin is available now&amp;nbsp;on&amp;nbsp;&lt;a href="https://pypi.org/project/serpapi-hermes-plugin/" rel="noopener noreferrer"&gt;PyPI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsd8jl9oml1y7v8kdb3ud.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsd8jl9oml1y7v8kdb3ud.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Plugin Adds
&lt;/h2&gt;

&lt;p&gt;Hermes already knows when it needs to search.&amp;nbsp;The plugin gives it four SerpApi&amp;nbsp;search paths to choose from:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What you ask for&lt;/th&gt;
&lt;th&gt;Hermes tool&lt;/th&gt;
&lt;th&gt;SerpApi engine&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;General web research&lt;/td&gt;
&lt;td&gt;&lt;code&gt;web_search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.com/google-light-api" rel="noopener noreferrer"&gt;Google Light&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Places and local businesses&lt;/td&gt;
&lt;td&gt;&lt;code&gt;serpapi_maps_search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.com/google-maps-api" rel="noopener noreferrer"&gt;Google Maps&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Current and recent news&lt;/td&gt;
&lt;td&gt;&lt;code&gt;serpapi_news_search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.com/google-news-light-api" rel="noopener noreferrer"&gt;Google News Light&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Products, prices, and merchants&lt;/td&gt;
&lt;td&gt;&lt;code&gt;serpapi_shopping_search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href="https://serpapi.com/google-shopping-light-api" rel="noopener noreferrer"&gt;Google Shopping Light&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For a normal web query,&amp;nbsp;Hermes continues to use its familiar&amp;nbsp;&lt;code&gt;web_search&lt;/code&gt;&amp;nbsp;tool;&amp;nbsp;the plugin supplies the SerpApi backend.&amp;nbsp;For a local,&amp;nbsp;news,&amp;nbsp;or shopping request,&amp;nbsp;Hermes can call the matching specialized tool.&amp;nbsp;You can ask naturally without&amp;nbsp;remembering an engine name or tool name.&lt;/p&gt;

&lt;p&gt;Google Light is the default for general web search because its compact response&amp;nbsp;and low latency are a good fit for agent workflows.&amp;nbsp;The specialized tools keep&amp;nbsp;the useful structured fields from their respective engines,&amp;nbsp;such as addresses&amp;nbsp;and ratings for places,&amp;nbsp;publishers and dates for news,&amp;nbsp;and prices and merchants&amp;nbsp;for products.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Native Hermes integration.&lt;/strong&gt; &amp;nbsp;The package uses Hermes's Python plugin and web-search provider interfaces. There is no separate server process to run.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Natural tool selection.&lt;/strong&gt; &amp;nbsp;Hermes chooses general web, Maps, News, or Shopping search from the user's request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One API key.&lt;/strong&gt; &amp;nbsp;&lt;code&gt;SERPAPI_API_KEY&lt;/code&gt;&amp;nbsp;authenticates every search path in the plugin.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Focused responses.&lt;/strong&gt; &amp;nbsp;Each search path returns the fields Hermes needs instead of passing an entire raw search response into the agent's context.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open source and pip-installable.&lt;/strong&gt; &amp;nbsp;The code is available on&amp;nbsp;&lt;a href="https://github.com/serpapi/serpapi-hermes-plugin" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, and the package is distributed through&amp;nbsp;&lt;a href="https://pypi.org/project/serpapi-hermes-plugin/" rel="noopener noreferrer"&gt;PyPI&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;You need a working Hermes Agent installation and a SerpApi account.&amp;nbsp;If you are&amp;nbsp;new to Hermes,&amp;nbsp;follow its&amp;nbsp;&lt;a href="https://hermes-agent.nousresearch.com/docs/getting-started/installation" rel="noopener noreferrer"&gt;installation guide&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a href="https://hermes-agent.nousresearch.com/docs/getting-started/quickstart/" rel="noopener noreferrer"&gt;quickstart&lt;/a&gt;&amp;nbsp;first.&lt;/p&gt;

&lt;p&gt;For complete step-by-step instructions,&amp;nbsp;including custom Hermes installations&amp;nbsp;and manual configuration,&amp;nbsp;see the&amp;nbsp;&lt;a href="https://github.com/serpapi/serpapi-hermes-plugin#install" rel="noopener noreferrer"&gt;repository README&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install it yourself
&lt;/h3&gt;

&lt;p&gt;For a standard Hermes installation on macOS or Linux,&amp;nbsp;install the package into&amp;nbsp;Hermes's Python environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/.hermes/hermes-agent
uv pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--python&lt;/span&gt; venv/bin/python serpapi-hermes-plugin
hermes plugins &lt;span class="nb"&gt;enable &lt;/span&gt;serpapi
hermes tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Select&amp;nbsp; &lt;strong&gt;SerpApi&lt;/strong&gt; &amp;nbsp;under&amp;nbsp; &lt;strong&gt;Web Search &amp;amp; Extract&lt;/strong&gt; ,&amp;nbsp;then enter the Private API Key&amp;nbsp;from your&amp;nbsp;&lt;a href="https://serpapi.com/dashboard" rel="noopener noreferrer"&gt;SerpApi dashboard&lt;/a&gt;.&amp;nbsp;Restart any Hermes&amp;nbsp;session that was already running.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let Hermes install it for you
&lt;/h3&gt;

&lt;p&gt;You can also share our installation instructions with Hermes and let the agent&amp;nbsp;install,&amp;nbsp;enable,&amp;nbsp;configure,&amp;nbsp;and verify the plugin.&amp;nbsp;Paste this into a Hermes chat:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Install and configure serpapi-hermes-plugin by following the instructions at:
https://github.com/serpapi/serpapi-hermes-plugin#ask-hermes-to-install-it
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Approve the installation commands when Hermes prompts you,&amp;nbsp;then provide your&amp;nbsp;Private API Key.&amp;nbsp;The&amp;nbsp;&lt;a href="https://github.com/serpapi/serpapi-hermes-plugin#ask-hermes-to-install-it" rel="noopener noreferrer"&gt;ready-to-copy installation prompt in the README&lt;/a&gt;&amp;nbsp;contains the full workflow and safety instructions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use and Test the Plugin in Hermes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Use case 1: Create a current AI news briefing
&lt;/h3&gt;

&lt;p&gt;You can start with a prompt as short as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Find latest AI news&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the example below,&amp;nbsp;Hermes turns that request into several focused news&amp;nbsp;searches.&amp;nbsp;It broadens the query to cover major AI companies,&amp;nbsp;chips,&amp;nbsp;safety,&amp;nbsp;and&amp;nbsp;regulation,&amp;nbsp;then uses its other browsing tools to inspect sources and prepare a&amp;nbsp;dated briefing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhgarjs29m2t8v2ko0qu3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhgarjs29m2t8v2ko0qu3.png" alt="Hermes Agent conversation using SerpApi for the prompt:  raw `Find latest AI news.` endraw " width="800" height="742"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Hermes Agent conversation using SerpApi for the prompt: &lt;code&gt;Find latest AI news.&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Hermes uses SerpApi for discovery, then combines the search results with its other tools to check sources and write the final briefing. The stories shown in this example reflect the time of the search and will change.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For a more repeatable briefing,&amp;nbsp;give Hermes a little more direction:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Find the latest AI news.&amp;nbsp;Use multiple focused news searches,&amp;nbsp;verify the&amp;nbsp;leading stories against reputable or primary sources,&amp;nbsp;and give me a concise&amp;nbsp;dated briefing with source links.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is where an agent-native search integration becomes useful:&amp;nbsp;Hermes can run&amp;nbsp;more than one query,&amp;nbsp;refine its search as it learns,&amp;nbsp;and organize the results&amp;nbsp;around the task instead of returning a single page of links.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use case 2: Find the best cafés across Paris
&lt;/h3&gt;

&lt;p&gt;A local search can be just as simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Find best Cafes in Paris&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Rather than treating the whole city as one search,&amp;nbsp;Hermes can explore different&amp;nbsp;neighborhoods and intents.&amp;nbsp;In this example,&amp;nbsp;it searches for specialty coffee&amp;nbsp;and cafés in Le Marais,&amp;nbsp;Saint-Germain-des-Prés,&amp;nbsp;Montmartre,&amp;nbsp;Canal Saint-Martin,&amp;nbsp;and the Latin Quarter before compiling a shortlist.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fquhwuz5kndounaa0d5mv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fquhwuz5kndounaa0d5mv.png" alt="Hermes Agent conversation using SerpApi for the prompt:  raw `Find best Cafes in Paris` endraw " width="800" height="684"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Hermes Agent conversation using SerpApi for the prompt: &lt;code&gt;Find best Cafes in Paris&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The resulting shortlist brings together useful Google Maps details such as ratings, review counts, addresses, price levels, and map references. Local business data can change, so check the live results when planning a visit.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For a more specific recommendation,&amp;nbsp;try:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Find the best cafés in Paris.&amp;nbsp;Search specialty coffee and notable&amp;nbsp;neighborhoods separately,&amp;nbsp;then return a varied shortlist with ratings,&amp;nbsp;review&amp;nbsp;counts,&amp;nbsp;addresses,&amp;nbsp;price levels,&amp;nbsp;and Google Maps links.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hermes can make several focused&amp;nbsp;&lt;code&gt;serpapi_maps_search&lt;/code&gt;&amp;nbsp;calls,&amp;nbsp;compare the&amp;nbsp;structured place results,&amp;nbsp;and turn them into one useful answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  More prompt ideas
&lt;/h3&gt;

&lt;p&gt;Try these prompts for the remaining search paths:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Web:&lt;/strong&gt; &amp;nbsp;"Search the web for the latest Python 3.14 release notes and summarize the important changes with source links."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;News:&lt;/strong&gt; &amp;nbsp;"Show me the most important reusable-rocket news from the past week. Group related coverage and cite the publishers."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shopping:&lt;/strong&gt; &amp;nbsp;"Find well-reviewed laptops under $1,200 with free shipping. Compare prices, ratings, and merchants."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together,&amp;nbsp;these prompts also work as quick smoke tests after installation.&amp;nbsp;Hermes should use&amp;nbsp;&lt;code&gt;web_search&lt;/code&gt;&amp;nbsp;for general research and the dedicated Maps,&amp;nbsp;News,&amp;nbsp;and Shopping tools for their respective requests.&amp;nbsp;Search results change&amp;nbsp;over time,&amp;nbsp;so verify the tool selected and the shape of the response rather&amp;nbsp;than expecting the same listings on every run.&lt;/p&gt;

&lt;p&gt;If Hermes does not find the plugin,&amp;nbsp;check these three points:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The package was installed into the Python environment that runs Hermes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;serpapi&lt;/code&gt;&amp;nbsp;is enabled in&amp;nbsp;&lt;code&gt;hermes plugins&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SERPAPI_API_KEY&lt;/code&gt;&amp;nbsp;is available to the Hermes process and SerpApi is selected as the web search backend.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;The PyPI package publishes a&amp;nbsp;&lt;code&gt;hermes_agent.plugins&lt;/code&gt;&amp;nbsp;entry point.&amp;nbsp;When Hermes&amp;nbsp;discovers and enables the package,&amp;nbsp;the plugin:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Registers SerpApi as a&amp;nbsp;&lt;code&gt;web_search&lt;/code&gt;&amp;nbsp;provider.&lt;/li&gt;
&lt;li&gt;Registers separate Maps, News, and Shopping tools with schemas that describe their supported inputs.&lt;/li&gt;
&lt;li&gt;Selects the corresponding SerpApi engine and validates the request.&lt;/li&gt;
&lt;li&gt;Converts the API response into a compact, predictable result for Hermes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This keeps the integration native to Hermes while preserving the structured&amp;nbsp;search data that makes SerpApi useful for agent workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The SerpApi plugin for Hermes Agent is available now on&amp;nbsp;&lt;a href="https://pypi.org/project/serpapi-hermes-plugin/" rel="noopener noreferrer"&gt;PyPI&lt;/a&gt;,&amp;nbsp;and its source code is&amp;nbsp;open on&amp;nbsp;&lt;a href="https://github.com/serpapi/serpapi-hermes-plugin" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you find a bug or have an idea for another Hermes-native search capability,&amp;nbsp;open an issue or pull request in the repository.&amp;nbsp;If you have not tried SerpApi&amp;nbsp;yet,&amp;nbsp;&lt;a href="https://serpapi.com/users/sign_up" rel="noopener noreferrer"&gt;create an account&lt;/a&gt;&amp;nbsp;and give Hermes live&amp;nbsp;search data in a few minutes.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Amazon ASIN Lookup API: Find and Fetch Product Details</title>
      <dc:creator>Hilman Ramadhan</dc:creator>
      <pubDate>Wed, 29 Jul 2026 02:45:23 +0000</pubDate>
      <link>https://dev.to/serpapi/amazon-asin-lookup-api-find-and-fetch-product-details-25n3</link>
      <guid>https://dev.to/serpapi/amazon-asin-lookup-api-find-and-fetch-product-details-25n3</guid>
      <description>&lt;p&gt;Amazon products are identified by an &lt;strong&gt;ASIN&lt;/strong&gt; , short for &lt;strong&gt;Amazon Standard Identification Number&lt;/strong&gt;. If you're building a product research tool, price monitoring system, competitor tracker, or an Amazon data workflow, the &lt;a href="https://en.wikipedia.org/wiki/Amazon_Standard_Identification_Number" rel="noopener noreferrer"&gt;ASIN&lt;/a&gt; is usually the key identifier you need.&lt;/p&gt;

&lt;p&gt;In this tutorial, we’ll learn how to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Search Amazon products by keyword.&lt;/li&gt;
&lt;li&gt;Extract the ASIN from Amazon search results.&lt;/li&gt;
&lt;li&gt;Use that ASIN to fetch detailed product information.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We’ll use two SerpApi APIs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://serpapi.com/amazon-search-api" rel="noopener noreferrer"&gt;Amazon Search API&lt;/a&gt;: to search Amazon and retrieve product results with ASINs.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://serpapi.com/amazon-product-api" rel="noopener noreferrer"&gt;Amazon Product API&lt;/a&gt;: to look up detailed product data using an ASIN.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fynjo0xz8y5u7igwhl3ue.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fynjo0xz8y5u7igwhl3ue.webp" alt="Amazon ASIN Lookup API method" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Amazon ASIN Lookup API method&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Video Tutorial
&lt;/h2&gt;

&lt;p&gt;We also provide video tutorials for this guide.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Amazon Search Results Scraper:&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/embed/j3YXfsMPKjQ?feature=oembed" rel="noopener noreferrer"&gt;https://www.youtube.com/embed/j3YXfsMPKjQ?feature=oembed&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Amazon Product Detail Scraper:&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/embed/Yd17Jr45liw?feature=oembed" rel="noopener noreferrer"&gt;https://www.youtube.com/embed/Yd17Jr45liw?feature=oembed&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why use an Amazon Search API?
&lt;/h2&gt;

&lt;p&gt;Manually searching Amazon and copying product details is slow. Building your own scraper also means handling HTML changes, blocking, proxies, parsing, and maintenance.&lt;/p&gt;

&lt;p&gt;With an API, you can programmatically look up products and get structured JSON data without the scraping headaches.&lt;/p&gt;

&lt;p&gt;The Amazon Search API uses the endpoint &lt;code&gt;https://serpapi.com/search?engine=amazon&lt;/code&gt;, and the query parameter is &lt;code&gt;k&lt;/code&gt;, which works like a regular Amazon search query.&lt;/p&gt;

&lt;p&gt;You can use this for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/use-cases/product-research-tool-api" rel="noopener noreferrer"&gt;Product research&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/use-cases/price-monitoring" rel="noopener noreferrer"&gt;Price monitoring&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Competitor tracking&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/blog/product-market-research-using-amazon-search-api/" rel="noopener noreferrer"&gt;Marketplace analysis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Product catalog enrichment&lt;/li&gt;
&lt;li&gt;Review and rating monitoring&lt;/li&gt;
&lt;li&gt;Amazon product matching&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/blog/build-an-ai-powered-shopping-catalog-with-serpapi-and-python/" rel="noopener noreferrer"&gt;AI shopping assistants&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Search Amazon products and get ASINs
&lt;/h2&gt;

&lt;p&gt;We're using Python for the tutorial. You can use any programming language you want.&lt;/p&gt;

&lt;p&gt;Install &lt;code&gt;requests&lt;/code&gt; first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new &lt;code&gt;main.py&lt;/code&gt; file. Let’s say we want to search for &lt;code&gt;"coffee"&lt;/code&gt; in Amazon:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="n"&gt;SERPAPI_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_SERPAPI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api_key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SERPAPI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;engine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon_domain&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;k&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;coffee&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://serpapi.com/search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sends a request to the Amazon Search API and returns Amazon search results in JSON format.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;k&lt;/code&gt; parameter defines the Amazon search query, and &lt;code&gt;amazon_domain&lt;/code&gt; lets you choose the Amazon marketplace, such as &lt;code&gt;amazon.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is the example result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffhwd85mlggtzvd41qn4f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffhwd85mlggtzvd41qn4f.png" alt="Amazon ASIN scraper sample result" width="800" height="652"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Amazon ASIN scraper sample result&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can see that we receive the ASIN for each item.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Extract ASINs from Amazon search results
&lt;/h2&gt;

&lt;p&gt;Amazon Search API results can include product fields like &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;link&lt;/code&gt;, &lt;code&gt;thumbnail&lt;/code&gt;, &lt;code&gt;rating&lt;/code&gt;, and &lt;code&gt;reviews&lt;/code&gt;. Products inside Amazon results include an &lt;code&gt;ASIN&lt;/code&gt; field and a &lt;code&gt;serpapi_link&lt;/code&gt; pointing to the Amazon Product API lookup for that ASIN.&lt;/p&gt;

&lt;p&gt;Let’s print a cleaner list of products:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="n"&gt;SERPAPI_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_SERPAPI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api_key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SERPAPI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;engine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon_domain&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;k&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;coffee&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://serpapi.com/search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;organic_results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]):&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;asin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;asin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;rating&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rating&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;reviews&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reviews&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Title: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ASIN: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;asin&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Price: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Rating: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;rating&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Reviews: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;reviews&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Title: Amazon Fresh, Colombia Ground Coffee, Medium Roast, 32 Oz
ASIN: B072MQ5BRX
Price: $15.31
Rating: 4.5
Reviews: 7823
--------------------------------------------------
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have the ASIN. Next, we can use it to get more complete product details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Look up product details by ASIN
&lt;/h2&gt;

&lt;p&gt;The Amazon Product API uses &lt;code&gt;engine=amazon_product&lt;/code&gt; and requires an &lt;code&gt;asin&lt;/code&gt; parameter. The request returns a &lt;code&gt;product_results&lt;/code&gt; object containing fields like &lt;code&gt;asin&lt;/code&gt;, &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;tags&lt;/code&gt;, &lt;code&gt;badges&lt;/code&gt;, variants, brand, links, thumbnails, and more.&lt;/p&gt;

&lt;p&gt;Here’s how to look up a product by ASIN:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="n"&gt;SERPAPI_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_SERPAPI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api_key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SERPAPI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;engine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon_product&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;asin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;B072MQ5BRX&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://serpapi.com/search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let’s print only the most useful product details:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="n"&gt;SERPAPI_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_SERPAPI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api_key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SERPAPI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;engine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon_product&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon_domain&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;asin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;B072MQ5BRX&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://serpapi.com/search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;product_results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Title: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ASIN: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;asin&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Brand: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;brand&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Rating: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rating&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Reviews: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;reviews&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Price: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Link: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;link&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Complete example: Search Amazon, get the first ASIN, then fetch product details
&lt;/h2&gt;

&lt;p&gt;In many cases, you don’t already know the ASIN. You only have a keyword, a product name, a brand, or a category.&lt;/p&gt;

&lt;p&gt;Here’s a complete workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="n"&gt;SERPAPI_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;YOUR_SERPAPI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;search_amazon_products&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api_key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SERPAPI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;engine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon_domain&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;k&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://serpapi.com/search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_amazon_product_by_asin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;asin&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api_key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SERPAPI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;engine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon_product&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon_domain&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amazon.com&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;asin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;asin&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://serpapi.com/search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="n"&gt;search_results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;search_amazon_products&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;coffee&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;first_product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;search_results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;organic_results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;asin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;first_product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;asin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Found ASIN: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;asin&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Product title: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;first_product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;product_details&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_amazon_product_by_asin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;asin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;product_details&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;product_results&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Product Details&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Title: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Brand: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;brand&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Price: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;price&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Rating: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rating&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Reviews: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;reviews&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  JavaScript example
&lt;/h2&gt;

&lt;p&gt;You can also do the same thing in JavaScript.&lt;/p&gt;

&lt;p&gt;Install the SerpApi package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;serpapi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create an &lt;code&gt;index.js&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getJson&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;serpapi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;YOUR_SERPAPI_API_KEY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;searchAmazonProducts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;getJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;amazon&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;amazon_domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;amazon.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getAmazonProductByAsin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;asin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;getJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;amazon_product&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;amazon_domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;amazon.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;asin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;searchResults&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;searchAmazonProducts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;coffee&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstProduct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;searchResults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;organic_results&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;firstProduct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No product found.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;asin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;firstProduct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;asin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Found ASIN:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;asin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Product title:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;firstProduct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;productDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAmazonProductByAsin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;asin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;productDetails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;product_results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Product Details&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Title:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Brand:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;brand&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Price:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Rating:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Reviews:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;reviews&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Useful parameters
&lt;/h2&gt;

&lt;p&gt;For Amazon Search API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"engine"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"amazon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"amazon_domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"amazon.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"k"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"coffee"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful parameters include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;k&lt;/code&gt;: the Amazon search query.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;amazon_domain&lt;/code&gt;: the Amazon marketplace to use.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;language&lt;/code&gt;: the Amazon search language.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;delivery_zip&lt;/code&gt;: ZIP or postal code for shipping-based results.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;shipping_location&lt;/code&gt;: shipping country.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;s&lt;/code&gt;: sorting option.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Amazon Search API supports sorting options such as featured, price low to high, price high to low, average customer review, newest arrivals, and best sellers.&lt;/p&gt;

&lt;h2&gt;
  
  
  What data can you get from an ASIN lookup?
&lt;/h2&gt;

&lt;p&gt;Depending on the product and Amazon page, the Amazon Product API can return structured data such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Product title&lt;/li&gt;
&lt;li&gt;ASIN&lt;/li&gt;
&lt;li&gt;Brand&lt;/li&gt;
&lt;li&gt;Description&lt;/li&gt;
&lt;li&gt;Product images&lt;/li&gt;
&lt;li&gt;Price&lt;/li&gt;
&lt;li&gt;Rating&lt;/li&gt;
&lt;li&gt;Reviews&lt;/li&gt;
&lt;li&gt;Badges&lt;/li&gt;
&lt;li&gt;Variants&lt;/li&gt;
&lt;li&gt;Product details&lt;/li&gt;
&lt;li&gt;Product features&lt;/li&gt;
&lt;li&gt;Buying options&lt;/li&gt;
&lt;li&gt;Other sellers&lt;/li&gt;
&lt;li&gt;Related products&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;An Amazon ASIN lookup workflow usually has two steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use the &lt;strong&gt;Amazon Search API&lt;/strong&gt; to search Amazon and find product ASINs.&lt;/li&gt;
&lt;li&gt;Use the &lt;strong&gt;Amazon Product API&lt;/strong&gt; to fetch detailed product information from a specific ASIN.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This makes it easier to build product research tools, price trackers, marketplace dashboards, AI shopping assistants, and catalog enrichment workflows without maintaining your own &lt;a href="https://serpapi.com/blog/scrape-amazon-product-data-tutorial/" rel="noopener noreferrer"&gt;Amazon scraper&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can try the APIs here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/amazon-search-api" rel="noopener noreferrer"&gt;Amazon Search API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/amazon-product-api" rel="noopener noreferrer"&gt;Amazon Product API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How I Built a Star Wars Grogu Product Research Agent with Codex, Lark, and SerpApi</title>
      <dc:creator>Magenta Qin</dc:creator>
      <pubDate>Tue, 28 Jul 2026 09:42:36 +0000</pubDate>
      <link>https://dev.to/serpapi/how-i-built-a-star-wars-grogu-product-research-agent-with-codex-lark-and-serpapi-lmg</link>
      <guid>https://dev.to/serpapi/how-i-built-a-star-wars-grogu-product-research-agent-with-codex-lark-and-serpapi-lmg</guid>
      <description>&lt;p&gt;Cross-border e-commerce sellers often spend hours comparing the same products across different Amazon marketplaces. Prices, reviews, and seller signals vary by country, but the process is still largely manual.&lt;/p&gt;

&lt;p&gt;I wanted to see how far I could automate it with a small AI agent built using Codex, SerpApi, and Lark.&lt;/p&gt;

&lt;p&gt;Suppose I ask in Codex:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Compare Grogu products in the US and Japan&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The workflow is straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;search Amazon marketplaces&lt;/li&gt;
&lt;li&gt;fetch product details&lt;/li&gt;
&lt;li&gt;summarize seller signals&lt;/li&gt;
&lt;li&gt;send a report to Lark&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I kept the stack intentionally simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Python 3.12&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;uv&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pydantic&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SerpApi Python SDK&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OpenAI structured outputs&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lark custom bot webhook&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codex&lt;/strong&gt; for both development and as the conversational interface&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Running the Agent from Codex&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Once everything was wired together, I could simply ask Codex:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Compare Grogu products in the US and Japan&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Codex understood the request, triggered the CLI workflow, collected marketplace data via SerpApi, and delivered a structured report to Lark.&lt;/p&gt;

&lt;p&gt;Here’s the entire flow in action:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;0:00&lt;br&gt;
/0:16&lt;br&gt;
1×&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Workflow
&lt;/h2&gt;

&lt;p&gt;The overall flow looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgy109zua3alr0bd1tmuv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgy109zua3alr0bd1tmuv.png" width="800" height="1200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Starting with a natural-language request in Codex, the agent first validates that the question is related to cross-border Amazon research.&lt;/p&gt;

&lt;p&gt;OpenAI then translates the request into a structured command. SerpApi handles both product discovery and detailed product retrieval, while OpenAI extracts seller-focused insights from the collected data.&lt;/p&gt;

&lt;p&gt;Finally, the results are packaged into a Lark card and delivered via a Custom Bot webhook.&lt;/p&gt;

&lt;p&gt;I intentionally did not start with FastAPI, background jobs, or a database. For the MVP, the important question was simpler: Can I go from a natural-language product question to a useful cross-border product card?&lt;/p&gt;

&lt;h2&gt;
  
  
  Translating Natural Language into Commands
&lt;/h2&gt;

&lt;p&gt;The natural-language entrypoint uses OpenAI to translate user requests into structured commands.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb2z2mq9p1ckeopv993fj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb2z2mq9p1ckeopv993fj.png" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Compare Grogu products in the US and Japan&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;query&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Grogu"&lt;/span&gt; 
&lt;span class="nv"&gt;marketplaces&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;&lt;span class="s2"&gt;"us"&lt;/span&gt;,&lt;span class="s2"&gt;"jp"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; 
&lt;span class="nv"&gt;output_mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"send_lark"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using a strict schema keeps the pipeline predictable and much easier to debug. Instead of letting the model orchestrate everything, I only ask it to generate structured commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Searching Amazon with SerpApi
&lt;/h2&gt;

&lt;p&gt;This project relies on two SerpApi endpoints.&lt;/p&gt;

&lt;p&gt;The Amazon Search API is used to discover candidate products, while the Amazon Product API enriches them with much richer details.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg0mkr0i9nwzl08s5pdeg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg0mkr0i9nwzl08s5pdeg.png" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Search results provide ranking context and thumbnails, while product pages contain detailed information such as images, availability, and descriptions.&lt;/p&gt;

&lt;p&gt;Combining both produced much better product cards than using either endpoint alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modeling Product Data
&lt;/h2&gt;

&lt;p&gt;Amazon pages are messy.&lt;/p&gt;

&lt;p&gt;Some products have ratings but no availability.&lt;/p&gt;

&lt;p&gt;Some have images but no variants.&lt;/p&gt;

&lt;p&gt;Some fields simply don't exist.&lt;/p&gt;

&lt;p&gt;Missing data is normal, not an exception.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk63xzwpj5zy05lksqhr7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk63xzwpj5zy05lksqhr7.png" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My first instinct was to say, "Why not model most fields as optional?" That is true, but it is not the whole solution.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;The real issue was that SerpApi returns useful product data from several different places.&lt;/strong&gt; Some fields are flat. Some fields are nested. Some fields have different names depending on whether they came from Amazon Search API or Amazon Product API. Some products should not be shown at all if they are missing the signals a seller actually needs.&lt;/p&gt;

&lt;p&gt;To make the data usable, I:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;normalized both endpoints into a common &lt;code&gt;Product&lt;/code&gt; model;&lt;/li&gt;
&lt;li&gt;filtered out products with weak seller signals;&lt;/li&gt;
&lt;li&gt;merged Product API details back into search results;&lt;/li&gt;
&lt;li&gt;treated missing fields as expected rather than failures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;Product&lt;/code&gt; model still uses optional fields, because missing data is normal:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7on39v7aohn00snze6b4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7on39v7aohn00snze6b4.png" width="800" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But optional fields alone were not enough. I also filtered search results before choosing products for detail lookup:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fol0lnzkt5qmxiikaym56.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fol0lnzkt5qmxiikaym56.png" width="800" height="199"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was important for the Lark card. A cross-border seller does not want a table full of &lt;code&gt;Rating: N/A&lt;/code&gt; and &lt;code&gt;Reviews: N/A&lt;/code&gt;. Those rows make the card noisy and less actionable.&lt;br&gt;&lt;br&gt;
The next issue was nested and inconsistent JSON.&lt;br&gt;&lt;br&gt;
For price, SerpApi may return a string, a number-like value, or a nested object:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb2j2sfm0qblqgpovxk2q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb2j2sfm0qblqgpovxk2q.png" width="799" height="205"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For availability, the Product API does not always use one stable field. I had to check &lt;code&gt;availability&lt;/code&gt;, &lt;code&gt;stock&lt;/code&gt;, and sometimes &lt;code&gt;delivery&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Folqa25sibiv1x4e1n13t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Folqa25sibiv1x4e1n13t.png" width="799" height="261"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping the Agent Narrow
&lt;/h2&gt;

&lt;p&gt;The most interesting part of the project isn't Grogu.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's scope.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The entrypoint only supports cross-border Amazon product research.&lt;/p&gt;

&lt;p&gt;If somebody asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What is today's weather?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;the app simply rejects the request.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffpvc3b9rfdebsu1cp5i9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffpvc3b9rfdebsu1cp5i9.png" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Requests outside the project scope are rejected locally before calling OpenAI.&lt;/p&gt;

&lt;p&gt;For supported requests, OpenAI returns a strict command object:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdu5fi54k96r6jhf3ocl7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdu5fi54k96r6jhf3ocl7.png" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This keeps the agent predictable. It translates requests into commands instead of improvising actions.&lt;/p&gt;

&lt;p&gt;I deliberately avoided turning this into a general chatbot.The agent only knows one workflow: cross-border Amazon product research.That narrow scope makes the behavior easier to explain, test, and trust. It also keeps OpenAI API responsible for translation rather than improvisation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating Seller-Friendly Insights and Delivering Them to Lark
&lt;/h2&gt;

&lt;p&gt;Once product data has been collected, OpenAI generates seller-focused insights. I intentionally constrain the model to use only information returned by the APIs, avoiding hallucinated prices, ratings, or availability.&lt;/p&gt;

&lt;p&gt;Instead of producing generic summaries, the analysis focuses on demand signals, social proof, pricing, and obvious risks — information that is much more useful for sellers.&lt;/p&gt;

&lt;p&gt;The final result is delivered through a Lark Custom Bot webhook.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frkbdwwxy2tm6mewsa0w4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frkbdwwxy2tm6mewsa0w4.png" width="799" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Error Handling
&lt;/h2&gt;

&lt;p&gt;External APIs fail. That's normal.&lt;/p&gt;

&lt;p&gt;I treated each layer independently.&lt;/p&gt;

&lt;p&gt;If OpenAI fails, no command is generated.&lt;/p&gt;

&lt;p&gt;If SerpApi fails, the analysis stops with a clear message.&lt;/p&gt;

&lt;p&gt;If Lark delivery fails, the report can still be viewed locally.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqg7mcfl78g6rsuxlcrds.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqg7mcfl78g6rsuxlcrds.png" width="800" height="541"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This separation keeps failures localized and prevents one component from bringing down the entire workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The most interesting lesson from this project wasn’t the Grogu theme or the Lark card.&lt;/p&gt;

&lt;p&gt;It was learning where the boundaries should be.&lt;/p&gt;

&lt;p&gt;The agent works because it stays narrow.&lt;/p&gt;

&lt;p&gt;That narrowness makes the system easier to understand, debug, and trust.&lt;/p&gt;

&lt;p&gt;And if you’re building tools for cross-border e-commerce, &lt;a href="https://serpapi.com/amazon-search-api" rel="noopener noreferrer"&gt;SerpApi’s Amazon API&lt;/a&gt; provide a surprisingly rich source of product data. They made this entire workflow possible.&lt;/p&gt;

&lt;p&gt;If you’re working on product research, seller analytics, or marketplace intelligence, I’d recommend giving them a try.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
