{
  "id": "GmyyDpPNB015JRlq",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Review Scraping & AI Outreach Workflow",
  "tags": [],
  "nodes": [
    {
      "id": "62f2881f-043e-4fd3-aafe-7cbebdaacabb",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        3680,
        192
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini",
          "cachedResultName": "gpt-4o-mini"
        },
        "options": {},
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "0ff05c14-d184-4680-91af-9872bc611c33",
      "name": "Process Each Review",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        1344,
        -16
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "c2c8b4d2-8119-4fa8-8c9d-a44acd956476",
      "name": "Check Existing Reviews",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1680,
        0
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{ $('Process Each Review').item.json.id }}",
              "lookupColumn": "Review ID"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1c_HPrB7PZdZJRSjIiG5GIk2b9UoLjfSyt4BUP2FKNCI/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1c_HPrB7PZdZJRSjIiG5GIk2b9UoLjfSyt4BUP2FKNCI",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1c_HPrB7PZdZJRSjIiG5GIk2b9UoLjfSyt4BUP2FKNCI/edit?usp=drivesdk",
          "cachedResultName": "Sathi's Review Data"
        },
        "combineFilters": "OR"
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7,
      "alwaysOutputData": true
    },
    {
      "id": "0cf83690-edcb-44fd-9e52-09fff9ec443d",
      "name": "Log New Review",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2208,
        -16
      ],
      "parameters": {
        "columns": {
          "value": {
            "Date": "={{ $('Process Each Review').item.json.date }}",
            "Rating": "={{ $('Process Each Review').item.json.rating }}",
            "Review ID": "={{ $('Process Each Review').item.json.id }}",
            "Review Text": "={{ $('Process Each Review').item.json.review }}",
            "Competitor URL": "={{ $('Process Each Review').item.json.appReviewUrl }}",
            "Reviewer Domain": "={{ $('Process Each Review').item.json.reviewer }}"
          },
          "schema": [
            {
              "id": "Review ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Review ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Competitor URL",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Competitor URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Rating",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Rating",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Reviewer Domain",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Reviewer Domain",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Website",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Website",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Review Text",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Review Text",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Contact Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Contact Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Contact Title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Contact Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Contact Email",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Contact Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Draft-Email",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Draft-Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1c_HPrB7PZdZJRSjIiG5GIk2b9UoLjfSyt4BUP2FKNCI/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1c_HPrB7PZdZJRSjIiG5GIk2b9UoLjfSyt4BUP2FKNCI",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1c_HPrB7PZdZJRSjIiG5GIk2b9UoLjfSyt4BUP2FKNCI/edit?usp=drivesdk",
          "cachedResultName": "Sathi's Review Data"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "81aa74dd-1903-4366-a0f9-21a98a37b678",
      "name": "Extract Clean Domain",
      "type": "n8n-nodes-base.code",
      "position": [
        3072,
        -16
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Grab the #1 organic link from our Google Search\nlet rawUrl = $input.item.json.organic[0].link;\n\n// Use regex to strip http://, https://, www. and any sub-pages\nlet cleanDomain = rawUrl.replace(/^(?:https?:\\/\\/)?(?:www\\.)?/i, \"\").split('/')[0];\n\n// Add the clean domain to your existing data so you don't lose the review info!\n$input.item.json.domain = cleanDomain;\n\nreturn $input.item;"
      },
      "typeVersion": 2
    },
    {
      "id": "482533f9-83d5-4efe-8b2a-bb28aa5c5e20",
      "name": "Hunter: Find Contact Info",
      "type": "n8n-nodes-base.hunter",
      "position": [
        3392,
        -16
      ],
      "parameters": {
        "limit": 1,
        "domain": "={{ $json.domain }}",
        "filters": {}
      },
      "credentials": {
        "hunterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "0d55243f-ad7e-47d7-9b18-156285358f9c",
      "name": "Generate Outreach Draft",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        3680,
        -16
      ],
      "parameters": {
        "text": "=Write a highly personalized, brief cold email to {{ $('Hunter: Find Contact Info').item.json.first_name || 'the team' }} at {{ $('Extract Clean Domain').item.json.domain }}. \n\nThey just left this review on a competitor's app: \"{{ $('Process Each Review').item.json.review }}\"\n\nAcknowledge their exact frustration with the competitor and pitch SATHI as the reliable, professional solution to their problem. Keep it under 100 words.",
        "batching": {},
        "promptType": "define"
      },
      "typeVersion": 1.9
    },
    {
      "id": "99ee23d4-ba4f-4f81-9f35-6bd551c4341e",
      "name": "Filter 4 Stars or Less",
      "type": "n8n-nodes-base.filter",
      "position": [
        1008,
        -16
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "b2200cbc-6c0c-438f-82a4-86b35dbe3b42",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.reviewer }}",
              "rightValue": ""
            },
            {
              "id": "eba39924-c644-476f-88a2-56dbfadfbe03",
              "operator": {
                "type": "number",
                "operation": "lte"
              },
              "leftValue": "={{ $json.rating }}",
              "rightValue": 4
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "05ae7244-250d-4a12-a562-865efb117a5a",
      "name": "Trigger Daily",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -192,
        -16
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 10,
              "triggerAtMinute": 6
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "ebcc19ea-9d6c-4b4a-8de0-df52fe92d9e7",
      "name": "Set Target App URLs",
      "type": "n8n-nodes-base.code",
      "position": [
        80,
        -16
      ],
      "parameters": {
        "jsCode": "return [\n  { url: \"https://apps.shopify.com/goaffpro/reviews\" },\n  { url: \"https://apps.shopify.com/collabs/reviews\" },\n  { url: \"https://apps.shopify.com/refersion/reviews\" }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "263f8642-18e4-4eeb-a247-422546ec1bd4",
      "name": "Scrape Shopify Reviews",
      "type": "@apify/n8n-nodes-apify.apify",
      "position": [
        400,
        -16
      ],
      "parameters": {
        "actorId": {
          "__rl": true,
          "mode": "list",
          "value": "0PFewmVCG49Vuvg1k",
          "cachedResultUrl": "https://console.apify.com/actors/0PFewmVCG49Vuvg1k/input",
          "cachedResultName": "Shopify App Reviews Scraper (powerai/shopify-app-reviews-scraper)"
        },
        "operation": "Run actor and get dataset",
        "customBody": "={\n  \"appReviewUrl\": \"{{ $json.url }}\",\n  \"maxItems\": 2\n}"
      },
      "credentials": {
        "apifyApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "730f1aef-8732-4078-99cd-4da8b0a19707",
      "name": "Remove Duplicate Reviews",
      "type": "n8n-nodes-base.removeDuplicates",
      "position": [
        736,
        -16
      ],
      "parameters": {
        "compare": "selectedFields",
        "options": {},
        "fieldsToCompare": "id"
      },
      "typeVersion": 2
    },
    {
      "id": "2f82fd49-7052-4193-b702-346a74018d81",
      "name": "If Review is New",
      "type": "n8n-nodes-base.if",
      "position": [
        1968,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "6bb41ab3-53db-4494-9455-cc24be1fba02",
              "operator": {
                "type": "string",
                "operation": "empty",
                "singleValue": true
              },
              "leftValue": "={{ $json['Review ID'] }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "ddf89555-e0fc-4c8c-8364-20ab5c2d1c7b",
      "name": "Search Google for Website",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2800,
        -16
      ],
      "parameters": {
        "url": "https://google.serper.dev/search",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"q\": \"{{ $('Process Each Review').item.json.reviewer }} official website\"\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "7fe47769-e3bf-4ec0-8597-35d5439abbf1",
      "name": "Save Email as Draft",
      "type": "n8n-nodes-base.gmail",
      "position": [
        4032,
        -16
      ],
      "parameters": {
        "message": "={{$json.text.substring($json.text.indexOf('\\n')).trim() }}",
        "options": {
          "sendTo": "={{ $('Hunter: Find Contact Info').item.json.value }}"
        },
        "subject": "={{ $json.text.split('\\n')[0].replace(/Subject:\\s*/i, '').trim() }}",
        "resource": "draft"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "e34f8227-4172-40ce-9967-27d306bdbe98",
      "name": "Update Contact Info",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        4320,
        -16
      ],
      "parameters": {
        "columns": {
          "value": {
            "Status": "=Draft Created",
            "Website": "={{ $('Extract Clean Domain').item.json.domain }}",
            "Review ID": "={{ $('Process Each Review').item.json.id }}",
            "Draft-Email": "={{ $('Generate Outreach Draft').item.json.text }}",
            "Contact Name": "={{ $('Hunter: Find Contact Info').item.json.first_name || 'The Team' }}",
            "Contact Email": "={{ $('Hunter: Find Contact Info').item.json.value }}",
            "Contact Title": "={{ $('Hunter: Find Contact Info').item.json.position_raw || 'Store Owner' }}"
          },
          "schema": [
            {
              "id": "Review ID",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Review ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Date",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Competitor URL",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Competitor URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Rating",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Rating",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Reviewer Domain",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Reviewer Domain",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Website",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Website",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Review Text",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Review Text",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Contact Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Contact Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Contact Title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Contact Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Contact Email",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Contact Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Draft-Email",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Draft-Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Review ID"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1c_HPrB7PZdZJRSjIiG5GIk2b9UoLjfSyt4BUP2FKNCI/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1c_HPrB7PZdZJRSjIiG5GIk2b9UoLjfSyt4BUP2FKNCI",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1c_HPrB7PZdZJRSjIiG5GIk2b9UoLjfSyt4BUP2FKNCI/edit?usp=drivesdk",
          "cachedResultName": "Sathi's Review Data"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "611a96c3-635b-4b85-a1df-bb4e55ca3596",
      "name": "Draft Ready Alert",
      "type": "n8n-nodes-base.slack",
      "position": [
        4592,
        -16
      ],
      "parameters": {
        "text": "=\u2705 Draft ready for {{ $json[\"Contact Name\"] || \"The Team\" }} at {{ $json[\"Website\"] || \"Unknown Website\" }}",
        "select": "channel",
        "blocksUi": "={{\nJSON.stringify({\n  \"blocks\": [\n    {\n      \"type\": \"header\",\n      \"text\": {\n        \"type\": \"plain_text\",\n        \"text\": \"\u2705 Outreach Draft Ready\",\n        \"emoji\": true\n      }\n    },\n    {\n      \"type\": \"section\",\n      \"text\": {\n        \"type\": \"mrkdwn\",\n        \"text\": \"*Contact enrichment and personalized email generation are complete.*\"\n      }\n    },\n    {\n      \"type\": \"section\",\n      \"fields\": [\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"*Website:*\\n\" + ($json[\"Website\"] || \"N/A\")\n        },\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"*Contact Name:*\\n\" + ($json[\"Contact Name\"] || \"The Team\")\n        },\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"*Contact Title:*\\n\" + ($json[\"Contact Title\"] || \"N/A\")\n        },\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"*Contact Email:*\\n\" + ($json[\"Contact Email\"] || \"N/A\")\n        }\n      ]\n    },\n    {\n      \"type\": \"section\",\n      \"text\": {\n        \"type\": \"mrkdwn\",\n        \"text\": \"*Generated Outreach Draft:*\\n```\" + ($json[\"Draft-Email\"] || \"Draft not found\") + \"```\"\n      }\n    },\n    {\n      \"type\": \"context\",\n      \"elements\": [\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"Status: `\" + ($json[\"Status\"] || \"Draft Created\") + \"` \u2022 Review ID: `\" + ($json[\"Review ID\"] || \"N/A\") + \"`\"\n        }\n      ]\n    }\n  ]\n})\n}}",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C091U351YLU",
          "cachedResultName": "customer-support"
        },
        "messageType": "block",
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.4
    },
    {
      "id": "db652eba-ec16-41d1-815d-09e4d9147d38",
      "name": "Alert New Review Detected",
      "type": "n8n-nodes-base.slack",
      "position": [
        2496,
        -16
      ],
      "parameters": {
        "text": "=\ud83d\udea8 New review detected: {{ $json[\"Reviewer Domain\"] || \"Unknown Brand\" }} - {{ $json[\"Rating\"] || \"N/A\" }}\u2b50",
        "select": "channel",
        "blocksUi": "={{\nJSON.stringify({\n  \"blocks\": [\n    {\n      \"type\": \"header\",\n      \"text\": {\n        \"type\": \"plain_text\",\n        \"text\": \"\ud83d\udea8 New Review Detected\",\n        \"emoji\": true\n      }\n    },\n    {\n      \"type\": \"section\",\n      \"fields\": [\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"*Brand / Reviewer:*\\n\" + ($json[\"Reviewer Domain\"] || \"N/A\")\n        },\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"*Rating:*\\n\" + ($json[\"Rating\"] || \"N/A\") + \" \u2b50\"\n        },\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"*Review Date:*\\n\" + ($json[\"Date\"] || \"N/A\")\n        },\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"*Status:*\\nNew Review Detected\"\n        }\n      ]\n    },\n    {\n      \"type\": \"section\",\n      \"text\": {\n        \"type\": \"mrkdwn\",\n        \"text\": \"*Competitor Review Page:*\\n\" + ($json[\"Competitor URL\"] || \"N/A\")\n      }\n    },\n    {\n      \"type\": \"section\",\n      \"text\": {\n        \"type\": \"mrkdwn\",\n        \"text\": \"*Review Text:*\\n> \" + ($json[\"Review Text\"] || \"N/A\")\n      }\n    },\n    {\n      \"type\": \"context\",\n      \"elements\": [\n        {\n          \"type\": \"mrkdwn\",\n          \"text\": \"Review ID: `\" + ($json[\"Review ID\"] || \"N/A\") + \"`\"\n        }\n      ]\n    }\n  ]\n})\n}}",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C091U351YLU",
          "cachedResultName": "customer-support"
        },
        "messageType": "block",
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.4
    },
    {
      "id": "0e627184-1d8d-4326-ac48-e8ff4ca394c8",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -240,
        -160
      ],
      "parameters": {
        "color": "#E5C2C2",
        "width": 208,
        "height": 288,
        "content": "## 1. Trigger Daily\n\n### Purpose\nThis node starts the workflow automatically every day.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "c395f113-62cf-4ddf-a173-3c5f4071a8d9",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -16,
        -288
      ],
      "parameters": {
        "color": "#ECD0DE",
        "width": 288,
        "height": 416,
        "content": "## 2. Set Target App URLs\n\n### Purpose\nThis node defines the competitor Shopify app review pages that should be monitored.\n\n### How It Works\nThe Code node returns a list of Shopify review URLs.\n\nEach URL is passed as a separate item to the next node.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "8e5777fe-5110-47b0-b47b-8e3fccab3644",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        288,
        -400
      ],
      "parameters": {
        "color": "#DAC7E6",
        "width": 336,
        "height": 528,
        "content": "## 3. Scrape Shopify Reviews\n\n### Purpose\nThis node collects recent reviews from each competitor Shopify app review page.\n\n### How It Works\nThe Apify actor receives the review page URL and scrapes review data from that page.  \nIt returns details such as:\n\n- Review ID\n- Rating\n- Review date\n- Reviewer / brand name\n- Review text\n- Review permalink\n- Competitor app URL\n"
      },
      "typeVersion": 1
    },
    {
      "id": "d3b1b06f-dd72-4661-adfb-dc44a485bcb2",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        640,
        -288
      ],
      "parameters": {
        "color": "#C9D7E9",
        "width": 272,
        "height": 416,
        "content": "## 4. Remove Duplicate Reviews\n\n### Purpose\nThis node removes duplicate review records from the scraped data.\n\n### How It Works\nIt compares incoming items using the `id` field.  \nIf the same review appears more than once, only one copy is kept.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "aeb169f7-ba11-4884-b88a-f9d233ea1a46",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        928,
        -464
      ],
      "parameters": {
        "color": "#D2ECD0",
        "width": 304,
        "height": 592,
        "content": "## 5. Filter 4 Stars or Less\n\n### Purpose\nThis node keeps only negative or neutral reviews.\n\n### How It Works\nThe Filter node checks two conditions:\n\n- The reviewer field is not empty\n- The review rating is less than or equal to 4\n\nOnly reviews that match both conditions continue.\n\n### Why It Is Used\nThe workflow is focused on finding merchants who may be unhappy with competitor platforms.  \nLow-rated reviews are more likely to contain pain points and sales opportunities."
      },
      "typeVersion": 1
    },
    {
      "id": "21ab330e-2476-4652-bc88-493038a9259c",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1248,
        -240
      ],
      "parameters": {
        "color": "#ECDEC5",
        "width": 304,
        "height": 368,
        "content": "## 6. Process Each Review\n\n### Purpose\nThis node processes reviews one by one.\n\n### How It Works\nThe Split In Batches node takes the filtered review list and sends one review at a time through the workflow."
      },
      "typeVersion": 1
    },
    {
      "id": "dbdb9d76-7634-4e64-96a4-fabf8328e7ff",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1568,
        -320
      ],
      "parameters": {
        "color": "#ECC5C5",
        "width": 320,
        "height": 448,
        "content": "## 7. Check Existing Reviews\n\n### Purpose\nThis node checks whether the review already exists in the Google Sheet.\n\n### How It Works\nThe Google Sheets node searches the master sheet using the current review\u2019s `Review ID`.\n\nIf the review ID already exists, it means the review was already processed earlier.  \nIf no matching row is found, the review is treated as new."
      },
      "typeVersion": 1
    },
    {
      "id": "ceeafbf1-431f-4c20-8d70-a7dd4621c0ba",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1904,
        -256
      ],
      "parameters": {
        "color": "#C9A9CB",
        "height": 384,
        "content": "## 8. If Review is New\n\n### How It Works\nThe IF node checks whether the `Review ID` returned from Google Sheets is empty.\n\n- If empty: the review is new and continues forward\n- If not empty: the review already exists and is skipped"
      },
      "typeVersion": 1
    },
    {
      "id": "5b8a2b09-7549-45d1-a83d-d17302041c34",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2160,
        -176
      ],
      "parameters": {
        "color": "#ECD0DE",
        "height": 304,
        "content": "## 9. Log New Review\n\n### Purpose\nThis node saves the new review into the Google Sheet.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "4ffd36af-af0e-4d13-92ae-947ddbca0de8",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2416,
        -448
      ],
      "parameters": {
        "color": "#DAC7E6",
        "width": 288,
        "height": 576,
        "content": "## 10. Alert New Review Detected\n\n### Purpose\nThis node sends a Slack alert when a new review is found.\n\n### How It Works\nThe Slack node sends a formatted block message to the selected Slack channel.  \nThe message includes:\n\n- Brand / reviewer name\n- Rating\n- Review date\n- Competitor review page\n- Review text\n- Review ID"
      },
      "typeVersion": 1
    },
    {
      "id": "e7cc426d-6b52-4247-b108-f2821c49edfb",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2720,
        -480
      ],
      "parameters": {
        "color": "#C9D7E9",
        "width": 272,
        "height": 608,
        "content": "## 11. Search Google for Website\n\n### Purpose\nThis node finds the official website of the reviewer or brand.\n\n### How It Works\nThe HTTP Request node sends a search request to Serper using this query format:\n\nreviewer name + official website\n\nThe search results return possible official websites related to the reviewer.\n\n### Why It Is Used\nThe workflow needs the merchant\u2019s website before it can find contact details and generate personalized outreach."
      },
      "typeVersion": 1
    },
    {
      "id": "6559c268-e2c4-488c-8652-be9da7b5208c",
      "name": "Sticky Note11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3008,
        -416
      ],
      "parameters": {
        "color": "#D2ECD0",
        "width": 304,
        "height": 544,
        "content": "## 12. Extract Clean Domain\n\n### Purpose\nThis node extracts a clean domain from the Google search result.\n\n### How It Works\nThe Code node takes the first organic search result URL and removes:\n\n- https://\n- http://\n- www.\n- Extra page paths\n\n### Why It Is Used\nHunter needs a clean domain to search for contact information accurately.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "30b261e2-4f4d-4840-a135-b694720b52ae",
      "name": "Sticky Note12",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3328,
        -368
      ],
      "parameters": {
        "color": "#ECDEC5",
        "width": 304,
        "height": 496,
        "content": "## 13. Hunter: Find Contact Info\n\n### Purpose\nThis node finds a contact email for the merchant\u2019s website.\n\n### How It Works\nThe Hunter node receives the clean domain and searches for available email addresses connected to that domain.\n\n### Why It Is Used\nThe workflow needs a valid contact email before it can create a sales outreach draft."
      },
      "typeVersion": 1
    },
    {
      "id": "dc5ccb3b-e4ac-4f96-bb5c-a9983b227bd0",
      "name": "Sticky Note13",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3648,
        -240
      ],
      "parameters": {
        "color": "#E5C2C2",
        "width": 288,
        "height": 368,
        "content": "## 14. Generate Outreach Draft\n\n### Purpose\nThis node creates a personalized cold email based on the review.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "a076373e-8910-494f-9ffe-bc19983e4d28",
      "name": "Sticky Note14",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3952,
        -272
      ],
      "parameters": {
        "color": "#C9A9CB",
        "width": 288,
        "height": 400,
        "content": "## 15. Save Email as Draft\n\n### Purpose\nThis node saves the AI-generated outreach email as a Gmail draft.\n\n### Why It Is Used\nThis keeps a human approval step in the process.  \nThe sales team can review, edit, and send the email manually."
      },
      "typeVersion": 1
    },
    {
      "id": "8b085122-065e-47d4-926d-2aa97deb5761",
      "name": "Sticky Note15",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4256,
        -368
      ],
      "parameters": {
        "color": "#D2ECD0",
        "height": 496,
        "content": "## 16. Update Contact Info\n\n### Purpose\nThis node updates the Google Sheet with contact and outreach details.\n\nIt adds:\n\n- Website\n- Contact name\n- Contact title\n- Contact email\n- Status\n- Draft email text\n"
      },
      "typeVersion": 1
    },
    {
      "id": "5bcfa315-cb6e-4866-98d0-6777d59b51a1",
      "name": "Sticky Note16",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4512,
        -400
      ],
      "parameters": {
        "color": "#ECDEC5",
        "width": 256,
        "height": 528,
        "content": "## 18. Draft Ready Alert\n\n### Purpose\nThis node notifies the team when the outreach draft is ready.\n\n### How It Works\nThe Slack node sends a formatted message with:\n\n- Website\n- Contact name\n- Contact title\n- Contact email\n- Generated outreach draft\n- Review ID\n- Current status"
      },
      "typeVersion": 1
    },
    {
      "id": "8268e87c-3099-45c3-8cca-47b20183102b",
      "name": "Sticky Note17",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -224,
        -688
      ],
      "parameters": {
        "color": "#E8DFA6",
        "width": 848,
        "height": 272,
        "content": "# Workflow Overview\n\n### This workflow automatically monitors competitor Shopify app reviews every day.  \n### It filters low-rated reviews, removes duplicates, and checks Google Sheets to process only new opportunities.  \n### For each new review, it logs the review, alerts the team in Slack, finds the merchant\u2019s website, enriches contact details using Hunter, and generates a personalized AI outreach email.  \n### The email is saved as a Gmail draft, the Google Sheet is updated, and the team receives a final Slack alert when the draft is ready."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "0e2f06f7-b971-470f-bd5a-db242d67ef5e",
  "connections": {
    "Trigger Daily": {
      "main": [
        [
          {
            "node": "Set Target App URLs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log New Review": {
      "main": [
        [
          {
            "node": "Alert New Review Detected",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Review is New": {
      "main": [
        [
          {
            "node": "Log New Review",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Process Each Review",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Draft Ready Alert": {
      "main": [
        [
          {
            "node": "Process Each Review",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Generate Outreach Draft",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Process Each Review": {
      "main": [
        [],
        [
          {
            "node": "Check Existing Reviews",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Email as Draft": {
      "main": [
        [
          {
            "node": "Update Contact Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Target App URLs": {
      "main": [
        [
          {
            "node": "Scrape Shopify Reviews",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Contact Info": {
      "main": [
        [
          {
            "node": "Draft Ready Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Clean Domain": {
      "main": [
        [
          {
            "node": "Hunter: Find Contact Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Existing Reviews": {
      "main": [
        [
          {
            "node": "If Review is New",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter 4 Stars or Less": {
      "main": [
        [
          {
            "node": "Process Each Review",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scrape Shopify Reviews": {
      "main": [
        [
          {
            "node": "Remove Duplicate Reviews",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Outreach Draft": {
      "main": [
        [
          {
            "node": "Save Email as Draft",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Remove Duplicate Reviews": {
      "main": [
        [
          {
            "node": "Filter 4 Stars or Less",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Alert New Review Detected": {
      "main": [
        [
          {
            "node": "Search Google for Website",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Hunter: Find Contact Info": {
      "main": [
        [
          {
            "node": "Generate Outreach Draft",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Google for Website": {
      "main": [
        [
          {
            "node": "Extract Clean Domain",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}