{
  "nodes": [
    {
      "id": "edef59f6-0197-408e-a819-141c1ca8dedd",
      "name": "When clicking \"Execute Workflow\"",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -1820,
        780
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "d56deaf5-1ad8-45a2-bbf0-3b71560f8036",
      "name": "Extract next start value",
      "type": "n8n-nodes-base.code",
      "position": [
        -640,
        480
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "let nextUrl\n\nif ($json && $json[\"serpapi_pagination\"] && $json[\"serpapi_pagination\"][\"next\"]) {\n    nextUrl = $json[\"serpapi_pagination\"][\"next\"];\n\n$input.item.json.start = nextUrl.split('&').find(param => param.startsWith('start=')).split('=')[1];\n}\n\n\nreturn $input.item;"
      },
      "typeVersion": 2
    },
    {
      "id": "6562c236-c957-437b-91a9-15e98af09858",
      "name": "Merge all values from SERPAPI",
      "type": "n8n-nodes-base.code",
      "position": [
        -140,
        680
      ],
      "parameters": {
        "jsCode": "const allData = []\n\nlet counter = 0;\ndo {\n  try {\n    const items = $items(\"SERPAPI - Scrape Google Maps URL\", 0, counter).map(item => item.json.local_results);\n    allData.push.apply(allData, items);\n  } catch (error) {\n    return [{json: {allData}}];  \n  }\n\n  counter++;\n} while(true);\nreturn $input.all();"
      },
      "typeVersion": 2
    },
    {
      "id": "357e8a57-dbb5-4241-b9c2-863b3ae3fd96",
      "name": "Transform data in the right format",
      "type": "n8n-nodes-base.code",
      "position": [
        380,
        680
      ],
      "parameters": {
        "jsCode": "console.log($input.all())\n\n\nconst data = $input.all()\n\nconsole.log(\"error\",data)\n\nfunction mergeData(data) {\n    let merged = [];\n    data.forEach(entry => {\n        for (const key in entry.json) {\n            merged.push(entry.json[key]);\n        }\n    });\n    return merged;\n}\n\nconst mergedData = mergeData(data);\nconsole.log(mergedData);\n\n\nreturn mergedData.filter(item => item !== null);"
      },
      "typeVersion": 2
    },
    {
      "id": "4e8e9ae9-f5e3-4bfd-b0d4-9403a1c38d39",
      "name": "Add rows in Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        760,
        680
      ],
      "parameters": {
        "columns": {
          "value": {},
          "schema": [
            {
              "id": "position",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "position",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "phone",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "phone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "website",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "website",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "rating",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "rating",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "reviews",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "reviews",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "place_id",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "place_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "data_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "data_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "data_cid",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "data_cid",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "reviews_link",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "reviews_link",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "photos_link",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "photos_link",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "gps_coordinates",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "gps_coordinates",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "place_id_search",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "place_id_search",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "provider_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "provider_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "price",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "price",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "type",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "type",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "types",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "types",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "address",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "address",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "open_state",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "open_state",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "hours",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "hours",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "operating_hours",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "operating_hours",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "description",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "description",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "service_options",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "service_options",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "order_online",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "order_online",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "thumbnail",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "thumbnail",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "editorial_reviews",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "editorial_reviews",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "unclaimed_listing",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "unclaimed_listing",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "autoMapInputData",
          "matchingColumns": [
            "place_id"
          ]
        },
        "options": {
          "cellFormat": "RAW"
        },
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 2023033319,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/170osqaLBql9M-4RAH3_lBKR7ZMaQqyLUkAD-88xGuEQ/edit#gid=2023033319",
          "cachedResultName": "Results"
        },
        "documentId": {
          "__rl": true,
          "mode": "url",
          "value": "https://docs.google.com/spreadsheets/d/170osqaLBql9M-4RAH3_lBKR7ZMaQqyLUkAD-88xGuEQ/edit#gid=2023033319"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "90194aa3-5960-47bd-9e0e-efee827004c4",
      "name": "SERPAPI - Scrape Google Maps URL",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        -920,
        500
      ],
      "parameters": {
        "url": "https://serpapi.com/search.json",
        "options": {},
        "sendQuery": true,
        "authentication": "predefinedCredentialType",
        "queryParameters": {
          "parameters": [
            {
              "name": "engine",
              "value": "google_maps"
            },
            {
              "name": "q",
              "value": "={{$json?.search_parameters?.q || $json.keyword }} "
            },
            {
              "name": "ll",
              "value": "={{ $json?.search_parameters?.ll|| $json.geo }}"
            },
            {
              "name": "type",
              "value": "search"
            },
            {
              "name": "start",
              "value": "={{ $json.start|| 0 }}"
            }
          ]
        },
        "nodeCredentialType": "serpApi"
      },
      "credentials": {
        "serpApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "9cfd1e76-2d7c-4618-86d6-e1f3c7729044",
      "name": "Remove duplicate items",
      "type": "n8n-nodes-base.itemLists",
      "position": [
        580,
        680
      ],
      "parameters": {
        "compare": "selectedFields",
        "options": {},
        "operation": "removeDuplicates",
        "fieldsToCompare": "place_id"
      },
      "typeVersion": 3.1
    },
    {
      "id": "e47dfa17-fc84-4694-950d-165302a9075f",
      "name": "Split out items",
      "type": "n8n-nodes-base.itemLists",
      "position": [
        40,
        680
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "allData"
      },
      "typeVersion": 3.1
    },
    {
      "id": "decc89ee-f836-4ec2-9a1a-0371a8889ef5",
      "name": "Remove empty values",
      "type": "n8n-nodes-base.filter",
      "position": [
        200,
        680
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json[0] }}",
              "operation": "isNotEmpty"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "bd7ca3a5-2697-4653-abf6-372088d925e6",
      "name": "Google Sheets - Get searches  to scrap",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -1380,
        500
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupColumn": "Status"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/170osqaLBql9M-4RAH3_lBKR7ZMaQqyLUkAD-88xGuEQ/edit#gid=0",
          "cachedResultName": "Add your search here"
        },
        "documentId": {
          "__rl": true,
          "mode": "url",
          "value": "https://docs.google.com/spreadsheets/d/170osqaLBql9M-4RAH3_lBKR7ZMaQqyLUkAD-88xGuEQ/edit#gid=0"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "6d0be482-b1ad-4fa0-8d2e-bef9a4414924",
      "name": "Extract keyword and location from URL",
      "type": "n8n-nodes-base.set",
      "position": [
        -1160,
        500
      ],
      "parameters": {
        "fields": {
          "values": [
            {
              "name": "keyword",
              "stringValue": "={{ $json.URL.match(/\\/search\\/(.*?)\\//)[1] }}"
            },
            {
              "name": "geo",
              "stringValue": "={{ $json.URL.match(/(@[^\\/?]+)/)[1]}}"
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.2
    },
    {
      "id": "f6fb8db2-8444-4605-af9d-22ca71c7937d",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1920,
        200
      ],
      "parameters": {
        "width": 312.2965981499806,
        "height": 266.8807730722022,
        "content": "## Adjust frequency to your own needs"
      },
      "typeVersion": 1
    },
    {
      "id": "234b5d18-75d7-495b-960f-06192d9e7c61",
      "name": "Run workflow every hours",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -1800,
        300
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours"
            }
          ]
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "ea2e9b89-e52c-4e25-803a-ce33c41c20fc",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1460,
        200
      ],
      "parameters": {
        "height": 511.2196121145973,
        "content": "## Copy my template and connect it to n8n\n\nTemplate link: \n https://docs.google.com/spreadsheets/d/170osqaLBql9M-4RAH3_lBKR7ZMaQqyLUkAD-88xGuEQ/edit?usp=sharing"
      },
      "typeVersion": 1
    },
    {
      "id": "de515d8d-641d-4b91-9472-608ad3878e32",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -980,
        169.3107006491615
      ],
      "parameters": {
        "height": 535.9388810024284,
        "content": "## Add your SERPAPI API Key\n\nStart a free trial at serpapi.com and get your API key in \"Your account\" section"
      },
      "typeVersion": 1
    },
    {
      "id": "a5a63861-7ff3-4072-a669-acce938939d8",
      "name": "Update Status to Success",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        940,
        680
      ],
      "parameters": {
        "columns": {
          "value": {
            "URL": "={{ $('Google Sheets - Get searches  to scrap').first().json.URL }}",
            "Status": "\u2705"
          },
          "schema": [
            {
              "id": "URL",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "URL"
          ]
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/170osqaLBql9M-4RAH3_lBKR7ZMaQqyLUkAD-88xGuEQ/edit#gid=0",
          "cachedResultName": "Add your search url here"
        },
        "documentId": {
          "__rl": true,
          "mode": "url",
          "value": "https://docs.google.com/spreadsheets/d/170osqaLBql9M-4RAH3_lBKR7ZMaQqyLUkAD-88xGuEQ/edit#gid=0"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "typeVersion": 4.2
    },
    {
      "id": "2bdc5b63-e3bb-453e-a236-9c83cd12cc03",
      "name": "Update Status to Error",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -640,
        620
      ],
      "parameters": {
        "columns": {
          "value": {
            "URL": "={{ $('Google Sheets - Get searches  to scrap').first().json.URL }}",
            "Status": "\u274c"
          },
          "schema": [
            {
              "id": "URL",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "URL"
          ]
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/170osqaLBql9M-4RAH3_lBKR7ZMaQqyLUkAD-88xGuEQ/edit#gid=0",
          "cachedResultName": "Add your search url here"
        },
        "documentId": {
          "__rl": true,
          "mode": "url",
          "value": "https://docs.google.com/spreadsheets/d/170osqaLBql9M-4RAH3_lBKR7ZMaQqyLUkAD-88xGuEQ/edit#gid=0"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "typeVersion": 4.2
    },
    {
      "id": "f413f4ef-fd6d-4967-8df7-a4fee4361246",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1920,
        640
      ],
      "parameters": {
        "width": 312.2965981499806,
        "height": 310.4703136043695,
        "content": "## Click on Execute Workflow to run the workflow manually"
      },
      "typeVersion": 1
    },
    {
      "id": "cbc53e43-f141-434c-a655-feb1f7d3c65b",
      "name": "Continue IF Loop is complete",
      "type": "n8n-nodes-base.if",
      "position": [
        -380,
        620
      ],
      "parameters": {
        "conditions": {
          "number": [
            {
              "value1": "={{ $json.search_parameters.start }}",
              "operation": "isNotEmpty"
            }
          ],
          "string": [
            {
              "value1": "={{ $json.serpapi_pagination.next }}",
              "operation": "isNotEmpty"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "229f9652-b703-490e-aa3c-c28b0fe1f2e8",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2340,
        200
      ],
      "parameters": {
        "width": 357.33341618921213,
        "height": 532.3420004517685,
        "content": "## Read Me\n\nThis workflow allows to scrape Google Maps data in an efficient way using SerpAPI. \n\nYou'll get all data from Gmaps at a cheaper cost than Google Maps API.\n\nAdd as input, your Google Maps search URL and you'll get a list of places with many data points such as:\n- phone number\n- website\n- rating\n- reviews\n- address\n\nAnd much more.\n\n\n**Full guide to implement the workflow is here**: \n\nhttps://lempire.notion.site/Scrape-Google-Maps-places-with-n8n-b7f1785c3d474e858b7ee61ad4c21136?pvs=4"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Split out items": {
      "main": [
        [
          {
            "node": "Remove empty values",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Remove empty values": {
      "main": [
        [
          {
            "node": "Transform data in the right format",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Remove duplicate items": {
      "main": [
        [
          {
            "node": "Add rows in Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract next start value": {
      "main": [
        [
          {
            "node": "Continue IF Loop is complete",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Run workflow every hours": {
      "main": [
        [
          {
            "node": "Google Sheets - Get searches  to scrap",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add rows in Google Sheets": {
      "main": [
        [
          {
            "node": "Update Status to Success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Continue IF Loop is complete": {
      "main": [
        [
          {
            "node": "SERPAPI - Scrape Google Maps URL",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Merge all values from SERPAPI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge all values from SERPAPI": {
      "main": [
        [
          {
            "node": "Split out items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SERPAPI - Scrape Google Maps URL": {
      "main": [
        [
          {
            "node": "Extract next start value",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Update Status to Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking \"Execute Workflow\"": {
      "main": [
        [
          {
            "node": "Google Sheets - Get searches  to scrap",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Transform data in the right format": {
      "main": [
        [
          {
            "node": "Remove duplicate items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract keyword and location from URL": {
      "main": [
        [
          {
            "node": "SERPAPI - Scrape Google Maps URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets - Get searches  to scrap": {
      "main": [
        [
          {
            "node": "Extract keyword and location from URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}