{
  "id": "YFsxtTA9Y4HsGYZS",
  "name": "Competitor Price and Campaign Change Tracker with Google Sheets and Gmail and Open AI",
  "tags": [],
  "nodes": [
    {
      "id": "5f9e9a29-0d50-410e-bcdc-9d1749e904e9",
      "name": "Workflow Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        -48
      ],
      "parameters": {
        "width": 560,
        "height": 784,
        "content": "## \ud83d\udcca Competitor Price & Campaign Change Tracker\n\nThis workflow monitors competitor websites every day and emails you an AI-generated summary of any pricing, plan, or campaign changes.\n\n## How it works\n1. Runs automatically every day at 9 AM\n2. Reads your list of competitor websites from Google Sheets\n3. Fetches each website's HTML and extracts the page text\n4. Loads the previously saved page text from Google Sheets\n5. Uses OpenAI (gpt-4o-mini) to compare both versions and summarize pricing, plan, and campaign changes\n6. Saves the latest page text back to Google Sheets as the new snapshot\n7. Sends a daily HTML report with all detected changes via Gmail\n\n## Setup steps\n1. Create a Google Sheet with a \"Monitored Sites\" tab (columns: Site ID, Site Name, URL) and a \"Snapshots\" tab (columns: Competitor Site ID, Last Fetched At, Page Text)\n2. Add your Google Sheets ID, sheet tab names, and report email address in the Config node\n3. Connect your Google Sheets, OpenAI, and Gmail credentials\n4. Adjust the schedule in the trigger node if needed\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "9585cf9b-bc38-40e9-91be-60b38928d62a",
      "name": "Step 1 - Trigger & Config",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        656,
        -48
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 752,
        "content": "## Trigger & Configuration\nStarts the workflow on a daily schedule and loads all user-configurable settings.\n\n**Daily 9 AM Trigger**: Runs the workflow every day at 9 AM\n**Config**: Stores your Google Sheets ID, sheet tab names, and report email address"
      },
      "typeVersion": 1
    },
    {
      "id": "0d8ad504-02a5-4678-9a0e-04495517758c",
      "name": "Step 2 - Fetch Content",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1104,
        -48
      ],
      "parameters": {
        "color": 7,
        "width": 672,
        "height": 752,
        "content": "## Fetch Website Content\nReads the list of competitor websites from Google Sheets, then fetches each site's HTML and extracts the visible page text for comparison."
      },
      "typeVersion": 1
    },
    {
      "id": "8a90c7f7-780a-4bc0-8e57-8181b9e88620",
      "name": "Step 3 - AI Detection",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1776,
        -48
      ],
      "parameters": {
        "color": 7,
        "width": 672,
        "height": 752,
        "content": "## AI Change Detection\nLoads the previously saved page text and uses OpenAI to:\n- Compare the previous and current page text\n- Summarize pricing, plan, and campaign changes as bullet points\n- Reply \"No changes detected\" when nothing has changed\n- Format each summary into an HTML table row for the report"
      },
      "typeVersion": 1
    },
    {
      "id": "8ced5718-9fa0-4b91-8e5b-75b155b67774",
      "name": "Step 4 - Save & Report",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2448,
        -48
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 752,
        "content": "## Save Snapshot & Send Report\nSaves the latest page text to Google Sheets as the new snapshot, aggregates all site summaries into one HTML table, and emails the daily report via Gmail."
      },
      "typeVersion": 1
    },
    {
      "id": "495e82df-64e5-4012-a5d6-968f5edacbff",
      "name": "Daily 9 AM Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        720,
        416
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 9 * * *"
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "777c0a52-9277-4fe3-903c-2ea3636e7846",
      "name": "Config",
      "type": "n8n-nodes-base.set",
      "position": [
        944,
        416
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "fbfebfa1-fdec-400d-bfcd-e019f97d33b7",
              "name": "GOOGLE_SHEETS_ID",
              "type": "string",
              "value": "YOUR_GOOGLE_SHEETS_ID_HERE"
            },
            {
              "id": "2492d8c5-aaa4-40f2-89fd-ee1b9df3467c",
              "name": "MONITORED_SITES_SHEET_NAME",
              "type": "string",
              "value": "Monitored Sites"
            },
            {
              "id": "6e3d33f9-b87d-41a9-8890-b6cd83046516",
              "name": "SNAPSHOTS_SHEET_NAME",
              "type": "string",
              "value": "Snapshots"
            },
            {
              "id": "f4a7a24c-1e8a-4789-8b7f-c252be96004a",
              "name": "EMAIL_ADDRESS",
              "type": "string",
              "value": "YOUR_EMAIL_ADDRESS_HERE"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "f0f7859f-4b1f-4e06-b554-cd9ac776e6c7",
      "name": "Read Monitored Sites",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1152,
        416
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $json.MONITORED_SITES_SHEET_NAME }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.GOOGLE_SHEETS_ID }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "4e97c7c2-1edb-410f-b566-5c257813de5e",
      "name": "Fetch Website HTML",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1360,
        416
      ],
      "parameters": {
        "url": "={{ $json['URL'] }}",
        "options": {}
      },
      "typeVersion": 4.2
    },
    {
      "id": "a4181df0-9fc0-4d5d-bee1-2e9d590cbfff",
      "name": "Extract Page Text",
      "type": "n8n-nodes-base.htmlExtract",
      "position": [
        1584,
        416
      ],
      "parameters": {
        "options": {},
        "extractionValues": {
          "values": [
            {
              "key": "pageText",
              "cssSelector": "body"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "91072338-41f9-4d83-8bf4-7a9d304b77d5",
      "name": "Read Previous Data",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1808,
        416
      ],
      "parameters": {
        "options": {
          "returnFirstMatch": true
        },
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{ $('Read Monitored Sites').item.json['Site ID'] }}",
              "lookupColumn": "Competitor Site ID"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Config').item.json.SNAPSHOTS_SHEET_NAME }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Config').item.json.GOOGLE_SHEETS_ID }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7,
      "alwaysOutputData": true
    },
    {
      "id": "447f7d64-6d4e-4b31-b2ad-12265ddd1309",
      "name": "Summarize Changes with AI",
      "type": "n8n-nodes-base.openAi",
      "position": [
        2016,
        416
      ],
      "parameters": {
        "prompt": {
          "messages": [
            {
              "role": "system",
              "content": "You are an AI assistant that detects pricing and campaign changes on competitor websites. Compare the previously captured page text with the newly captured page text, and summarize any changes related to pricing, prices, campaigns, or plans as concise bullet points. If nothing has changed, reply with only \"No changes detected\"."
            },
            {
              "content": "=[Monitored Site] {{ $('Read Monitored Sites').item.json['Site Name'] }}\n\n[Previous Page Text]\n{{ ($('Read Previous Data').item.json['Page Text'] ?? '(No previous data - this is the first run)').slice(0, 10000) }}\n\n[Current Page Text]\n{{ $('Extract Page Text').item.json.pageText.slice(0, 10000) }}"
            }
          ]
        },
        "options": {
          "maxTokens": 1000,
          "temperature": 0.3
        },
        "resource": "chat",
        "chatModel": "gpt-4o-mini",
        "requestOptions": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "68c06247-2977-4f25-9683-8c1c0979dec5",
      "name": "Format Results",
      "type": "n8n-nodes-base.set",
      "position": [
        2240,
        416
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "html-row-field",
              "name": "htmlRow",
              "type": "string",
              "value": "=<tr style=\"border-bottom:1px solid #ddd;\"><td style=\"padding:10px 14px;font-weight:bold;min-width:120px;\">{{ $('Read Monitored Sites').item.json['Site Name'] }}</td><td style=\"padding:10px 14px;white-space:pre-wrap;\">{{ $json.message.content }}</td></tr>"
            },
            {
              "id": "site-id-field",
              "name": "siteId",
              "type": "string",
              "value": "={{ $('Read Monitored Sites').item.json['Site ID'] }}"
            },
            {
              "id": "page-text-field",
              "name": "pageText",
              "type": "string",
              "value": "={{ $('Extract Page Text').item.json.pageText.slice(0, 40000) }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "74b69576-09c8-41c0-a54d-84f36ce3aef2",
      "name": "Save Current Data",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2512,
        416
      ],
      "parameters": {
        "columns": {
          "value": {
            "Page Text": "={{ $json.pageText }}",
            "Last Fetched At": "={{ $now.toISO() }}",
            "Competitor Site ID": "={{ $json.siteId }}"
          },
          "schema": [
            {
              "id": "Competitor Site ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Competitor Site ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Last Fetched At",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Last Fetched At",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            },
            {
              "id": "Page Text",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Page Text",
              "defaultMatch": false,
              "canBeUsedToMatch": false
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Competitor Site ID"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Config').item.json.SNAPSHOTS_SHEET_NAME }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Config').item.json.GOOGLE_SHEETS_ID }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "c2ea9862-0ae4-4327-a92a-b94171176a45",
      "name": "Aggregate Results",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        2496,
        256
      ],
      "parameters": {
        "options": {},
        "fieldsToAggregate": {
          "fieldToAggregate": [
            {
              "fieldToAggregate": "htmlRow"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "60fb3f0f-33dd-48bc-9b78-cc95b0f6c9d2",
      "name": "Send Email Report",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2720,
        256
      ],
      "parameters": {
        "sendTo": "={{ $('Config').item.json.EMAIL_ADDRESS }}",
        "message": "=<div style=\"font-family:sans-serif;max-width:700px;\"><h2 style=\"color:#333;border-bottom:2px solid #4a90d9;padding-bottom:8px;\">\ud83d\udcca Competitor Site Daily Monitoring Report</h2><p><strong>Checked At:</strong> {{ $now.format('MMMM dd, yyyy HH:mm') }}</p><table style=\"border-collapse:collapse;width:100%;\"><thead><tr style=\"background:#4a90d9;color:white;\"><th style=\"padding:10px 14px;text-align:left;\">Site Name</th><th style=\"padding:10px 14px;text-align:left;\">Changes Detected</th></tr></thead><tbody>{{ $json.htmlRow.join('') }}</tbody></table><p style=\"color:#888;font-size:12px;margin-top:16px;\">This email was sent automatically by n8n.</p></div>",
        "options": {},
        "subject": "={{ '[Competitor Monitoring Report] Daily Check Results - ' + $now.format('MMMM dd, yyyy') }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "29ae0e3a-397e-4785-9467-8806522d3e54",
  "nodeGroups": [],
  "connections": {
    "Config": {
      "main": [
        [
          {
            "node": "Read Monitored Sites",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Results": {
      "main": [
        [
          {
            "node": "Save Current Data",
            "type": "main",
            "index": 0
          },
          {
            "node": "Aggregate Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate Results": {
      "main": [
        [
          {
            "node": "Send Email Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Page Text": {
      "main": [
        [
          {
            "node": "Read Previous Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Daily 9 AM Trigger": {
      "main": [
        [
          {
            "node": "Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Website HTML": {
      "main": [
        [
          {
            "node": "Extract Page Text",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Previous Data": {
      "main": [
        [
          {
            "node": "Summarize Changes with AI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Monitored Sites": {
      "main": [
        [
          {
            "node": "Fetch Website HTML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Summarize Changes with AI": {
      "main": [
        [
          {
            "node": "Format Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}