<?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: Robert Breen</title>
    <description>The latest articles on DEV Community by Robert Breen (@robert_breen_d96e41ecd765).</description>
    <link>https://dev.to/robert_breen_d96e41ecd765</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%2Fuser%2Fprofile_image%2F4172249%2Fcd8de2d9-27f9-43a0-9024-fae1e21b45e4.jpg</url>
      <title>DEV Community: Robert Breen</title>
      <link>https://dev.to/robert_breen_d96e41ecd765</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/robert_breen_d96e41ecd765"/>
    <language>en</language>
    <item>
      <title>n8n: Talk to your Google Sheets with an AI Agent (and why it sometimes gets the math wrong)</title>
      <dc:creator>Robert Breen</dc:creator>
      <pubDate>Sun, 11 Oct 2026 12:29:51 +0000</pubDate>
      <link>https://dev.to/robert_breen_d96e41ecd765/n8n-talk-to-your-google-sheets-with-an-ai-agent-and-why-it-sometimes-gets-the-math-wrong-k2a</link>
      <guid>https://dev.to/robert_breen_d96e41ecd765/n8n-talk-to-your-google-sheets-with-an-ai-agent-and-why-it-sometimes-gets-the-math-wrong-k2a</guid>
      <description>&lt;p&gt;Spreadsheets are where a lot of office work lives: the client list, the sales log, the invoice tracker. n8n ships a popular chat template that lets you ask a Google Sheet questions in plain English, and it feels like magic the first time. It also has a habit that surprises people: it is great at looking things up and sometimes confidently wrong at math. Here is how the setup works, and how to keep the answers honest.&lt;/p&gt;

&lt;p&gt;I teach this at Stepthrough, so the walkthrough at the end is my own free lesson. The rest of this post stands on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you are building
&lt;/h2&gt;

&lt;p&gt;Three pieces, wired together on the n8n canvas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A &lt;strong&gt;Chat Trigger&lt;/strong&gt; that gives you a chat box.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;AI Agent&lt;/strong&gt; node that reads your question and decides what to do.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Google Sheets tool&lt;/strong&gt; the agent can call to fetch rows, plus a &lt;strong&gt;chat model&lt;/strong&gt; (OpenAI, in this case) that does the thinking.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Chat message -&amp;gt; AI Agent -&amp;gt; (chat model + Google Sheets tool) -&amp;gt; answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The template opens with empty credentials and no data, so the actual work is connecting your own OpenAI key, authorizing Google Sheets, and pointing the tool at a real spreadsheet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Prepare a sheet the agent can read
&lt;/h2&gt;

&lt;p&gt;Agents do much better with a boring, clean table. Use one header row, one record per row, and no merged cells. A made-up example for a small consulting firm:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Client&lt;/th&gt;
&lt;th&gt;Industry&lt;/th&gt;
&lt;th&gt;Invoice&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;Due&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Harbor Dental&lt;/td&gt;
&lt;td&gt;Healthcare&lt;/td&gt;
&lt;td&gt;4200&lt;/td&gt;
&lt;td&gt;Paid&lt;/td&gt;
&lt;td&gt;2026-09-30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Brightline Legal&lt;/td&gt;
&lt;td&gt;Legal&lt;/td&gt;
&lt;td&gt;6800&lt;/td&gt;
&lt;td&gt;Overdue&lt;/td&gt;
&lt;td&gt;2026-09-15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maple Accounting&lt;/td&gt;
&lt;td&gt;Finance&lt;/td&gt;
&lt;td&gt;3100&lt;/td&gt;
&lt;td&gt;Open&lt;/td&gt;
&lt;td&gt;2026-10-20&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Clear column names matter more than you think. The agent reads them to figure out what it can ask for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Connect the Google Sheets tool
&lt;/h2&gt;

&lt;p&gt;Open the Google Sheets tool node, choose your credential, then pick the document and the sheet. Set the operation to read rows. A common mistake is leaving the tool on a placeholder document, which makes the agent say the sheet is empty when it simply is not looking at yours.&lt;/p&gt;

