{
  "id": "utArnqVsmeqz3rWi",
  "name": "Template 6: Trustpilot / G2 Review Monitor",
  "tags": [],
  "nodes": [
    {
      "id": "9c5fdac3-c39d-4a6d-b3b9-134f3a73c649",
      "name": "Weekly Review Monitor Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -672,
        144
      ],
      "parameters": {
        "rule": {
          "interval": [
            {}
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "1308ed7d-bcc2-4d29-ad90-f5c7afa6d7ea",
      "name": "Get Competitor URLs",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -448,
        144
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/19UTcz6-wQL6rb37jWHUgneWvm2yEe6HXf24Qo8x2TxY/edit#gid=0",
          "cachedResultName": "Competitors"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "19UTcz6-wQL6rb37jWHUgneWvm2yEe6HXf24Qo8x2TxY",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/19UTcz6-wQL6rb37jWHUgneWvm2yEe6HXf24Qo8x2TxY/edit?usp=drivesdk",
          "cachedResultName": "Competitor Review Monitor"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "643e0173-a31e-47a2-b3dc-cd6cab4fe12a",
      "name": "Loop Through Competitors",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -144,
        144
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "b0a0ca79-e2dc-45cb-93e6-31e35f5fc5a5",
      "name": "Fetch Review Page",
      "type": "n8n-nodes-scrapeunblocker.scrapeUnblocker",
      "position": [
        32,
        0
      ],
      "parameters": {
        "url": "={{ $json[\"Profile URL\"] }}"
      },
      "credentials": {},
      "typeVersion": 1
    },
    {
      "id": "ae375556-dcc2-4d82-98b4-0028eb0b4794",
      "name": "Extract Review Data",
      "type": "n8n-nodes-base.code",
      "position": [
        224,
        0
      ],
      "parameters": {
        "jsCode": "const html = items[0].json;\n\n// Extract all JSON-LD blocks\nconst scriptRegex = /<script[^>]*type=\"application\\/ld\\+json\"[^>]*>([\\s\\S]*?)<\\/script>/gi;\n\nlet match;\nlet software = null;\n\nwhile ((match = scriptRegex.exec(html)) !== null) {\n  try {\n    const json = JSON.parse(match[1]);\n\n    if (json[\"@type\"] === \"SoftwareApplication\" && Array.isArray(json.review)) {\n      software = json;\n      break;\n    }\n  } catch (e) {}\n}\n\nif (!software) {\n  return [{\n    json: {\n      error: \"SoftwareApplication JSON-LD not found.\"\n    }\n  }];\n}\n\nconst reviews = software.review.map(r => ({\n  reviewer: r.author?.name || \"\",\n  title: r.name || \"\",\n  rating: Number(r.reviewRating?.ratingValue || 0),\n  review: (r.reviewBody || \"\")\n    .replace(/<[^>]+>/g, \"\")\n    .replace(/\\s+/g, \" \")\n    .trim(),\n  date: r.datePublished || \"\"\n}));\n\nconst averageRating =\n  reviews.length\n    ? reviews.reduce((sum, r) => sum + r.rating, 0) / reviews.length\n    : 0;\n\nreturn [{\n  json: {\n    company: software.name,\n    totalReviews: reviews.length,\n    averageRating: Number(averageRating.toFixed(2)),\n    reviews\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "a67362b9-562b-42d4-9364-cd8405250f1d",
      "name": "Filter Recent Reviews",
      "type": "n8n-nodes-base.code",
      "position": [
        512,
        0
      ],
      "parameters": {
        "jsCode": "const reviews = $json.reviews || [];\n\nconst today = new Date();\nconst sevenDaysAgo = new Date(today);\nsevenDaysAgo.setDate(today.getDate() - 7);\n\nconst recentReviews = reviews.filter(review => {\n  const reviewDate = new Date(review.date);\n  return reviewDate >= sevenDaysAgo && reviewDate <= today;\n});\n\nconst averageRating = recentReviews.length\n  ? recentReviews.reduce((sum, r) => sum + r.rating, 0) / recentReviews.length\n  : 0;\n\nreturn [{\n  json: {\n    company: $json.company,\n    reviewCount: recentReviews.length,\n    averageRating: Number(averageRating.toFixed(2)),\n    reviews: recentReviews\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "eb686af9-4478-4bd9-8637-8d5ce9e6a871",
      "name": "Check for New Reviews",
      "type": "n8n-nodes-base.if",
      "position": [
        720,
        80
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "d442633d-ab4d-48f9-bf17-7444ab6da1e0",
              "operator": {
                "type": "number",
                "operation": "equals"
              },
              "leftValue": "={{ $json.reviewCount }}",
              "rightValue": 0
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "95270c7d-bfa1-4f29-a9c9-2a6eb3e656ff",
      "name": "Generate AI Review Summary",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        944,
        96
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini",
          "cachedResultName": "GPT-4.1-MINI"
        },
        "options": {},
        "responses": {
          "values": [
            {
              "content": "=You are a competitive intelligence analyst.\n\nAnalyze these competitor reviews from the last 7 days.\n\nCompany:\n{{$json.company}}\n\nAverage Rating:\n{{$json.averageRating}}\n\nNumber of Reviews:\n{{$json.reviewCount}}\n\nReviews:\n{{ JSON.stringify($json.reviews, null, 2) }}\n\nCreate a concise report with:\n\n1. Overall sentiment\n2. Main praise themes\n3. Main complaints\n4. Notable trends\n5. Actionable recommendations for our product team\n\nKeep the report under 250 words and use bullet points."
            }
          ]
        },
        "builtInTools": {}
      },
      "typeVersion": 2.1
    },
    {
      "id": "013cba04-4206-4f87-b8f3-77e74ad9f1f5",
      "name": "Send Weekly Review Digest",
      "type": "n8n-nodes-base.slack",
      "position": [
        1296,
        144
      ],
      "parameters": {
        "text": "=\ud83d\udcca Weekly Competitor Review Digest  \ud83c\udfe2 Company: {{$json.company}}  \u2b50 Average Rating: {{$json.averageRating}}/10  \ud83d\udcdd Reviews This Week: {{$json.reviewCount}}  \ud83e\udd16 AI Summary  {{$json.output}}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "=Your_Channel"
        },
        "otherOptions": {}
      },
      "typeVersion": 2.4
    },
    {
      "id": "7a89355f-507b-4b6c-91f0-04e9538cf647",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1488,
        -192
      ],
      "parameters": {
        "width": 608,
        "height": 736,
        "content": "## Weekly Competitor Review Monitor\n\n### How It Works\n* **Schedule & Source:** Triggers on a weekly schedule, reading target competitor review profile URLs from a designated Google Sheet.\n* **Batch Scraping:** Loops through each competitor URL sequentially and fetches page HTML via **ScrapeUnblocker**.\n* **Extraction & Filtering:** Parses `SoftwareApplication` JSON-LD schema to extract reviewer details and filters for feedback posted within the last 7 days.\n\n### Quick Setup Checklist\n1. **Google Sheets:** Authenticate account and verify spreadsheet ID, tab name (`Competitors`), and the `Profile URL` column name.\n2. **ScrapeUnblocker:** Connect active credentials to enable web scraping.\n\n### Customization\n* **Date Filter Range:** Adjust the 7-day lookback window inside `Filter Recent Reviews` to change summary frequency.\n* **AI Analysis Prompt:** Tweak instructions in `Generate AI Review Summary` to tailor output structure or key focus areas."
      },
      "typeVersion": 1
    },
    {
      "id": "600cb104-4600-4b1a-b3f3-c49f51d84730",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -800,
        -16
      ],
      "parameters": {
        "color": 7,
        "width": 512,
        "height": 384,
        "content": "## 1. Trigger & Competitor Profiles Fetch\nTriggers on a weekly schedule, fetches competitor profile URLs from Google Sheets, and initializes the processing loop."
      },
      "typeVersion": 1
    },
    {
      "id": "b6237b04-5a14-4303-b802-77750fa5e850",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -240,
        -160
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 528,
        "content": "## 2. Scraping & Data Extraction\nScrapes competitor profile pages, parses JSON-LD structured schema for review objects, and filters for entries published within the last 7 days."
      },
      "typeVersion": 1
    },
    {
      "id": "6ad7f2fa-e34d-4d84-adb5-80eef0a26e86",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        432,
        -160
      ],
      "parameters": {
        "color": 7,
        "width": 1040,
        "height": 528,
        "content": "## 3. AI Insights & Slack Dispatch\nEvaluates recent review text using OpenAI to extract sentiment and actionable insights, then posts a digest report to Slack."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "3f7549d1-dcc3-4918-918a-bca8c09b3151",
  "nodeGroups": [],
  "connections": {
    "Fetch Review Page": {
      "main": [
        [
          {
            "node": "Extract Review Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Review Data": {
      "main": [
        [
          {
            "node": "Filter Recent Reviews",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Competitor URLs": {
      "main": [
        [
          {
            "node": "Loop Through Competitors",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check for New Reviews": {
      "main": [
        [
          {
            "node": "Loop Through Competitors",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Generate AI Review Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Recent Reviews": {
      "main": [
        [
          {
            "node": "Check for New Reviews",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Through Competitors": {
      "main": [
        [],
        [
          {
            "node": "Fetch Review Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Weekly Review Digest": {
      "main": [
        [
          {
            "node": "Loop Through Competitors",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate AI Review Summary": {
      "main": [
        [
          {
            "node": "Send Weekly Review Digest",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Weekly Review Monitor Trigger": {
      "main": [
        [
          {
            "node": "Get Competitor URLs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}