<?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>How to Scrape Walmart Reviews Results</title>
      <dc:creator>Noraina Nordin</dc:creator>
      <pubDate>Wed, 02 Sep 2026 04:55:27 +0000</pubDate>
      <link>https://dev.to/serpapi/how-to-scrape-walmart-reviews-results-hb6</link>
      <guid>https://dev.to/serpapi/how-to-scrape-walmart-reviews-results-hb6</guid>
      <description>&lt;p&gt;Customer reviews are one of the richest signals Walmart provides. Ratings, review text, and helpfulness feedback tell you what buyers actually think about a product, where it delights, where it disappoints, and which features drive or sink a purchase. In this tutorial, you'll learn how to scrape Walmart review results using a simple API from SerpApi's &lt;a href="https://serpapi.com/walmart-product-reviews-api" rel="noopener noreferrer"&gt;Walmart Product Reviews API&lt;/a&gt;, page through every review for a product, and export the results to CSV for analysis.&lt;/p&gt;

&lt;p&gt;This is a companion to our main guide, &lt;a href="https://serpapi.com/blog/how-to-scrape-walmart-data/" rel="noopener noreferrer"&gt;How to Scrape Walmart&lt;/a&gt;, which covers scraping search listings and product details. If you already have a &lt;code&gt;product_id&lt;/code&gt;, you can jump straight in below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why scrape Walmart reviews?
&lt;/h2&gt;

&lt;p&gt;A single product page can hold hundreds of reviews, and at scale that feedback becomes a dataset. By scraping Walmart reviews, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run sentiment analysis to understand how buyers feel about a product over time.&lt;/li&gt;
&lt;li&gt;Monitor recurring complaints and feature requests to inform product or sourcing decisions.&lt;/li&gt;
&lt;li&gt;Compare review sentiment and ratings across competing products before stocking or dropshipping.&lt;/li&gt;
&lt;li&gt;Track how ratings shift after a price change, a new variant, or a seller switch.&lt;/li&gt;
&lt;li&gt;Feed structured review text into downstream models for summarization or classification.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For e-commerce teams, analysts, and automation builders, review data turns anecdotal feedback into something you can measure and act on.&lt;/p&gt;

&lt;h2&gt;
  
  
  What can you extract from Walmart product reviews?
&lt;/h2&gt;