&lt;p&gt;A tool description helps the agent decide when to use it. Something like:&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"client_invoices"&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;"Returns every row of the client invoice sheet. Columns: Client, Industry, Invoice, Status, Due."&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;
  
  
  Step 3: Give the agent a short system prompt
&lt;/h2&gt;

&lt;p&gt;Without guidance the agent improvises. A few plain sentences go a long way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You answer questions about the client invoice sheet.
Always read the sheet before answering.
If the answer needs a calculation, show the rows you used.
If you are not sure, say so instead of guessing.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Ask it things
&lt;/h2&gt;

&lt;p&gt;Try lookups first: "Which clients are overdue?" or "When is Maple Accounting due?" These work well because the agent only has to find rows and quote them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it sometimes gets the math wrong
&lt;/h2&gt;

&lt;p&gt;Now ask: "What is the total of all open and overdue invoices?" Sometimes you get 9,900 (correct), and sometimes a number that is close but off.&lt;/p&gt;

&lt;p&gt;The reason is that a language model predicts text. It is not a calculator. When it adds a column of numbers, it is producing what a plausible sum looks like. With three rows that usually works. With three hundred, rows get skipped, duplicated, or truncated, because the tool may only hand back part of the sheet and the model does not always notice.&lt;/p&gt;

&lt;p&gt;Three habits that fix most of it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Make it show its work.&lt;/strong&gt; Asking for the rows it used lets you spot a missing record in seconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do the math outside the model.&lt;/strong&gt; Add a Summary column or a pivot tab in the sheet itself and have the agent read that figure. The spreadsheet is a calculator; let it be one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch the row limit.&lt;/strong&gt; If the sheet is long, filter before returning rows, for example only Status = Overdue, so the model is not asked to hold the whole table in its head.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A good rule of thumb: use the agent for finding and explaining, and use formulas for adding. If a number is going into a report or an email to a client, check it against the sheet once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this is useful in an office
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A bookkeeper asking "who has not paid in 30 days?" without building a filter.&lt;/li&gt;
&lt;li&gt;An account manager checking a client's renewal date mid-call.&lt;/li&gt;
&lt;li&gt;An operations lead getting a plain-English summary of a weekly log before a meeting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of that requires code beyond what you have seen above, and none of it should touch real client data while you are still learning. Practice on a made-up sheet first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it step by step
&lt;/h2&gt;

&lt;p&gt;If you would rather click through it than read about it, I built a free practice version. You work in a practice copy of the n8n editor, it checks each step, and nothing touches your real accounts. It takes about 8 minutes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://learn.ynteractive.com/content/n8n-talk-to-google-sheets-chatgpt-ai-agent" rel="noopener noreferrer"&gt;n8n: Talk to Your Google Sheets with ChatGPT (free lesson)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Have you hit the "confident wrong number" problem with an agent in your own workflows? I would like to hear how you solved it.&lt;/p&gt;

</description>
      <category>n8n</category>
      <category>ai</category>
      <category>automation</category>
      <category>googlesheets</category>
    </item>
    <item>
      <title>n8n: Swap SerpApi for a Cheaper Search API in 5 Minutes</title>
      <dc:creator>Robert Breen</dc:creator>
      <pubDate>Fri, 09 Oct 2026 13:05:37 +0000</pubDate>
      <link>https://dev.to/robert_breen_d96e41ecd765/n8n-swap-serpapi-for-a-cheaper-search-api-in-5-minutes-3ea4</link>
      <guid>https://dev.to/robert_breen_d96e41ecd765/n8n-swap-serpapi-for-a-cheaper-search-api-in-5-minutes-3ea4</guid>
      <description>&lt;p&gt;If you have an n8n workflow that pulls Google results through SerpApi, the search call is usually the most expensive part of the run. The good news is that it's also the easiest part to swap. It's one HTTP Request node. The trigger, the parsing, the sheet and the email after it don't care which provider answered, as long as the fields come back with the same names.&lt;/p&gt;

