Workflow: develop a modular n8n workflow that supports Code Filter Create Scheduled
Integrations: code, filter, googleSheets, httpRequest, if, itemLists, manualTrigger, scheduleTrigger, set, stickyNote

{"meta": {"instanceId": "f0a68da631efd4ed052a324b63ff90f7a844426af0398a68338f44245d1dd9e5"}, "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": {"id": "2", "name": "Google Sheets account lucas"}}, "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": {"id": "MP9W6wBcEfhc6ofn", "name": "SerpAPI account"}}, "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": {"id": "2", "name": "Google Sheets account lucas"}}, "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": {"id": "2", "name": "Google Sheets account lucas"}}, "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": {"id": "2", "name": "Google Sheets account lucas"}}, "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}], "pinData": {}, "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}]]}}}