&lt;p&gt;The Walmart Product Reviews API returns two things at once. A summary of a product's overall review profile and the individual reviews themselves. Here's what's available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Product info:&lt;/strong&gt; The product name, its Walmart URL, and the category path it sits in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overall rating:&lt;/strong&gt; The product's average star rating across all reviews (for example, 4.6).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Total review count:&lt;/strong&gt; The total number of reviews for the product. It is useful for gauging sample size or weighting sentiment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rating distribution:&lt;/strong&gt; A breakdown of how many reviews fall under each star level, 1 through 5, so you can see the &lt;em&gt;shape&lt;/em&gt; of sentiment at a glance rather than just the average.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Top positive review:&lt;/strong&gt; The highest-rated review that other customers found most helpful.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Top negative review:&lt;/strong&gt; The lowest-rated review that customers found most helpful. Often, the most actionable complaints surface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Individual reviews:&lt;/strong&gt; For every review on the page, you get the title, full review text, star rating, positive and negative feedback counts (how many users up- or down-voted it), submission date, reviewer nickname, and customer type (such as &lt;code&gt;VerifiedPurchaser&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also &lt;strong&gt;filter by star rating&lt;/strong&gt; (1 - 5) and &lt;strong&gt;sort&lt;/strong&gt; the results by relevancy, helpfulness, newest or oldest submission, or highest or lowest rating to pull exactly the slice of feedback you need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use an API?
&lt;/h2&gt;

&lt;p&gt;Reviews are paginated, rendered dynamically, and protected by the same anti-bot measures as the rest of Walmart, so a DIY scraper means maintaining pagination logic, rotating proxies, and patching parsers every time the markup shifts.&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://serpapi.com/" rel="noopener noreferrer"&gt;SerpApi&lt;/a&gt;, that overhead disappears. The Walmart Product Reviews API returns clean, structured review data. No browser automation, no HTML parsing, and get fast response times. You can see live response times and success rates on the &lt;a href="https://serpapi.com/walmart-product-reviews-api/api-metrics" rel="noopener noreferrer"&gt;SerpApi Status page&lt;/a&gt;. For the full picture on scraping Walmart search and product pages, see the &lt;a href="https://serpapi.com/blog/how-to-scrape-walmart-data/" rel="noopener noreferrer"&gt;complete Walmart scraping guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting the product_id
&lt;/h2&gt;

&lt;p&gt;To pull reviews for a product, you need to pass the &lt;code&gt;product_id&lt;/code&gt; parameter. You can get it from:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The Walmart product URL itself.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&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%2Fkleorhjfg7jijvuvog9g.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%2Fkleorhjfg7jijvuvog9g.png" alt="Walmart product_id from URL" width="800" height="30"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Walmart product_id from URL&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Walmart Search results.&lt;/strong&gt; If you're working from search data, extract the &lt;code&gt;product_id&lt;/code&gt; from each organic result. See the &lt;a href="https://serpapi.com/blog/how-to-scrape-walmart-data/" rel="noopener noreferrer"&gt;main Walmart guide&lt;/a&gt; for how to scrape those listings.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can test any &lt;code&gt;product_id&lt;/code&gt; on our &lt;a href="https://serpapi.com/playground?engine=walmart_product_reviews" rel="noopener noreferrer"&gt;interactive playground&lt;/a&gt; before writing a line of code.&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%2F7bp6r1gakul2z3c9dmx4.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%2F7bp6r1gakul2z3c9dmx4.png" alt="Walmart product reviews API playground" width="799" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Walmart product reviews API playground&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;To learn more about the parameters, visit the &lt;a href="https://serpapi.com/walmart-product-reviews-api" rel="noopener noreferrer"&gt;Walmart Reviews API documentation&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%2Fbpn51xhpwc0q5ql00lbs.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%2Fbpn51xhpwc0q5ql00lbs.png" alt="Walmart Reviews API documentation" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Walmart Reviews API documentation&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to scrape Walmart reviews
&lt;/h2&gt;

&lt;p&gt;If you have your API key, you're ready to start pulling review data from Walmart. The results will be identical across every method below, so use whichever one you prefer.&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%2F1owdwqe3ig12xs4o2723.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%2F1owdwqe3ig12xs4o2723.png" alt="Walmart product reviews page" width="800" height="616"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Walmart product reviews page&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For every review on the page, we'll extract the "title", "rating", "review text", "positive and negative feedback", "review submission time", "user nickname", and "customer type".&lt;/p&gt;

&lt;h3&gt;
  
  
  GET request
&lt;/h3&gt;

&lt;p&gt;This fetches the first page of reviews for a specific product (&lt;code&gt;product_id&lt;/code&gt;), straight from the &lt;code&gt;search.json&lt;/code&gt; endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://serpapi.com/search.json?engine=walmart_product_reviews&amp;amp;product_id=2205851521&amp;amp;page=1&amp;amp;api_key=SERPAPI_API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Increment the &lt;code&gt;page&lt;/code&gt; parameter to move through additional pages of reviews. By default, each page returns 20 reviews.&lt;/p&gt;

&lt;h3&gt;
  
  
  Python Tutorial
&lt;/h3&gt;

&lt;p&gt;The examples below use the official &lt;a href="https://serpapi.com/integrations/python" rel="noopener noreferrer"&gt;SerpApi Python library&lt;/a&gt;. This is the most thorough walkthrough. It also covers paging through every review and exporting the results to CSV.&lt;/p&gt;

&lt;h4&gt;
  
  
  Setup
&lt;/h4&gt;

&lt;p&gt;After installing the &lt;a href="https://github.com/serpapi/serpapi-python" rel="noopener noreferrer"&gt;&lt;code&gt;serpapi-python&lt;/code&gt;&lt;/a&gt; package, import the libraries and load your API key.&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="kn"&gt;import&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;csv&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: Make sure you create a &lt;code&gt;.env&lt;/code&gt; file to store your API key.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Define the parameters. The &lt;code&gt;page&lt;/code&gt; parameter is optional. By default, one page returns 20 reviews.&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;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;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&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;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;walmart_product_reviews&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;product_id&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;2205851521&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;page&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initialize the SerpApi client:&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;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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Send the Walmart product reviews request:&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;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="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Parse the reviews
&lt;/h4&gt;

&lt;p&gt;Loop through the reviews on the page and print each field:&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;reviews&lt;/span&gt; &lt;span class="o"&gt;=&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;reviews&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="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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;review&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;reviews&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;review&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;review_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;review&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;text&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;review&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;positive_feedback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;review&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;positive_feedback&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;negative_feedback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;review&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;negative_feedback&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;review_submission_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;review&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;review_submission_time&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_nickname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;review&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;user_nickname&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;customer_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;review&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;customer_type&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;Review text: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;review_text&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;Positive feedback: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;positive_feedback&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;Negative feedback: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;negative_feedback&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;Review submission time: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;review_submission_time&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;User nickname: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;user_nickname&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;Customer type: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;customer_type&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;h4&gt;
  
  
  The output
&lt;/h4&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%2Fhccnoz0gk8sakqddy05o.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%2Fhccnoz0gk8sakqddy05o.png" alt="Walmart product reviews results in terminal" width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Walmart product reviews results in terminal&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Scrape every page of reviews
&lt;/h4&gt;

&lt;p&gt;A single request returns one page (20 reviews). Popular products have many pages, so to collect all of them you can increment the &lt;code&gt;page&lt;/code&gt; parameter until the API stops returning reviews. We add a &lt;code&gt;max_pages&lt;/code&gt; cap so the loop always terminates:&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;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;all_reviews&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;max_pages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;  &lt;span class="c1"&gt;# safety cap so the loop can't run away
&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;max_pages&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;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&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;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;walmart_product_reviews&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;product_id&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;2205851521&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;page&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;page&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="n"&gt;params&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;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;reviews&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="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;reviews&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;

    &lt;span class="n"&gt;all_reviews&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reviews&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;Page &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: collected &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;reviews&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 (total: &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;all_reviews&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="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&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;Done. Collected &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;all_reviews&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 in total.&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;h4&gt;
  
  
  Export the reviews to CSV
&lt;/h4&gt;

&lt;p&gt;Printing to the terminal is useful for debugging, but in real workflows you'll want the data saved for analysis. Here's how to write every collected review to a CSV file you can open in Excel or Google Sheets:&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;header&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="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;text&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;positive_feedback&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;negative_feedback&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;review_submission_time&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_nickname&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;customer_type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;walmart_reviews.csv&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;w&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;UTF8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newline&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="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writerow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&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;review&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;all_reviews&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writerow&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="n"&gt;review&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;review&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;review&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;text&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;review&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;positive_feedback&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;review&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;negative_feedback&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;review&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;review_submission_time&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;review&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;user_nickname&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;review&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;customer_type&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;You now have a clean, structured CSV containing every review for the product, ready for sentiment analysis, dashboards, or cross-product comparisons.&lt;/p&gt;

&lt;h3&gt;
  
  
  JavaScript and Node.js
&lt;/h3&gt;

&lt;p&gt;This example uses the &lt;a href="https://serpapi.com/integrations/javascript" rel="noopener noreferrer"&gt;SerpApi JavaScript library&lt;/a&gt; to fetch the first page of reviews for a product and print the title, rating, and text of each one:&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="s1"&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;search&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="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;walmart_product_reviews&lt;/span&gt;&lt;span class="dl"&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;SERPAPI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2205851521&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;page&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="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;review&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;reviews&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="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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;review&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;review&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="s2"&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;review&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&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;-&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&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 collect every review, increment the &lt;code&gt;page&lt;/code&gt; value until the API stops returning results:&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="s1"&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;allReviews&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;page&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;maxPages&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;span class="c1"&gt;// safety cap so the loop can't run away&lt;/span&gt;

&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;maxPages&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;search&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="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;walmart_product_reviews&lt;/span&gt;&lt;span class="dl"&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;SERPAPI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2205851521&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;page&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;reviews&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;reviews&lt;/span&gt; &lt;span class="o"&gt;??&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="nx"&gt;reviews&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&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;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;allReviews&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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="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="s2"&gt;`Page &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: collected &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="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; reviews (total: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;allReviews&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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;page&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="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="s2"&gt;`Done. Collected &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;allReviews&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; reviews in total.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  cURL
&lt;/h3&gt;

&lt;p&gt;This fetches the first page of reviews for a specific product:&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; https://serpapi.com/search &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_KEY_GOES_HERE"&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;"walmart_product_reviews"&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;product_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"2205851521"&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;page&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Other languages and no-code solutions
&lt;/h3&gt;

&lt;p&gt;You can use the API directly with GET requests even if there isn't an official SerpApi integration for your language. SerpApi also works with &lt;a href="https://serpapi.com/blog/announcing-serpapis-make-app/" rel="noopener noreferrer"&gt;Make.com&lt;/a&gt;, &lt;a href="https://serpapi.com/blog/boost-your-n8n-workflows-with-serpapis-verified-node/" rel="noopener noreferrer"&gt;n8n&lt;/a&gt;, and other no-code tools.&lt;/p&gt;

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

&lt;p&gt;Walmart reviews are a high-signal, high-volume source of customer feedback, but scraping them reliably means wrestling with pagination and anti-bot protections. In this tutorial, we used SerpApi's Walmart Product Reviews API to skip that overhead and pull structured review data directly. You learned how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Find the &lt;code&gt;product_id&lt;/code&gt; you need to query reviews&lt;/li&gt;
&lt;li&gt;Retrieve and parse reviews for a specific product&lt;/li&gt;
&lt;li&gt;Page through every review with a bounded loop&lt;/li&gt;
&lt;li&gt;Export the results to CSV for downstream analysis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Want the full workflow including search listings and product details as well as reviews? Read the &lt;a href="https://serpapi.com/blog/how-to-scrape-walmart-data/" rel="noopener noreferrer"&gt;complete guide to scraping Walmart&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ready to start collecting Walmart review data without maintaining a scraper? &lt;a href="https://serpapi.com/users/sign_up?utm_source=blog" rel="noopener noreferrer"&gt;Create your free SerpApi account&lt;/a&gt; today.&lt;/p&gt;

&lt;p&gt;Contact us at &lt;a href="mailto:contact@serpapi.com"&gt;contact@serpapi.com&lt;/a&gt; if you have any questions.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Understanding HTTP 429: Too Many Requests</title>
      <dc:creator>Josef Strzibny</dc:creator>
      <pubDate>Mon, 31 Aug 2026 20:46:16 +0000</pubDate>
      <link>https://dev.to/serpapi/understanding-http-429-too-many-requests-40nm</link>
      <guid>https://dev.to/serpapi/understanding-http-429-too-many-requests-40nm</guid>
      <description>&lt;p&gt;HTTP 429 Too Many Requests is the status code a server returns when a client exceeds a rate limit for a given URL. This often happens when exhausting API quotas or when scraping public web pages too aggressively. The error doesn't necessarily say that requesting the resource isn't allowed, but rather points out that the server cannot handle more requests like that at the moment. Let's go and understand what this code means exactly and how to make it go away.&lt;/p&gt;

&lt;h2&gt;
  
  
  HTTP status codes
&lt;/h2&gt;

&lt;p&gt;HTTP status codes tell clients what happened with the request they sent. They are grouped by their first digit into 5 categories. The group tells a client whether a request succeeded, requires another step, or failed:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Range&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Common examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1xx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Informational response while processing continues&lt;/td&gt;
&lt;td&gt;&lt;code&gt;100 Continue&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;2xx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The request succeeded&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;200 OK&lt;/code&gt;, &lt;code&gt;201 Created&lt;/code&gt;, &lt;code&gt;204 No Content&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;3xx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The client needs to follow a redirect or use cached content&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;301 Moved Permanently&lt;/code&gt;, &lt;code&gt;304 Not Modified&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;4xx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The client must change something about the request or its behavior&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;400 Bad Request&lt;/code&gt;, &lt;code&gt;401 Unauthorized&lt;/code&gt;, &lt;code&gt;404 Not Found&lt;/code&gt;, &lt;code&gt;429 Too Many Requests&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;5xx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The server failed to complete an otherwise valid request&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;500 Internal Server Error&lt;/code&gt;, &lt;code&gt;502 Bad Gateway&lt;/code&gt;, &lt;code&gt;503 Service Unavailable&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;HTTP 429 belongs to the &lt;code&gt;4xx&lt;/code&gt; group because the client is expected to change its behavior by sending fewer requests or waiting before trying again. It does not necessarily mean the request data is malformed or that the server is broken.&lt;/p&gt;

&lt;p&gt;A request can be valid and still receive a 429 because it arrived after the client's allowed quota had been exhausted.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTP 429: Too Many Requests
&lt;/h3&gt;

&lt;p&gt;You might encounter this error while calling an API, &lt;a href="https://serpapi.com/blog/web-scraping-with-ruby/" rel="noopener noreferrer"&gt;scraping a website&lt;/a&gt;, submitting forms, polling for updates, or running several background jobs at once. The request may be perfectly valid. The problem is how frequently the requests are being sent.&lt;/p&gt;

&lt;p&gt;A typical response looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt; &lt;span class="m"&gt;429&lt;/span&gt; &lt;span class="ne"&gt;Too Many Requests&lt;/span&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/json&lt;/span&gt;
&lt;span class="na"&gt;Retry-After&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;60&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rate_limit_exceeded"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Try again in 60 seconds"&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;The server is telling the client to slow down. Retrying the same request immediately usually extends the problem rather than fixing it.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTP 429 versus HTTP 503
&lt;/h3&gt;

&lt;p&gt;Both status codes call for controlled retries. The distinction matters for monitoring as repeated 429 responses usually point to client behavior or plan limits, while widespread 503 responses usually indicate a server-side availability problem.&lt;/p&gt;

&lt;p&gt;Here's the main difference between these two error status codes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP 429 means the client has exceeded a limit. The response is usually specific to an API key, account, IP address, or request pattern.&lt;/li&gt;
&lt;li&gt;HTTP 503, known as &lt;code&gt;Service Unavailable&lt;/code&gt;, generally means the service itself cannot handle the request because it is overloaded or undergoing maintenance. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why servers return HTTP 429
&lt;/h2&gt;

&lt;p&gt;Rate limits protect services from accidental overload, abusive traffic, and unexpectedly expensive workloads. They also help providers distribute limited capacity fairly among users.&lt;/p&gt;

&lt;p&gt;Common causes include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sending too many requests per second or minute&lt;/li&gt;
&lt;li&gt;Running more concurrent requests than an API plan permits&lt;/li&gt;
&lt;li&gt;Sharing one API key across too many workers&lt;/li&gt;
&lt;li&gt;Polling an endpoint more frequently than necessary&lt;/li&gt;
&lt;li&gt;Retrying failed requests immediately and without a limit&lt;/li&gt;
&lt;li&gt;Scraping pages faster than a website can reasonably serve them&lt;/li&gt;
&lt;li&gt;Exceeding a daily or monthly account quota&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Not every limit is based on an IP address. A service may limit requests by API key, account, endpoint, user, geographic region, or a combination of these factors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check the Retry-After header
&lt;/h2&gt;

&lt;p&gt;A 429 response may include a &lt;code&gt;Retry-After&lt;/code&gt; header telling the client when it can try again. The value can be a number of seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Retry-After: 60
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But it can also be an HTTP date:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Retry-After: Wed, 26 Aug 2026 14:30:00 GMT
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clients should support both formats when possible.&lt;/p&gt;

&lt;p&gt;Some APIs also return headers describing the active limit, remaining requests, and reset time. Header names vary between providers, so check the API documentation instead of assuming one universal format.&lt;/p&gt;

&lt;p&gt;A 503 response may also contain &lt;code&gt;Retry-After&lt;/code&gt;, but reducing one client's request rate might not resolve the underlying outage.&lt;/p&gt;

&lt;h2&gt;
  
  
  How clients should handle HTTP 429
&lt;/h2&gt;

&lt;p&gt;The correct response to receiving the &lt;em&gt;Too Many Requests&lt;/em&gt; status code is to reduce pressure on the server immediately and be more mindful in the future.&lt;/p&gt;

&lt;h3&gt;
  
  
  Respect Retry-After
&lt;/h3&gt;

&lt;p&gt;Do not retry before the server's requested delay has passed. If several workers receive a 429 together, add a small random delay so they do not all retry at exactly the same moment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use exponential backoff and jitter
&lt;/h3&gt;

&lt;p&gt;When &lt;code&gt;Retry-After&lt;/code&gt; is not specified, increase the delay after every failure. If that doesn't help, increase it again exponentially. You can also consider adding jitter which adds randomness to each delay. This prevents synchronized clients from creating another traffic spike when the waiting period ends.&lt;/p&gt;

&lt;h3&gt;
  
  
  Limit retries
&lt;/h3&gt;

&lt;p&gt;A retry loop must have a maximum number of attempts. Permanent account quotas, invalid plans, and strict website limits will not be fixed by retrying forever.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reduce concurrency
&lt;/h3&gt;

&lt;p&gt;A scraper with many workers can exceed a limit even when each worker appears slow. Use a shared rate limiter or queue so all processes follow the same request budget.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cache and batch requests
&lt;/h3&gt;

&lt;p&gt;Avoid requesting the same resource repeatedly. Cache responses when freshness requirements allow it, combine requests when an API supports batching, and stop polling when the result is no longer needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authenticate correctly
&lt;/h3&gt;

&lt;p&gt;Anonymous requests often have lower limits than authenticated ones. Confirm that the API key is present, belongs to the expected account, and is not being shared unintentionally across environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrying a 429 response
&lt;/h2&gt;

&lt;p&gt;Here's a simplified Ruby example that respects a numeric &lt;code&gt;Retry-After&lt;/code&gt; value and otherwise falls back to exponential backoff with jitter:&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="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"faraday"&lt;/span&gt;

&lt;span class="no"&gt;MAX_RETRIES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="kp"&gt;loop&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Faraday&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="s2"&gt;"https://api.example.com/data"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;break&lt;/span&gt; &lt;span class="k"&gt;unless&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;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;429&lt;/span&gt;

  &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"Rate limit exceeded"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="no"&gt;MAX_RETRIES&lt;/span&gt;

  &lt;span class="n"&gt;retry_after&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Integer&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;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"retry-after"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;exception: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;backoff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;
  &lt;span class="n"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;retry_after&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;backoff&lt;/span&gt;

  &lt;span class="nb"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A production implementation should also handle an HTTP-date &lt;code&gt;Retry-After&lt;/code&gt; value, request timeouts, network errors, logging, cancellation, and the API's documented rate-limit headers.&lt;/p&gt;

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

&lt;p&gt;If you are getting HTTP error 429 when using an external API or when &lt;a href="https://serpapi.com/blog/web-scraping-in-javascript-complete-tutorial-for-beginner/" rel="noopener noreferrer"&gt;scraping&lt;/a&gt; public web sites, it's important to stop the requests immediately and retry later. How much later can be determined from the &lt;code&gt;Retry-After&lt;/code&gt; header if present. If the header is not present, try exponential backoff with jitter to not overwhelm the servers on the other side.&lt;/p&gt;

</description>
      <category>api</category>
      <category>backend</category>
      <category>softwareengineering</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Introducing SerpApi's New Markdown Output</title>
      <dc:creator>Tomás Murúa</dc:creator>
      <pubDate>Mon, 24 Aug 2026 19:59:59 +0000</pubDate>
      <link>https://dev.to/serpapi/introducing-serpapis-new-markdown-output-3ana</link>
      <guid>https://dev.to/serpapi/introducing-serpapis-new-markdown-output-3ana</guid>
      <description>&lt;p&gt;We’re proud to announce the launch of &lt;a href="https://serpapi.com/markdown-output" rel="noopener noreferrer"&gt;Markdown Output&lt;/a&gt;, a new feature designed to deliver real-time search data in a format optimized for LLMs and AI agents. It is available on every search, on every API, and it comes back from the same structured search that JSON does. This is SerpApi’s effort to adapt and improve our product for LLMs and AI agents. Based on our benchmarks, the new output gives you roughly half the tokens of JSON on average and up to 90% for some APIs. If you already use our APIs, you can implement it right away; no configuration is needed, and it works automatically across our &lt;a href="https://serpapi.com/search-engine-apis" rel="noopener noreferrer"&gt;100+ APIs&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/markdown-output" rel="noopener noreferrer"&gt;SerpApi: Markdown Output for AI Agents&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this post, we’ll show what the new Markdown Output looks like on a real search and explain when to use it and when to stay on JSON.&lt;/p&gt;

&lt;p&gt;Getting Markdown results does not require a new endpoint. Any existing search can return it in three ways:&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="c"&gt;# Query parameter&lt;/span&gt;
curl &lt;span class="s2"&gt;"https://serpapi.com/search?engine=google&amp;amp;q=coffee&amp;amp;api_key=YOUR_KEY&amp;amp;output=md"&lt;/span&gt;

&lt;span class="c"&gt;# Route extension&lt;/span&gt;
curl &lt;span class="s2"&gt;"https://serpapi.com/search.md?engine=google&amp;amp;q=coffee&amp;amp;api_key=YOUR_KEY"&lt;/span&gt;

&lt;span class="c"&gt;# Accept header&lt;/span&gt;
curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Accept: text/markdown"&lt;/span&gt; &lt;span class="s2"&gt;"https://serpapi.com/search?engine=google&amp;amp;q=coffee&amp;amp;api_key=YOUR_KEY"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why Markdown for LLMs
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.markdownguide.org/" rel="noopener noreferrer"&gt;Markdown&lt;/a&gt; is a plain-text format with headers, tables, links, and lists that you can read raw or render as structure. In the last few years, it also became the default language of LLMs. Models are trained on enormous amounts of it (documentation, READMEs, forums); chat interfaces render their answers from it, and &lt;a href="https://developers.openai.com/api/docs/guides/prompt-engineering#message-formatting-with-markdown-and-xml" rel="noopener noreferrer"&gt;OpenAI's own prompt engineering guide&lt;/a&gt; recommends Markdown headers and lists to communicate hierarchy to the models.&lt;/p&gt;

&lt;p&gt;We took that signal from our users and from the industry, everyone converging on Markdown as the common input and output format for LLMs and agents, and adapted our product to it. Every design choice in the new output serves one goal, to fit more useful data in your model's context window. Let's see each one with a real search for &lt;code&gt;coffee&lt;/code&gt; on Google.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/playground?device=desktop&amp;amp;engine=google&amp;amp;gl=us&amp;amp;google_domain=google.com&amp;amp;hl=en&amp;amp;location=Austin%2C+Texas%2C+United+States&amp;amp;q=Coffee" rel="noopener noreferrer"&gt;SerpApi Playground - SerpApi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Token Efficient
&lt;/h3&gt;

&lt;p&gt;Take the first organic result from a &lt;code&gt;coffee&lt;/code&gt; search on Google. This is everything JSON carries for it:&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;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&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="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"link"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://en.wikipedia.org/wiki/Coffee"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"redirect_link"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://www.google.com/url?sa=t&amp;amp;source=web&amp;amp;rct=j&amp;amp;opi=89978449&amp;amp;url=https://en.wikipedia.org/wiki/Coffee&amp;amp;ved=2ahUKEwiOsKzK96uWAxXmQjABHecdCtsQFnoECCcQAQ"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"displayed_link"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://en.wikipedia.org › wiki › Coffee"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"thumbnail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQs1E6FVWWD12JBVWlsho0fGc7GxAR50Pf030IPyxJNl5A9xYPmgt_1&amp;amp;usqp=CAE&amp;amp;s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"favicon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://serpapi.com/images/i/iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAAAnklEQVR4AeTNIQiDQABG4b-u17X1aF6PK3YEO9iMJqPVau82y4FgMezS0oVLhqsHtrcqeqzDXv3CEz_6L4yTtZM3dnHmPTtjzXZAXKYVo4agkU2GI2Lloc6JDez1-flswMu1EQZ3xlE7lK8eKDkjtwE-crBMV-wesKmCiisGGepZIfQJpMj9SNb2MYWrChjVkULuCyCfRvsdmBieyQQAsoDk_9ryhFMAAAAASUVORK5CYII.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"snippet"&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 is a beverage brewed from roasted ground coffee beans. Dark-colored and bitter, coffee has a stimulating effect on humans due to its caffeine content;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"snippet_highlighted_words"&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="s2"&gt;"a beverage brewed from roasted ground coffee beans"&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;"about_this_result"&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;"source"&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;"description"&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 is a beverage brewed from roasted ground coffee beans. Dark-colored and bitter, coffee has a stimulating effect on humans due to its caffeine content;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source_info_link"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://en.wikipedia.org/wiki/Coffee"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"icon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://serpapi.com/images/i/iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAAAnklEQVR4AeTNIQiDQABG4b-u17X1aF6PK3YEO9iMJqPVau82y4FgMezS0oVLhqsHtrcqeqzDXv3CEz_6L4yTtZM3dnHmPTtjzXZAXKYVo4agkU2GI2Lloc6JDez1-flswMu1EQZ3xlE7lK8eKDkjtwE-crBMV-wesKmCiisGGepZIfQJpMj9SNb2MYWrChjVkULuCyCfRvsdmBieyQQAsoDk_9ryhFMAAAAASUVORK5CYII.png"&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;"languages"&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="s2"&gt;"en"&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;"regions"&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="s2"&gt;"US"&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;"about_page_link"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://www.google.com/search?q=About+https://en.wikipedia.org/wiki/Coffee&amp;amp;tbm=ilp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"about_page_serpapi_link"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://serpapi.com/search.json?engine=google_about_this_result&amp;amp;google_domain=google.com&amp;amp;q=About+https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FCoffee"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Wikipedia"&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;And the same result as a Markdown table row:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Organic Results&lt;/span&gt;

| Position | Title | Thumbnail | Snippet | About Page Link | Source | Read More Link | Date |
| --- | --- | --- | --- | --- | --- | --- | --- |
| 1 | &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Coffee&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://en.wikipedia.org/wiki/Coffee&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; | !&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Thumbnail&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQs1E6FVWWD12JBVWlsho0fGc7GxAR50Pf030IPyxJNl5A9xYPmgt_1&amp;amp;usqp=CAE&amp;amp;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; | Coffee is a beverage brewed from roasted ground coffee beans. Dark-colored and bitter, coffee has a stimulating effect on humans due to its caffeine content; | https://www.google.com/search?q=About+https://en.wikipedia.org/wiki/Coffee&amp;amp;tbm=ilp | Wikipedia |  |  |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing the model needs is missing. The position, title, thumbnail, snippet, and source are all kept in the output, and the row costs a fraction of the tokens the object did. Across the full &lt;code&gt;coffee&lt;/code&gt; response, the JSON weighs 24,723 tokens and the markdown 6,435, a 74% cut.&lt;/p&gt;

&lt;p&gt;Here are some examples:&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%2Fe6nol22f8ewcx7qryuta.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%2Fe6nol22f8ewcx7qryuta.png" alt="Token savings across SerpApi APIs" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Token savings across SerpApi APIs&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Native Markdown Links
&lt;/h3&gt;

&lt;p&gt;In JSON a result splits its data across separate fields:&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;"title"&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="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"link"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://en.wikipedia.org/wiki/Coffee"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"displayed_link"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://en.wikipedia.org › wiki › Coffee"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Markdown that is one cell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Coffee&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://en.wikipedia.org/wiki/Coffee&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model gets the title and the URL already bound together.&lt;/p&gt;

&lt;h3&gt;
  
  
  No Noise
&lt;/h3&gt;

&lt;p&gt;The same JSON result also carries a &lt;code&gt;redirect_link&lt;/code&gt; (a 150-character Google tracking URL), a 320-character &lt;code&gt;favicon&lt;/code&gt; URL, and internal metadata objects:&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;"redirect_link"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://www.google.com/url?sa=t&amp;amp;source=web&amp;amp;rct=j&amp;amp;opi=89978449&amp;amp;url=https://en.wikipedia.org/wiki/Coffee&amp;amp;ved=2ahUKEwiOsKzK96uWAxXmQjABHecdCtsQFnoECCcQAQ"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"favicon"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://serpapi.com/images/i/iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAAAAABXZoBIAAAAnklEQVR4AeTNIQiDQABG4b-u17X1aF6PK3YEO9iMJqPVau82y4FgMezS0oVLhqsHtrcqeqzDXv3CEz_6L4yTtZM3dnHmPTtjzXZAXKYVo4agkU2GI2Lloc6JDez1-flswMu1EQZ3xlE7lK8eKDkjtwE-crBMV-wesKmCiisGGepZIfQJpMj9SNb2MYWrChjVkULuCyCfRvsdmBieyQQAsoDk_9ryhFMAAAAASUVORK5CYII.png"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;None of that helps a model answer a question about coffee. The Markdown Output strips them automatically, and you can check the table row above; none of these fields made it in. The title, link, snippet, and source remain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Structured Output
&lt;/h3&gt;

&lt;p&gt;Markdown does not flatten the response into prose. Each result array becomes a table, and the nine organic results of our &lt;code&gt;coffee&lt;/code&gt; search arrive as nine rows under one header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Organic Results&lt;/span&gt;

| Position | Title | Thumbnail | Snippet | About Page Link | Source | Read More Link | Date |
| --- | --- | --- | --- | --- | --- | --- | --- |
| 1 | &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Coffee&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://en.wikipedia.org/wiki/Coffee&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; | !&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Thumbnail&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQs1E6FVWWD12JBVWlsho0fGc7GxAR50Pf030IPyxJNl5A9xYPmgt_1&amp;amp;usqp=CAE&amp;amp;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; | Coffee is a beverage brewed from roasted ground coffee beans. Dark-colored and bitter, coffee has a stimulating effect on humans due to its caffeine content; | https://www.google.com/search?q=About+https://en.wikipedia.org/wiki/Coffee&amp;amp;tbm=ilp | Wikipedia |  |  |
| 2 | &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Fresh Roasted, Single Origin Coffee Beans&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://creaturecoffee.co/collections/coffee?srsltid=AfmBOoo5rAxqBgQmreq6MaHX-U_rw-P5UI-90YLvKI1oRGTosk_eXwMU&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; |  | Creature Coffee roasts single origin coffee beans from around the globe right here in Austin, Texas. | https://www.google.com/search?q=About+https://creaturecoffee.co/collections/coffee?srsltid=AfmBOoo5rAxqBgQmreq6MaHX-U_rw-P5UI-90YLvKI1oRGTosk_eXwMU&amp;amp;tbm=ilp | Creature Coffee Co |  |  |
| 3 | &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Coffee Shops Austin, TX - Last Updated August 2026&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://www.yelp.com/search?find_desc=Coffee+Shops&amp;amp;find_loc=Austin%2C+TX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; |  | Coffee Shops Austin, TX · 1. Mazúr Coffee · 2. Palomino Coffee · 3. Idlewild Coffee · 4. Desnudo Coffee · 5. Flora Coffee · 6. Daydreamer Coffee. 3.9 ... | https://www.google.com/search?q=About+https://www.yelp.com/search?find_desc=Coffee+Shops&amp;amp;find_loc=Austin%2C+TX&amp;amp;tbm=ilp | Yelp | https://www.yelp.com/search?find_desc=Coffee+Shops&amp;amp;find_loc=Austin,+TX#:~:text=Coffee%20Shops%20Austin%2C%20TX&amp;amp;text=1.%20Maz%C3%BAr%20Coffee&amp;amp;text=2.%20Palomino%20Coffee&amp;amp;text=3.%20Idlewild%20Coffee&amp;amp;text=4.%20Desnudo%20Coffee&amp;amp;text=5.%20Flora%20Coffee&amp;amp;text=6.%20Daydreamer%20Coffee,3.9%20(25%20reviews) |  |
| 4 | &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;r/Coffee&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://www.reddit.com/r/Coffee/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; |  | This is a place to share and talk about your favorite coffee roasters or beans. recommendations, reviews, etc. | https://www.google.com/search?q=About+https://www.reddit.com/r/Coffee/&amp;amp;tbm=ilp | Reddit · r/Coffee |  |  |
| 5 | &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Cuvée Coffee: Always Something Brewing. Austin, TX&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://cuveecoffee.com/?srsltid=AfmBOorjX3_f5tAt5zldI8Vqr4pNmmfh2FRWlZcVVMEGXhowAfzLZ_Jt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; |  | At Cuvée, coffee isn't a job, it's a passion. Since 1998, we've become known for roasting exceptional, ethically sourced, sustainable coffee. | https://www.google.com/search?q=About+https://cuveecoffee.com/?srsltid=AfmBOorjX3_f5tAt5zldI8Vqr4pNmmfh2FRWlZcVVMEGXhowAfzLZ_Jt&amp;amp;tbm=ilp | Cuvée Coffee |  |  |
| 6 | &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Coffee - The Nutrition Source&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://nutritionsource.hsph.harvard.edu/food-features/coffee/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; |  | Various polyphenols in coffee have been shown to prevent cancer cell growth in animal studies. Coffee has also been associated with decreased estrogen levels, a ... | https://www.google.com/search?q=About+https://nutritionsource.hsph.harvard.edu/food-features/coffee/&amp;amp;tbm=ilp | The Nutrition Source | https://nutritionsource.hsph.harvard.edu/food-features/coffee/#:~:text=Type%202%20Diabetes |  |
| 7 | &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Texas Coffee Traders&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://texascoffeetraders.com/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; |  | No information is available for this page. | https://www.google.com/search?q=About+https://texascoffeetraders.com/&amp;amp;tbm=ilp | Texas Coffee Traders |  |  |
| 8 | &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;33 Best Coffee Shops In Austin, Sorted By Neighborhood&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://www.atasteofkoko.com/visit-austin/coffee-shops-in-austin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; |  | Best Coffee Shops in Central Austin · Hank's · Civil Goat Coffee Roasters (Central) · Merit Coffee (Central) · Bennu Coffee · Terrible Love. | https://www.google.com/search?q=About+https://www.atasteofkoko.com/visit-austin/coffee-shops-in-austin&amp;amp;tbm=ilp | A Taste of Koko | https://www.atasteofkoko.com/visit-austin/coffee-shops-in-austin#:~:text=Best%20Coffee%20Shops%20in%20Central,Austin&amp;amp;text=Hank's&amp;amp;text=Civil%20Goat%20Coffee%20Roasters%20(Central)&amp;amp;text=Merit%20Coffee%20(Central)&amp;amp;text=Bennu%20Coffee&amp;amp;text=Terrible%20Love | Apr 22, 2026 |
| 9 | &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Try the new gold standard of coffee at home!&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://icoffee.co/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; |  | At Industry Coffee, we take great care in every step of our coffee making process. From selecting the best beans, to roasting, brewing, and blending our ... | https://www.google.com/search?q=About+https://icoffee.co/&amp;amp;tbm=ilp | Industry Coffee | https://icoffee.co/#:~:text=At%20Industry%20Coffee%2C%20we%20take,committed%20to%20quality%20and%20consistency. |  |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same happens for &lt;a href="https://serpapi.com/google-shopping-api" rel="noopener noreferrer"&gt;shopping&lt;/a&gt; results, &lt;a href="https://serpapi.com/google-hotels-api" rel="noopener noreferrer"&gt;hotel&lt;/a&gt; listings, and any other result array.&lt;/p&gt;

&lt;p&gt;The response also opens with a &lt;a href="https://yaml.org/about/" rel="noopener noreferrer"&gt;YAML&lt;/a&gt; frontmatter block carrying the search parameters and metadata:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;search_metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;6a853ba34c437ff2e1aa1265&lt;/span&gt;
  &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Success&lt;/span&gt;
  &lt;span class="na"&gt;json_endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://serpapi.com/searches/cPnrW0xTHlgDT2yVVjFSmg/6a853ba34c437ff2e1aa1265.json"&lt;/span&gt;
  &lt;span class="na"&gt;markdown_endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://serpapi.com/searches/cPnrW0xTHlgDT2yVVjFSmg/6a853ba34c437ff2e1aa1265.md"&lt;/span&gt;
  &lt;span class="na"&gt;pixel_position_endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://serpapi.com/searches/cPnrW0xTHlgDT2yVVjFSmg/6a853ba34c437ff2e1aa1265.json_with_pixel_position"&lt;/span&gt;
  &lt;span class="na"&gt;created_at&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2026-08-19T05:14:11.488Z"&lt;/span&gt;
  &lt;span class="na"&gt;processed_at&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2026-08-19T05:14:11.497Z"&lt;/span&gt;
  &lt;span class="na"&gt;google_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://www.google.com/search?q=Coffee&amp;amp;oq=Coffee&amp;amp;uule=w+CAIQICIaQXVzdGluLFRleGFzLFVuaXRlZCBTdGF0ZXM&amp;amp;hl=en&amp;amp;gl=us&amp;amp;sourceid=chrome&amp;amp;ie=UTF-8"&lt;/span&gt;
  &lt;span class="na"&gt;raw_html_file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://serpapi.com/searches/cPnrW0xTHlgDT2yVVjFSmg/6a853ba34c437ff2e1aa1265.html"&lt;/span&gt;
  &lt;span class="na"&gt;total_time_taken&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.91&lt;/span&gt;
&lt;span class="na"&gt;search_parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;engine&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;google&lt;/span&gt;
  &lt;span class="na"&gt;q&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Coffee&lt;/span&gt;
  &lt;span class="na"&gt;location_requested&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Austin, Texas, United States&lt;/span&gt;
  &lt;span class="na"&gt;location_used&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Austin,Texas,United States&lt;/span&gt;
  &lt;span class="na"&gt;google_domain&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;google.com&lt;/span&gt;
  &lt;span class="na"&gt;hl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;en&lt;/span&gt;
  &lt;span class="na"&gt;gl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us&lt;/span&gt;
  &lt;span class="na"&gt;device&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;desktop&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So even in text form you still have the search id, status, and the endpoints to fetch the same search again in either format.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Choose Markdown or JSON?
&lt;/h2&gt;

&lt;p&gt;Both formats come from the same search, so this is not a migration. It is a per-call choice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Markdown fits when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You feed results straight into an LLM prompt or a RAG context&lt;/li&gt;
&lt;li&gt;An agent consumes search results as a tool response&lt;/li&gt;
&lt;li&gt;You want a quick human-readable digest of a search&lt;/li&gt;
&lt;li&gt;Tokens are the budget you optimize for&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;JSON fits when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your code extracts fields programmatically (prices as numbers, coordinates, ratings)&lt;/li&gt;
&lt;li&gt;You handle pagination, filters, or metadata downstream&lt;/li&gt;
&lt;li&gt;You store results in a database with a fixed schema&lt;/li&gt;
&lt;li&gt;You need every field, including the ones Markdown strips&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Simply put: if a model reads it, use Markdown. If code reads it, use JSON.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the JSON Restrictor
&lt;/h2&gt;

&lt;p&gt;Before Markdown Output, the tool for cutting response size was the &lt;a href="https://serpapi.com/json-restrictor" rel="noopener noreferrer"&gt;JSON Restrictor&lt;/a&gt;, and it is still the right tool when you stay on JSON. You pass a field selector with the request, and SerpApi filters the response server-side before sending it back. We have used it for exactly this purpose in earlier posts, like &lt;a href="https://serpapi.com/blog/how-to-connect-your-local-llm-with-web-search-data/" rel="noopener noreferrer"&gt;connecting a local LLM to web search data&lt;/a&gt;, where trimming the JSON was the difference between fitting the context window or not.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/json-restrictor" rel="noopener noreferrer"&gt;SerpApi: JSON Restrictor&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cutting Tokens While Staying on JSON
&lt;/h3&gt;

&lt;p&gt;If your pipeline needs structured fields but not all of them, the restrictor alone gets you most of the way. We'll request only the two fields an agent might rank on, position and title:&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="s2"&gt;"https://serpapi.com/search?engine=google&amp;amp;q=Coffee&amp;amp;location=Austin,+Texas,+United+States&amp;amp;api_key=YOUR_KEY&amp;amp;json_restrictor=organic_results[].position,organic_results[].title"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response is the whole search reduced to this:&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;"organic_results"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Cuvée Coffee: Always Something Brewing. Austin, TX"&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;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&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 Shops Austin, TX - Last Updated August 2026"&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;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"r/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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&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 - The Nutrition Source"&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;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Texas Coffee Traders"&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;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"50 Best Austin Coffee Shops You Should Try"&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;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Buy Coffee, Tea, Powders Online | The Coffee Bean &amp;amp; Tea ..."&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;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"History of coffee - NCA"&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="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;You keep exact types and programmatic access, and drop every section your code never touches. The difference with Markdown Output is what each one removes. The restrictor cuts entire fields and sections you name, while Markdown keeps every section but re-renders it in a lighter format. One subtracts data, the other changes its shape.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stacking Both
&lt;/h3&gt;

&lt;p&gt;You don't have to pick one. Pass &lt;code&gt;json_restrictor&lt;/code&gt; on a Markdown request, and SerpApi first filters the sections, then renders only what is left as Markdown:&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="s2"&gt;"https://serpapi.com/search.md?engine=google&amp;amp;q=Coffee&amp;amp;location=Austin,+Texas,+United+States&amp;amp;api_key=YOUR_KEY&amp;amp;json_restrictor=organic_results"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response is just the Organic Results table from earlier, nothing else. On our &lt;code&gt;coffee&lt;/code&gt; search, the four levels look like this:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Request&lt;/th&gt;
&lt;th&gt;Tokens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Full JSON&lt;/td&gt;
&lt;td&gt;24,723&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON + &lt;code&gt;json_restrictor=organic_results&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;8,486&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full markdown&lt;/td&gt;
&lt;td&gt;6,435&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Markdown + &lt;code&gt;json_restrictor=organic_results&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;1,298&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That is a 95% reduction from the original JSON, and you chose exactly which part of the search enters the model's context. For an agent that only reasons over organic results, everything else was noise anyway.&lt;/p&gt;

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

&lt;p&gt;Markdown Output is live today on every SerpApi plan, at no extra cost, across all 100+ APIs. Same searches, same credits, and around 50% fewer tokens on average and up to 90% for some APIs.&lt;/p&gt;

&lt;p&gt;The fastest way to see what it does for you is to take an API you already use, add &lt;code&gt;output=md&lt;/code&gt; to one request, and count the tokens before and after.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/markdown-output" rel="noopener noreferrer"&gt;SerpApi: Markdown Output for AI Agents&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/json-restrictor" rel="noopener noreferrer"&gt;SerpApi: JSON Restrictor&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/introducing-serpapi-search-tools-real-time-web-search-for-python-ai-agents/" rel="noopener noreferrer"&gt;Introducing SerpApi Search Tools: Real-Time Web Search for Python AI Agents&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&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;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/how-to-connect-your-local-llm-with-web-search-data/" rel="noopener noreferrer"&gt;How to Connect Your Local LLM with Web Search Data&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How a Lead Generation Company Scaled Outreach with SerpApi's Google Maps API</title>
      <dc:creator>Sonika Arora</dc:creator>
      <pubDate>Sat, 22 Aug 2026 03:43:22 +0000</pubDate>
      <link>https://dev.to/serpapi/how-a-lead-generation-company-scaled-outreach-with-serpapis-google-maps-api-1jgb</link>
      <guid>https://dev.to/serpapi/how-a-lead-generation-company-scaled-outreach-with-serpapis-google-maps-api-1jgb</guid>
      <description>&lt;p&gt;For businesses that rely on outbound sales, growth often comes down to one thing: a consistent pipeline of qualified leads.&lt;/p&gt;

&lt;p&gt;For a lead generation company specializing in Google Business Profile optimization and client acquisition through email marketing, generating those leads at scale was becoming increasingly challenging. As demand grew, the team needed a faster and more reliable way to collect business data from Google Maps without the operational headaches that came with managing their own scraping infrastructure.&lt;/p&gt;

&lt;p&gt;In their COO's words:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"SerpApi is the only platform that has really helped us expand rapidly."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By leveraging SerpApi's Google Maps API, the company was able to dramatically increase its lead generation capacity and support the rapid growth of its outreach efforts.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;📌 &lt;strong&gt;Customer Snapshot&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Industry:&lt;/strong&gt; Lead Generation &amp;amp; Marketing&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Primary APIs:&lt;/strong&gt; Google Maps API, Google Maps Reviews API&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Use Case:&lt;/strong&gt; Business Lead Discovery&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Scale:&lt;/strong&gt; Millions of searches monthly&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Key Benefit:&lt;/strong&gt; Faster lead generation through high-concurrency data collection&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  About The Use Case
&lt;/h2&gt;

&lt;p&gt;The company specializes in helping businesses improve their presence on Google Business Profile (formerly Google My Business) and acquire new customers through targeted email marketing campaigns.&lt;/p&gt;

&lt;p&gt;The company's COO oversees the systems used to identify and engage potential customers. For this process to succeed, reliable access to accurate business data from Google Maps is essential.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Google Maps Data Matters For Businesses
&lt;/h3&gt;

&lt;p&gt;Google Maps is more than a directory of businesses - it's a foundation of any company's lead generation process. By identifying businesses with specific characteristics, a company can build highly targeted outreach campaigns for any industry.&lt;/p&gt;

&lt;p&gt;Additionally, reviews data from Google Maps can help businesses understand customer sentiment, identify strengths and weaknesses, and improve products or services based on real user feedback. It also supports competitor analysis, market research, reputation monitoring, and AI-powered recommendations.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Challenge: Generating Leads at Scale
&lt;/h2&gt;

&lt;p&gt;Before adopting SerpApi, the team relied on a combination of internal tools and alternative approaches to gather business information from Google Maps.&lt;/p&gt;

&lt;p&gt;They even built their own Selenium-based scraping solution, which worked for smaller workloads. However, as the business grew, so did the volume of data required. They needed to scrape tens of thousands of business listings every day to support their lead generation workflows.&lt;/p&gt;

&lt;p&gt;At that scale, several challenges emerged:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Internal scraping infrastructure wasn't fast enough.&lt;/li&gt;
&lt;li&gt;High request volumes increased the risk of IP blocks.&lt;/li&gt;
&lt;li&gt;Maintaining reliable data collection required significant effort.&lt;/li&gt;
&lt;li&gt;Lead generation capacity was becoming a bottleneck for growth.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The team explored various options, and settled on using SerpApi.&lt;/p&gt;

&lt;p&gt;In their words:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Well, we always had issues generating fast enough leads - which obviously caused declines in revenue. With SerpApi, we fixed that."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why SerpApi?
&lt;/h2&gt;

&lt;p&gt;SerpApi streamlines the process of web-scraping, manages the intricacies of scraping and returns structured JSON results.&lt;/p&gt;

&lt;p&gt;We do all the work to maintain all of our parsers and adapt them to respond to changes on Google's side. This is important, as Google is constantly experimenting with new layouts, new elements, and other changes. By taking care of this for you on our side, we eliminate a lot of time and complexity from your workflow.&lt;/p&gt;

&lt;p&gt;According to their COO, one feature stood out above everything else: &lt;strong&gt;concurrency&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"We were looking for an API that scrapes Google Maps. Building our own Selenium tool worked, and we have used it, but we need to scrape over 40k places everyday, that would   &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;cause our IP’s to be blocked and
&lt;/li&gt;
&lt;li&gt;It isn’t fast enough."&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;The ability to run large volumes of searches simultaneously allows the company to process data at a scale that would have been difficult to achieve with internally managed tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Scalable Lead Generation Engine
&lt;/h2&gt;

&lt;p&gt;Today, they use SerpApi's Google Maps API as a core component of their lead generation workflow. They have developed their own proprietary algorithm that identifies and evaluates business profiles from Google Maps, helping the team discover high-value prospects for outreach campaigns.&lt;/p&gt;

&lt;p&gt;Empowered with the data that the company gets using SerpApi, it can focus on improving its lead qualification process and scaling outreach operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Impact
&lt;/h3&gt;

&lt;p&gt;The biggest benefit was removing a critical growth constraint. Before implementing SerpApi, they frequently struggled to generate enough leads quickly enough to support their sales efforts.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Well, we always had issues generating leads fast enough, which obviously caused declines in revenue. With SerpApi, we fixed that."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With a more scalable and reliable data collection pipeline in place, they significantly increased their lead generation capacity, enabling the business to support more outreach campaigns and accelerate growth.&lt;/p&gt;

&lt;p&gt;In addition to the product itself, the team highlighted the responsiveness of the SerpApi team as a key part of their experience.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Very fast responses and very helpful."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Looking Ahead
&lt;/h2&gt;

&lt;p&gt;As they continue expanding their lead generation efforts, scalable access to Google Maps data remains a critical part of their growth strategy.&lt;/p&gt;

&lt;p&gt;By replacing the limitations of self-managed scraping infrastructure with SerpApi's Google Maps API, the company has been able to focus less on data collection challenges and more on what matters most: finding and connecting with new customers.&lt;/p&gt;

&lt;p&gt;When asked whether they would recommend SerpApi to others, their COO's answer was jokingly reluctant:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"No, because I want to gatekeep it. "&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Fortunately for everyone else, they're willing to share their success story. Behind the humor is a clear result. By replacing the limitations of self-managed scraping infrastructure with SerpApi's Google Maps API, they transformed lead generation from a bottleneck into a scalable growth engine.&lt;/p&gt;

&lt;h2&gt;
  
  
  About SerpApi
&lt;/h2&gt;

&lt;p&gt;SerpApi provides real-time search engine data APIs, including &lt;a href="https://serpapi.com/search-api" rel="noopener noreferrer"&gt;Google Search API&lt;/a&gt;, &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-shopping-api" rel="noopener noreferrer"&gt;Google Shopping API&lt;/a&gt;, &lt;a href="https://serpapi.com/amazon-search-api" rel="noopener noreferrer"&gt;Amazon Search API&lt;/a&gt;, &lt;a href="https://serpapi.com/yelp-search-api" rel="noopener noreferrer"&gt;Yelp Search API&lt;/a&gt;, and many more (See all our APIs &lt;a href="https://serpapi.com/search-engine-apis" rel="noopener noreferrer"&gt;here&lt;/a&gt;). Developers and businesses use SerpApi to access structured search data in JSON format.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/google-maps-api" rel="noopener noreferrer"&gt;SerpApi 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/pricing#all-plans" rel="noopener noreferrer"&gt;SerpApi Plans and Pricing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Explore More Google Maps API Use Cases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/how-ai-can-predict-the-success-of-your-business-using-data-from-google-maps/" rel="noopener noreferrer"&gt;How AI Can Predict the Success of Your Business Using Data from Google Maps&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/gauge-business-popularities-using-google-maps/" rel="noopener noreferrer"&gt;Gauge Business Popularities using Google Maps&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://serpapi.com/blog/build-a-no-code-ai-powered-local-lead-outreach-system/" rel="noopener noreferrer"&gt;Build A No Code AI-Powered Local Lead Outreach System&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How to Scrape Google Flights</title>
      <dc:creator>Noraina Nordin</dc:creator>
      <pubDate>Fri, 14 Aug 2026 10:50:50 +0000</pubDate>
      <link>https://dev.to/serpapi/how-to-scrape-google-flights-2ik8</link>
      <guid>https://dev.to/serpapi/how-to-scrape-google-flights-2ik8</guid>
      <description>&lt;p&gt;Google Flights is Google's free flight search service, part of the Google Travel platform. It aggregates flights from multiple airlines so travelers can search by departure and destination, compare prices across carriers, track fares, and book tickets in one place.&lt;/p&gt;

&lt;p&gt;That aggregated data is exactly what makes Google Flights worth scraping. If you want to build or research flight prices, routes, and availability, scraping Google Flights gives you a rich, continuously updated data source, and SerpApi's &lt;a href="https://serpapi.com/google-flights-api" rel="noopener noreferrer"&gt;Google Flights API&lt;/a&gt; lets you pull it as structured JSON in Python, JavaScript, or in any programming language of your choice without maintaining your own scraper.&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%2Flh7-us.googleusercontent.com%2Fdocsz%2FAD_4nXca5uKZaB4dilp7Q2xnvgZuRGjbSzcEA98slsx_jy7BRY1Fn-1moMKO-Osge7qqrXaFGCVqTznwZfdCxFzGpztSFDTw5NtT8gJN7Q3UvKUBhv4NGJy5ZidIOUqNTOu87oLZ3lDKvicNh7wfISkTXMD-_Qg%3Fkey%3DeyouYlaTWA7jstLRznSGZg" 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%2Flh7-us.googleusercontent.com%2Fdocsz%2FAD_4nXca5uKZaB4dilp7Q2xnvgZuRGjbSzcEA98slsx_jy7BRY1Fn-1moMKO-Osge7qqrXaFGCVqTznwZfdCxFzGpztSFDTw5NtT8gJN7Q3UvKUBhv4NGJy5ZidIOUqNTOu87oLZ3lDKvicNh7wfISkTXMD-_Qg%3Fkey%3DeyouYlaTWA7jstLRznSGZg" alt="Google Flights User Interface" width="1189" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Flights User Interface&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Needs the Scraped Google Flights Data?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Travel agencies and online travel businesses&lt;/strong&gt; use it for market analysis and competitive intelligence. They can track competitors' pricing strategies, route popularity, and demand trends. With that visibility, they can adjust their own fares and offers to stay competitive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developers&lt;/strong&gt; use it to build flight comparison platforms, fare trackers, and AI travel assistants. All of these need live prices, routes, and availability. The API supplies that data on demand, so there's no fragile in-house flight scraper to build or maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Available Data on the Google Flights API
&lt;/h2&gt;

&lt;p&gt;Before scraping, it helps to understand the structure of the data returned.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flight Results
&lt;/h3&gt;

&lt;p&gt;A response is organized into two main arrays:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;best_flights&lt;/code&gt;&lt;/strong&gt; : The top options for your search criteria. However, note that these results are not always returned by Google Flights itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;other_flights&lt;/code&gt;&lt;/strong&gt; : The remaining options, in the same structure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each entry contains a list of individual &lt;code&gt;flights&lt;/code&gt; with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Departure and arrival airports and times&lt;/li&gt;
&lt;li&gt;Duration, airplane model, airline, travel class, and flight number&lt;/li&gt;
&lt;li&gt;Layover details (duration, and whether it's overnight)&lt;/li&gt;
&lt;li&gt;The journey's &lt;code&gt;total_duration&lt;/code&gt;, carbon emissions data, and &lt;code&gt;price&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;An &lt;code&gt;extensions&lt;/code&gt; array of flight features, and &lt;code&gt;ticket_also_sold_by&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;departure_token&lt;/code&gt; (used to fetch the return legs of a round trip)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Full field-by-field detail is in the &lt;a href="https://serpapi.com/google-flights-results" rel="noopener noreferrer"&gt;Google Flights API documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Price Insights
&lt;/h3&gt;

&lt;p&gt;Each response also carries a &lt;strong&gt;&lt;code&gt;price_insights&lt;/code&gt;&lt;/strong&gt; object, so you can tell whether a fare is a good deal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;lowest_price&lt;/code&gt; : The cheapest ticket among the options&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;price_level&lt;/code&gt; : The affordability tier for that price&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;typical_price_range&lt;/code&gt; : A &lt;code&gt;[low, high]&lt;/code&gt; array of expected prices for the route&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;price_history&lt;/code&gt; : Timestamped price points, ideal for a price-tracking chart&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More detail in the &lt;a href="https://serpapi.com/google-flights-price-insights" rel="noopener noreferrer"&gt;price insights documentation&lt;/a&gt;. We'll read these fields in the Scrape flight prices section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Google Flights Data Scraping
&lt;/h2&gt;

&lt;p&gt;You can get structured Google Flights data with a single GET request using SerpApi's &lt;a href="https://serpapi.com/google-flights-api" rel="noopener noreferrer"&gt;Google Flights API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prefer to watch?&lt;/strong&gt; Here's a quick walkthrough of scraping Google Flights with the API:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/embed/zqZSvuj7JMs?feature=oembed" rel="noopener noreferrer"&gt;https://www.youtube.com/embed/zqZSvuj7JMs?feature=oembed&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Setting Up a SerpApi Account&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://serpapi.com/" rel="noopener noreferrer"&gt;SerpApi&lt;/a&gt; offers a free plan for newly created accounts. Head to the &lt;a href="https://serpapi.com/users/sign_up?plan=free" rel="noopener noreferrer"&gt;sign-up&lt;/a&gt; page to register an account and complete your first search with our &lt;a href="https://serpapi.com/playground?engine=google_flights" rel="noopener noreferrer"&gt;interactive playground&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When you want to do more searches with us, please visit the &lt;a href="https://serpapi.com/pricing" rel="noopener noreferrer"&gt;pricing page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you are familiar with all the results, you can utilize SERP APIs using your&lt;a href="https://serpapi.com/manage-api-key" rel="noopener noreferrer"&gt;API Key&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%2Fu24lxk1gwj5y8byotixd.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%2Fu24lxk1gwj5y8byotixd.png" alt="SerpApi Google Flights API data from playground" width="800" height="563"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;SerpApi Google Flights API data from playground&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Search by Airport Code
&lt;/h3&gt;

&lt;p&gt;Search a route by &lt;strong&gt;IATA airport code&lt;/strong&gt; (find codes on &lt;a href="https://www.iata.org/en/publications/directories/code-search/" rel="noopener noreferrer"&gt;IATA's site&lt;/a&gt; or Google Flights).&lt;/p&gt;

&lt;p&gt;Let's find the best flights to Berlin. The data contains: "total_duration", "price", "type", "number_of_flights", and more.&lt;/p&gt;

&lt;h4&gt;
  
  
  cURL implementation
&lt;/h4&gt;

&lt;p&gt;The simplest way to test the API:&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; https://serpapi.com/search &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;"SERPAPI_API_KEY"&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_flights"&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;departure_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"AUS"&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;arrival_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"BER"&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;outbound_date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"2026-09-15"&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;return_date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"2026-09-22"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Python Implementation
&lt;/h4&gt;

&lt;p&gt;First, install the &lt;a href="https://github.com/serpapi/serpapi-python" rel="noopener noreferrer"&gt;SerpApi client library&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;Get your API Key from&lt;a href="https://serpapi.com/?ref=serpapi.com" rel="noopener noreferrer"&gt;SerpApi&lt;/a&gt;&lt;a href="https://serpapi.com/manage-api-key" rel="noopener noreferrer"&gt;credentials&lt;/a&gt; and run a basic search. Store your key as an environment variable (&lt;code&gt;export SERPAPI_KEY=your_key&lt;/code&gt;) and read it with &lt;code&gt;os.getenv&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;os&lt;/span&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="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&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;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;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_flights&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;departure_id&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;AUS&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;arrival_id&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;BER&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;outbound_date&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;2026-09-15&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;return_date&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;2026-09-22&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;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="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="n"&gt;params&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;The &lt;code&gt;results&lt;/code&gt; object behaves like a regular dictionary, so you can read fields straight off it.&lt;/p&gt;

&lt;p&gt;Let's say you only want the price, total duration, type, and number of flights from each of the best options:&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;item&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;best_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="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;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="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;Total duration (min):&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;total_duration&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;Type:&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;type&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;Number of flights:&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;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;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="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;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, let's export the data to a CSV file for easier analysis.&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;csv&lt;/span&gt;

&lt;span class="n"&gt;header&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;total_duration&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="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;number_of_flights&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&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_flights.csv&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;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;UTF8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newline&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="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writerow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&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;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;best_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;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writerow&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;total_duration&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="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;type&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;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;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="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;Data exported to google_flights.csv&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%2Fqs8dwlmwwtvbgbcdi3sa.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%2Fqs8dwlmwwtvbgbcdi3sa.png" alt="Google Flight Result in CSV format" width="702" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Google Flight Result in CSV format&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  JavaScript Implementation
&lt;/h4&gt;

&lt;p&gt;Install the &lt;code&gt;serpapi&lt;/code&gt; 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;Run a basic query:&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="nf"&gt;getJson&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;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="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;google_flights&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;departure_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AUS&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;arrival_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;BER&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;outbound_date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-09-15&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;return_date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2026-09-22&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;USD&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="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;results&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="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;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;best_flights&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More on the library: &lt;a href="https://github.com/serpapi/serpapi-javascript" rel="noopener noreferrer"&gt;serpapi-javascript on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can call the API with a plain GET request in any language. Ready-made libraries for Ruby, PHP, Java, Go, and more are listed on &lt;a href="https://serpapi.com/integrations" rel="noopener noreferrer"&gt;SerpApi Integrations&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Search by city ID
&lt;/h3&gt;

&lt;p&gt;To include every airport in a city, search by &lt;strong&gt;city ID&lt;/strong&gt; instead of an airport code. City IDs can be retrieved with the &lt;a href="https://serpapi.com/google-maps-api" rel="noopener noreferrer"&gt;Google Maps API&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;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;departure_id&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;/m/04jpl&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;arrival_id&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;/m/07dfk&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="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Customize the Flight Search
&lt;/h2&gt;

&lt;p&gt;The API exposes the same controls you'd use on Google Flights itself. Add any of these to the &lt;code&gt;params&lt;/code&gt; dict from the basic search, then run &lt;code&gt;client.search(params)&lt;/code&gt; again.&lt;/p&gt;

&lt;h3&gt;
  
  
  Round-trip vs. one-way
&lt;/h3&gt;

&lt;p&gt;Set &lt;code&gt;type&lt;/code&gt; to &lt;code&gt;1&lt;/code&gt; for a round trip (default), &lt;code&gt;2&lt;/code&gt; for one-way, or &lt;code&gt;3&lt;/code&gt; for multi-city. A round trip needs a &lt;code&gt;return_date&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;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&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;1&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;outbound_date&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;2026-09-15&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;return_date&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;2026-09-22&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;h3&gt;
  
  
  Retrieving the returning flights
&lt;/h3&gt;

&lt;p&gt;A round-trip search returns only the outbound flights first. Each outbound flight carries its own &lt;code&gt;departure_token&lt;/code&gt;, you need to pass it back to get that flight's return options:&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;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&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;1&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;departure_token&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;PASTE_DEPARTURE_TOKEN_FROM_PREVIOUS_RESPONSE&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;&lt;em&gt;(This is the Google Flights equivalent of pagination. You drill into a flight rather than page through a list.)&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Scrape flight prices and price insights
&lt;/h3&gt;

&lt;p&gt;Prices are usually the whole point of a &lt;strong&gt;flight price scraper&lt;/strong&gt;. Every response carries the fare on each option plus the &lt;code&gt;price_insights&lt;/code&gt; object described in the data structure.&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;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="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&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;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_flights&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;departure_id&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;JFK&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;arrival_id&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;LHR&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;outbound_date&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;2026-09-15&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;return_date&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;2026-09-22&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;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="p"&gt;})&lt;/span&gt;

&lt;span class="n"&gt;insights&lt;/span&gt; &lt;span class="o"&gt;=&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;price_insights&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="s"&gt;Lowest 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;insights&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;lowest_price&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;Price level:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;insights&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_level&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;            &lt;span class="c1"&gt;# e.g. "low", "typical", "high"
&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;Typical range:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;insights&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;typical_price_range&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# [low, high]
&lt;/span&gt;
&lt;span class="c1"&gt;# The cheapest fares from the results themselves
&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;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;best_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="nf"&gt;print&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;-&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;total_duration&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;min&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;Because the response is already structured, scraping flight pricing is just reading fields without HTML parsing or broken selectors. To watch a route over time, run the same request on a schedule and store &lt;code&gt;lowest_price&lt;/code&gt; and &lt;code&gt;price_history&lt;/code&gt; on each run.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cabin class
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;travel_class&lt;/code&gt;: &lt;code&gt;1&lt;/code&gt; Economy (default), &lt;code&gt;2&lt;/code&gt; Premium economy, &lt;code&gt;3&lt;/code&gt; Business, &lt;code&gt;4&lt;/code&gt; First.&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;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;travel_class&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;3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;   &lt;span class="c1"&gt;# Business
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Filter by airline
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;exclude_airlines&lt;/code&gt; drops carriers while &lt;code&gt;include_airlines&lt;/code&gt; keeps only the ones you name (comma-separated). The two can't be combined:&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;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;exclude_airlines&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;MH,EY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;   &lt;span class="c1"&gt;# or {"include_airlines": "QF"}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Stops, duration, and other filters
&lt;/h3&gt;

&lt;p&gt;Filter by number of stops with &lt;code&gt;stops&lt;/code&gt;: &lt;code&gt;0&lt;/code&gt; any (default), &lt;code&gt;1&lt;/code&gt; nonstop only, &lt;code&gt;2&lt;/code&gt; one stop or fewer, &lt;code&gt;3&lt;/code&gt; two stops or fewer.&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;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stops&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;1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;   &lt;span class="c1"&gt;# nonstop only
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add any of these to narrow results further:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;max_duration&lt;/code&gt; : The total trip-time cap in minutes (e.g. &lt;code&gt;"1400"&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;layover_duration&lt;/code&gt; : Layover range in minutes, two-number string (e.g. &lt;code&gt;"250,300"&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;exclude_conns&lt;/code&gt; : Exclude a connecting airport by ID (e.g. &lt;code&gt;"AUH"&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;outbound_times&lt;/code&gt; / &lt;code&gt;return_times&lt;/code&gt; : Departure hour ranges (e.g. &lt;code&gt;"14,18"&lt;/code&gt; = 2–6 PM)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;max_price&lt;/code&gt; : Upper price limit for the whole trip (e.g. &lt;code&gt;"600"&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sort_by&lt;/code&gt; : &lt;code&gt;1&lt;/code&gt; Top flights (default), &lt;code&gt;2&lt;/code&gt; Price, &lt;code&gt;3&lt;/code&gt; Departure time, &lt;code&gt;4&lt;/code&gt; Arrival time, &lt;code&gt;5&lt;/code&gt; Duration, &lt;code&gt;6&lt;/code&gt; Emissions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For full list check out the &lt;a href="https://serpapi.com/google-flights-api#api-parameters-advanced-filters" rel="noopener noreferrer"&gt;advanced filter parameters in the documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flexible dates
&lt;/h3&gt;

&lt;p&gt;Google Flights has no native flexible-date search, but a few lines turn the API into a flexible-date &lt;strong&gt;flight scraper.&lt;/strong&gt; Loop over a window and collect the cheapest fare per day:&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;import&lt;/span&gt; &lt;span class="n"&gt;serpapi&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timedelta&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="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&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;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;search_flexible_dates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;flexible_days&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2026&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&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="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="n"&gt;flexible_days&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;outbound&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="o"&gt;=&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;return_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;outbound&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# adjust trip length as needed
&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_flights&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;departure_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;origin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arrival_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;destination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;outbound_date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;outbound&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isoformat&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;return_date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;return_date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isoformat&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;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;1&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="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Outbound: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;outbound&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; | Return: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;return_date&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;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;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;best_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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;flight&lt;/span&gt; &lt;span class="ow"&gt;in&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;flights&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="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;flight&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;flight_number&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="sh"&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;flight&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;departure_airport&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;id&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; -&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;flight&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;arrival_airport&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;id&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="sh"&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;flight&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;airline&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;total_duration&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; min | &lt;/span&gt;&lt;span class="sh"&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;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="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;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;search_parameters&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;currency&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;search_flexible_dates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;JFK&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;LAX&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Groups of passengers
&lt;/h3&gt;

&lt;p&gt;Tailor results to a group with &lt;code&gt;adults&lt;/code&gt;, &lt;code&gt;children&lt;/code&gt;, &lt;code&gt;infants_in_seat&lt;/code&gt;, and &lt;code&gt;infants_on_lap&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;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;adults&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;3&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;children&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;2&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;infants_in_seat&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;1&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;infants_on_lap&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;1&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;h2&gt;
  
  
  Bonus: Deals and airport autocomplete
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Hunting for cheap fares specifically? See the &lt;a href="https://serpapi.com/google-flights-deals-api" rel="noopener noreferrer"&gt;Google Flights Deals API&lt;/a&gt; and our tutorial: &lt;a href="https://serpapi.com/blog/how-to-scrape-google-flights-deals/" rel="noopener noreferrer"&gt;How to Scrape Google Flights Deals&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Building a search box? The &lt;a href="https://serpapi.com/google-flights-autocomplete-api" rel="noopener noreferrer"&gt;Google Flights Autocomplete API&lt;/a&gt; returns airport and city suggestions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions (FAQs)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Is it legal to scrape Google Flights?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Collecting publicly available data is generally permitted, and using an API like SerpApi keeps you off Google's infrastructure. Always review the applicable terms of service for your use case.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How do I scrape flight prices?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Send a Google Flights API request for your route and read the &lt;code&gt;price&lt;/code&gt; on each flight plus the &lt;code&gt;price_insights&lt;/code&gt; object (&lt;code&gt;lowest_price&lt;/code&gt;, &lt;code&gt;price_level&lt;/code&gt;, &lt;code&gt;typical_price_range&lt;/code&gt;, &lt;code&gt;price_history&lt;/code&gt;). See the scrape flight prices section above for a working example.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How do I scrape Google Flights in Python?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Install the &lt;code&gt;serpapi&lt;/code&gt; package (&lt;code&gt;pip install serpapi&lt;/code&gt;), create a client with your API key, and call &lt;code&gt;client.search()&lt;/code&gt; with &lt;code&gt;engine="google_flights"&lt;/code&gt; and your route parameters. The results are returned in JSON format, so no HTML scraping is required. The full code is in Basic Google Flights Data Scraping.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How much does it cost?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Register at serpapi.com to start for free with 250 searches per month. Paid plans scale with your usage.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Why scrape Google Flights data?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Live flight prices, routes, and availability power price-comparison tools, fare trackers, travel dashboards, and market analysis for travel businesses without maintaining a fragile scraper.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;That's it! You can now scrape Google Flights end-to-end: set up the API, understand the response, run a basic search, and customize it by route, dates, prices, class, filters, and passengers. Experiment for free in the &lt;a href="https://serpapi.com/playground?engine=google_flights" rel="noopener noreferrer"&gt;Google Flights playground&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Building a broader travel product? Pair this with our other travel APIs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/google-hotels-api" rel="noopener noreferrer"&gt;Google Hotels API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/google-flights-deals-api" rel="noopener noreferrer"&gt;Google Flights Deals API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://serpapi.com/google-travel-explore-api" rel="noopener noreferrer"&gt;Google Travel Explore API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have any questions, feel free to contact our team at &lt;a href="mailto:contact@serpapi.com"&gt;contact@serpapi.com&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <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>
  </channel>
</rss>