&lt;p&gt;This post walks through moving one real-world style workflow from SerpApi to &lt;strong&gt;Litescrape&lt;/strong&gt;, a third-party search-results API for Google, Bing and Maps data. It's priced as a cheaper alternative. The whole change comes down to four edits in one node:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Change the URL.&lt;/li&gt;
&lt;li&gt;Delete two query parameters.&lt;/li&gt;
&lt;li&gt;Move the API key into a Bearer Auth credential.&lt;/li&gt;
&lt;li&gt;Test.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The workflow we're changing
&lt;/h2&gt;

&lt;p&gt;Here's the example. Northpeak Packs (made up) sells backpacks. Every Monday at 8:00, an n8n workflow checks competitor prices for "20L commuter backpack" on Google Shopping and adds them to a Google Sheet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Schedule Trigger (Mondays 8:00)
  → HTTP Request "SerpApi Google Shopping"   GET serpapi.com
  → Split Out                                 field: shopping_results
  → Edit Fields                               date, store, price
  → Google Sheets: Append row in sheet        "Competitor prices" / Weekly
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sheet has five columns: &lt;strong&gt;Date, Store, Product, Price, Was&lt;/strong&gt;. "Was" holds the old price when something is on sale.&lt;/p&gt;

&lt;p&gt;The HTTP Request node is the only node that changes. The rest of this post is about that one node.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the SerpApi call looks like today
&lt;/h2&gt;

&lt;p&gt;With SerpApi, every search goes to the same endpoint, and the &lt;code&gt;engine&lt;/code&gt; parameter picks the search type. The key travels as a query parameter.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Method&lt;/td&gt;
&lt;td&gt;GET&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;URL&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://serpapi.com/search.json&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authentication&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Specify Query Parameters&lt;/td&gt;
&lt;td&gt;Using Fields Below&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Query parameters:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;engine&lt;/td&gt;
&lt;td&gt;google_shopping&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;q&lt;/td&gt;
&lt;td&gt;20L commuter backpack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gl&lt;/td&gt;
&lt;td&gt;us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;hl&lt;/td&gt;
&lt;td&gt;en&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;num&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;api_key&lt;/td&gt;
&lt;td&gt;(your SerpApi key)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That last row is worth a second look. Because the key is in the query string, it's sitting in plain text in the node. It can end up in execution logs and in any JSON you export or share. Moving providers is a good excuse to fix that too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Point the node at Litescrape
&lt;/h2&gt;

&lt;p&gt;Litescrape uses &lt;strong&gt;one endpoint per search type&lt;/strong&gt;, not one endpoint plus an &lt;code&gt;engine&lt;/code&gt; parameter. For Google Shopping it's:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://api.litescrape.com/api/google/shopping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open the HTTP Request node (double-click it) and replace the &lt;strong&gt;URL&lt;/strong&gt; with that address. Leave &lt;strong&gt;Method&lt;/strong&gt; on GET.&lt;/p&gt;

&lt;p&gt;If you work with SerpApi's other engines too, the pattern is the same. Look up the matching Litescrape endpoint in its docs, and don't assume the path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Delete &lt;code&gt;engine&lt;/code&gt; and &lt;code&gt;api_key&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Under &lt;strong&gt;Query Parameters&lt;/strong&gt;, most rows stay exactly as they are. &lt;code&gt;q&lt;/code&gt;, &lt;code&gt;gl&lt;/code&gt;, &lt;code&gt;hl&lt;/code&gt; and &lt;code&gt;num&lt;/code&gt; have the same names in Litescrape, so leave them alone.&lt;/p&gt;

&lt;p&gt;Delete two rows with the trash icon:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;engine.&lt;/strong&gt; The URL already says Google Shopping, so this parameter has no job anymore.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;api_key.&lt;/strong&gt; Litescrape wants the key in a header, never in the URL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You're left with:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;q&lt;/td&gt;
&lt;td&gt;20L commuter backpack&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gl&lt;/td&gt;
&lt;td&gt;us&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;hl&lt;/td&gt;
&lt;td&gt;en&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;num&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 3: Send the key in a Bearer Auth credential
&lt;/h2&gt;

&lt;p&gt;Litescrape expects the key in the &lt;code&gt;Authorization&lt;/code&gt; header as a bearer token:&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;Authorization: Bearer YOUR_LITESCRAPE_API_KEY
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You &lt;em&gt;could&lt;/em&gt; add that as a header in the node. Don't. Use a credential instead, so the key is stored encrypted and never shows up in the workflow JSON.&lt;/p&gt;

&lt;p&gt;In the HTTP Request node:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scroll up to &lt;strong&gt;Authentication&lt;/strong&gt; and choose &lt;strong&gt;Generic Credential Type&lt;/strong&gt;. That's the option for any service n8n doesn't have a built-in node for.&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;Generic Auth Type&lt;/strong&gt; to &lt;strong&gt;Bearer Auth&lt;/strong&gt;. It sends &lt;code&gt;Authorization: Bearer &amp;lt;token&amp;gt;&lt;/code&gt;, which is exactly what Litescrape asks for.&lt;/li&gt;
&lt;li&gt;Open the &lt;strong&gt;Bearer Auth&lt;/strong&gt; credential drop-down and click &lt;strong&gt;+ Create new credential&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Paste your Litescrape API key (from the Litescrape dashboard) into &lt;strong&gt;Bearer Token&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Save&lt;/strong&gt;. n8n names it "Bearer Auth account" by default. Rename it to something like "Litescrape" so you can find it later.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's the finished node, as far as it matters:&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Litescrape Google Shopping"&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="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"n8n-nodes-base.httpRequest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&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;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&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://api.litescrape.com/api/google/shopping"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"authentication"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"genericCredentialType"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"genericAuthType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"httpBearerAuth"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sendQuery"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"queryParameters"&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;"parameters"&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"q"&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="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"20L commuter backpack"&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gl"&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="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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hl"&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="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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"num"&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="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5"&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;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"credentials"&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;"httpBearerAuth"&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Litescrape"&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;(That's trimmed to show the settings you change. Don't paste it over your node. Make the edits in the editor so n8n keeps the node's ID and connections.)&lt;/p&gt;

&lt;p&gt;Also rename the node from "SerpApi Google Shopping" to "Litescrape Google Shopping". If any later node refers to it by name, like &lt;code&gt;$('SerpApi Google Shopping')&lt;/code&gt;, update those expressions too, or they'll break.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Test one step, then the whole run
&lt;/h2&gt;

&lt;p&gt;Click &lt;strong&gt;Execute step&lt;/strong&gt; in the node. It sends exactly one request, so it costs one call.&lt;/p&gt;

&lt;p&gt;The response comes back in &lt;code&gt;shopping_results&lt;/code&gt;, and each result has the fields the next nodes already use:&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;"search_information"&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;"query_displayed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"20L commuter backpack"&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;"shopping_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;"Trailhaven Metro 20L Backpack"&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;"Trailhaven"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$89.00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"extracted_price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;89&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"rating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;4.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;"reviews"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1240&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;"Cityline Gear Daypack 20L"&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;"Cityline Gear"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$74.99"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"extracted_price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;74.99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"old_price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$94.99"&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;(The stores and prices are made up for the example.)&lt;/p&gt;

&lt;p&gt;Check these four things in the output:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The array is still called &lt;strong&gt;shopping_results&lt;/strong&gt;, so &lt;strong&gt;Split Out&lt;/strong&gt; still finds it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;title&lt;/strong&gt;, &lt;strong&gt;source&lt;/strong&gt;, &lt;strong&gt;price&lt;/strong&gt; and &lt;strong&gt;extracted_price&lt;/strong&gt; are there with the same names.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;old_price&lt;/strong&gt; only shows up on items that are on sale. That was true before too, but it's worth making sure your Edit Fields mapping handles a missing value.&lt;/li&gt;
&lt;li&gt;Numbers like &lt;code&gt;extracted_price&lt;/code&gt; come back as numbers, not text.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your Edit Fields node maps them like this, nothing downstream changes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight liquid"&gt;&lt;code&gt;Date     &lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;$now.toFormat('yyyy-MM-dd')&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;
Store    &lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;$json.source&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;
Product  &lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;$json.title&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;
Price    &lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;$json.extracted_price.toFixed(2)&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;
Was      &lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;($json.old_price&lt;span class="w"&gt; &lt;/span&gt;??&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;).replace('$',&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;)&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Close the node and click &lt;strong&gt;Execute workflow&lt;/strong&gt; to run the whole thing once. Then open the sheet and look at the new rows. You're checking the actual rows, not the green checkmarks. Green means the node ran. It doesn't mean the data is right.&lt;/p&gt;

&lt;p&gt;If the run looks good and the workflow was already published, click &lt;strong&gt;Publish&lt;/strong&gt; again so the live version uses the new node. Saving alone doesn't change what runs on Monday.&lt;/p&gt;

&lt;h2&gt;
  
  
  If something goes wrong
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;401 or "unauthorized".&lt;/strong&gt; The key isn't reaching the API. Check that Authentication is &lt;strong&gt;Generic Credential Type&lt;/strong&gt; → &lt;strong&gt;Bearer Auth&lt;/strong&gt;, that the right credential is selected, and that you pasted only the key, with no "Bearer " in front. n8n adds that part for you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Results are empty.&lt;/strong&gt; Check that the &lt;code&gt;q&lt;/code&gt; parameter survived the edit, and that you deleted &lt;code&gt;engine&lt;/code&gt; and not &lt;code&gt;q&lt;/code&gt; by mistake.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Split Out says the field doesn't exist.&lt;/strong&gt; Open the HTTP Request output and confirm the array name. If you changed endpoints (for example, from Shopping to regular Google search results), the array name changes too, and Split Out needs the new name.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expressions in later nodes are red.&lt;/strong&gt; You renamed the node, and an expression still points at the old name.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Before you cancel the old plan
&lt;/h2&gt;

&lt;p&gt;Two habits make a swap like this boring, in a good way:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Run both for a week.&lt;/strong&gt; Duplicate the workflow, point the copy at Litescrape, and write to a second tab. Compare the products, positions and prices on Monday. Search results move around between providers and between hours, so you're looking for "same kind of data", not identical rows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the pricing pages yourself.&lt;/strong&gt; Litescrape gives you 5 free calls to try it, then works on prepaid credits. SerpApi works on monthly plans. Check litescrape.com/pricing and SerpApi's pricing page against how many searches you actually run, because the cheaper option depends on your volume.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And whichever provider you use, keep the key in a credential, never in the URL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practice it first, without a real key
&lt;/h2&gt;

&lt;p&gt;I turned this exact swap into a free, hands-on practice lesson. You click through a practice copy of n8n, change the URL, delete the two parameters, set up the Bearer Auth credential and check the sheet. It takes about 7 minutes, and it doesn't use any n8n, Litescrape or Google account. No request is sent, and the API key is a placeholder.&lt;/p&gt;

&lt;p&gt;Disclosure: I run Stepthrough, and Litescrape is one of its partner lessons.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Free lesson: &lt;a href="https://learn.ynteractive.com/content/litescrape-n8n-serpapi-alternative" rel="noopener noreferrer"&gt;Litescrape in n8n: swap SerpApi for a cheaper search API&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>n8n</category>
      <category>automation</category>
      <category>api</category>
      <category>nocode</category>
    </item>
  </channel>
</rss>
