{
  "id": "psYzSydCkrbiJU2j",
  "name": "n8n_Challenge_Haeng_Franz_Rott",
  "tags": [],
  "nodes": [
    {
      "id": "042eb5f7-dbf1-47c5-a03f-f4e965a48d62",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "notes": "Trigger node \u2013 waits for an HTTP request on /webhook/n8n-challenge and starts the workflow. The final response is supplied by the Respond* nodes.",
      "position": [
        -1820,
        -140
      ],
      "parameters": {
        "path": "example_path",
        "options": {},
        "responseMode": "responseNode"
      },
      "typeVersion": 1
    },
    {
      "id": "71f3e740-7974-4302-94c8-161daa6c71c7",
      "name": "Firecrawl HTTP Request",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "Calls Firecrawl API to scrape the target web page in Markdown and HTML. Uses Bearer-token authentication configured in credentials.",
      "onError": "continueErrorOutput",
      "position": [
        -1600,
        -140
      ],
      "parameters": {
        "url": "<insert_url>",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"url\": \"https://we-hang.com/pages/n8n-automation-expert-challenge\",\n  \"formats\": [\n    \"markdown\",\n    \"html\"\n  ]\n} ",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth"
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "e8e42131-3da1-46ea-814a-247082658576",
      "name": "Get Timestamp",
      "type": "n8n-nodes-base.code",
      "notes": "JavaScript Code node \u2013 attaches a millisecond timestamp to the scraped content (legacy high-port flag kept untouched for compatibility).",
      "onError": "continueErrorOutput",
      "position": [
        -1380,
        -140
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\n\nconst updatedItems = items.map((item) => {\n  if (item.json.data.port > 5000) {\n    item.json.data[\"high-port\"] = true;\n  }\n  return item.json;\n});\n\nconst timestamp = new Date().getTime();\n\nreturn { updatedItems, timestamp };\n"
      },
      "typeVersion": 2
    },
    {
      "id": "7262962a-e5c8-4e87-9b17-80b43557782a",
      "name": "Update Current Content",
      "type": "n8n-nodes-base.googleSheets",
      "notes": "Writes the freshly scraped content into row 2 of the *comparison* sheet (columns current_timestamp & current_content).",
      "onError": "continueErrorOutput",
      "position": [
        -1160,
        -140
      ],
      "parameters": {
        "columns": {
          "value": {
            "row_number": "2",
            "current_content": "={{ $json.updatedItems[0].data.markdown }}",
            "current_timestamp": "={{ $json.timestamp }}"
          },
          "schema": [
            {
              "id": "last_timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "last_timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "last_content",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "last_content",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "current_timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "current_timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "current_content",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "current_content",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "row_number"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 725909638,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g/edit#gid=725909638",
          "cachedResultName": "comparison"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g/edit?usp=drivesdk",
          "cachedResultName": "H\u00e4ng_Log"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "d26b1096-0288-4ca7-8a0c-388996226728",
      "name": "Read Current and Latest Content",
      "type": "n8n-nodes-base.googleSheets",
      "notes": "Loads the same row 2, giving us both last_content and current_content for comparison.",
      "onError": "continueErrorOutput",
      "position": [
        -940,
        -140
      ],
      "parameters": {
        "options": {
          "returnAllMatches": "returnFirstMatch"
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 725909638,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g/edit#gid=725909638",
          "cachedResultName": "comparison"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g/edit?usp=drivesdk",
          "cachedResultName": "H\u00e4ng_Log"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4,
      "alwaysOutputData": true
    },
    {
      "id": "52c5313a-1ebb-4875-8c8b-61b407bc6cab",
      "name": "Is Equal?",
      "type": "n8n-nodes-base.if",
      "notes": "IF node \u2013 checks whether the scraped content changed. True branch \u2192 unchanged, False branch \u2192 changed.",
      "onError": "continueErrorOutput",
      "position": [
        -720,
        -140
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.last_content }}",
              "value2": "={{ $json.current_content }}"
            }
          ]
        },
        "combineOperation": "any"
      },
      "executeOnce": true,
      "typeVersion": 1
    },
    {
      "id": "cd72f620-e31f-4c0d-8835-59ed187a1ccd",
      "name": "Respond Unchanged",
      "type": "n8n-nodes-base.respondToWebhook",
      "notes": "Returns a 200 OK response to the original webhook caller when no change was detected.",
      "position": [
        -500,
        -240
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "3ac13426-967f-46a8-af12-a5cac4bd4b20",
      "name": "Read Latest and Latest Content",
      "type": "n8n-nodes-base.googleSheets",
      "notes": "Reads the current sheet row again on the \u2018changed\u2019 path so subsequent code nodes have the freshest values.",
      "onError": "continueErrorOutput",
      "position": [
        -500,
        -40
      ],
      "parameters": {
        "options": {
          "returnAllMatches": "returnFirstMatch"
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 725909638,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g/edit#gid=725909638",
          "cachedResultName": "comparison"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g/edit?usp=drivesdk",
          "cachedResultName": "H\u00e4ng_Log"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4,
      "alwaysOutputData": true
    },
    {
      "id": "6ca28b23-f8da-4dd1-af41-ca42f76b69f7",
      "name": "Extract Differences",
      "type": "n8n-nodes-base.code",
      "notes": "Splits last & current content into arrays, determines new vs missing segments, attaches another timestamp.",
      "onError": "continueErrorOutput",
      "position": [
        -280,
        -240
      ],
      "parameters": {
        "jsCode": "const items = $input.all().map((item) => item.json);\n\nconst result = items.map((item) => {\n  const lastContent = item.last_content.split(\",\");\n  const currentContent = item.current_content.split(\",\");\n  const newContent = currentContent.filter((i) => !lastContent.includes(i));\n  const missingContent = lastContent.filter((i) => !currentContent.includes(i));\n  return {\n    ...item,\n    newContent,\n    missingContent,\n    timestamp: new Date().getTime(),\n  };\n});\n\nreturn result;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "ec0188a2-f4c0-4f8d-b155-fe5eb67faf8f",
      "name": "Gmail",
      "type": "n8n-nodes-base.gmail",
      "notes": "Sends a plain-text email detailing what changed (first diff only) to n8nchallenge@we-hang.com.",
      "onError": "continueErrorOutput",
      "position": [
        -60,
        -240
      ],
      "parameters": {
        "sendTo": "=example@gmail.com",
        "message": "=Guten Tag, \n\nEs gab eine \u00c4nderung an der beobachteten Website:\n\nUm \"{{ $json.timestamp }}\" wurde \"{{ $json.missingContent[0] }}\" durch \"{{ $json.newContent[0] }}\" ersetzt.\n\nViele Gr\u00fc\u00dfe ",
        "options": {},
        "subject": "Relevante Inhalts\u00e4nderung auf Website",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "1b85582b-48e1-4f70-8df2-fa5dbd505ddd",
      "name": "Append Log Row",
      "type": "n8n-nodes-base.googleSheets",
      "notes": "Adds a new row to *Log* sheet with timestamp & full current content \u2013 creates a historical audit trail.",
      "onError": "continueErrorOutput",
      "position": [
        -60,
        -40
      ],
      "parameters": {
        "columns": {
          "value": {
            "content": "={{ $json.current_content }}",
            "timestamp": "={{ $json.current_timestamp }}"
          },
          "schema": [
            {
              "id": "timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "content",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "content",
              "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/1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g/edit#gid=0",
          "cachedResultName": "Log"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g/edit?usp=drivesdk",
          "cachedResultName": "H\u00e4ng_Log"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "a57f34af-ddca-4973-8c52-7947006cc5fa",
      "name": "Update Latest Content",
      "type": "n8n-nodes-base.googleSheets",
      "notes": "Moves current values into the *last_* columns (row 2) so the next run will compare against them.",
      "onError": "continueErrorOutput",
      "position": [
        -60,
        160
      ],
      "parameters": {
        "columns": {
          "value": {
            "row_number": "2",
            "last_content": "={{ $json.current_content }}",
            "last_timestamp": "={{ $json.current_timestamp }}"
          },
          "schema": [
            {
              "id": "last_timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "last_timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "last_content",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "last_content",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "current_timestamp",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "current_timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "current_content",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "current_content",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "row_number"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 725909638,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g/edit#gid=725909638",
          "cachedResultName": "comparison"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1JashxHNjWMu0IGg7ck6pDxtH6Eo-jVvIIMAWWRspc8g/edit?usp=drivesdk",
          "cachedResultName": "H\u00e4ng_Log"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "69c262ab-fcc5-480f-acff-01c982b68673",
      "name": "Respond Changed",
      "type": "n8n-nodes-base.respondToWebhook",
      "notes": "Returns a success response to the original HTTP call confirming that a change was processed.",
      "position": [
        160,
        60
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "ccbaaf84-52cf-40dd-9147-e09e5c91e71e",
      "name": "\ud83d\udccb SETUP OVERVIEW",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2140,
        -840
      ],
      "parameters": {
        "width": 400,
        "height": 460,
        "content": "\ud83c\udfaf WORKFLOW PURPOSE:\nThis workflow monitors a webpage for content changes and sends email notifications when changes are detected.\n\n\ud83d\udcca KEY COMPONENTS:\n\u2022 Firecrawl API for web scraping\n\u2022 Google Sheets for data storage & comparison\n\u2022 Gmail for notifications\n\u2022 Webhook trigger for external activation\n\n\ud83d\udd04 WORKFLOW FLOW:\nWebhook \u2192 Scrape \u2192 Compare \u2192 Email (if changed) \u2192 Log \u2192 Respond"
      },
      "typeVersion": 1
    },
    {
      "id": "1adc1940-ff74-4454-b841-6e9379c76d9e",
      "name": "\ud83d\udd10 CREDENTIALS SETUP",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1700,
        -840
      ],
      "parameters": {
        "width": 400,
        "height": 460,
        "content": "\u2699\ufe0f REQUIRED CREDENTIALS:\n\n1\ufe0f\u20e3 FIRECRAWL API:\n\u2022 Sign up at https://firecrawl.dev\n\u2022 Get API key from dashboard\n\u2022 Create 'Bearer YOUR_TOKEN_HERE' credential in n8n\n\u2022 Name: 'Bearer YOUR_TOKEN_HERE account'\n\n2\ufe0f\u20e3 GOOGLE SHEETS:\n\u2022 Enable Google Sheets API in Google Cloud Console\n\u2022 Create OAuth2 credentials\n\u2022 Add credential in n8n as 'Google Sheets account'\n\n3\ufe0f\u20e3 GMAIL:\n\u2022 Enable Gmail API in Google Cloud Console\n\u2022 Create OAuth2 credentials\n\u2022 Add credential in n8n as 'Gmail account'"
      },
      "typeVersion": 1
    },
    {
      "id": "38fc9213-614c-467e-af3f-18fe8c62a99e",
      "name": "\ud83d\udcca GOOGLE SHEETS SETUP",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1320,
        100
      ],
      "parameters": {
        "width": 400,
        "height": 300,
        "content": "\ud83d\udccb SPREADSHEET STRUCTURE:\n\n\ud83d\uddc2\ufe0f Create a Google Sheet with 2 tabs:\n\n1\ufe0f\u20e3 'Log' sheet (gid=0):\n\u2022 Column A: timestamp\n\u2022 Column B: content\n\n2\ufe0f\u20e3 'comparison' sheet (gid=725909638):\n\u2022 Column A: last_timestamp\n\u2022 Column B: last_content  \n\u2022 Column C: current_timestamp\n\u2022 Column D: current_content\n\u2022 Column E: row_number\n\u2022 Row 2: Set 'row_number' to '2'\n\n\ud83d\udcdd Copy the spreadsheet ID from the URL and update all Google Sheets nodes with your ID."
      },
      "typeVersion": 1
    },
    {
      "id": "d9a32777-2a21-46ba-a179-534f27616b28",
      "name": "\u2699\ufe0f CONFIGURATION",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1240,
        -840
      ],
      "parameters": {
        "width": 400,
        "height": 460,
        "content": "\ud83d\udd27 CUSTOMIZATION SETTINGS:\n\n\ud83c\udf10 TARGET WEBSITE:\n\u2022 Update Firecrawl node 'url' parameter\n\n\ud83d\udce7 EMAIL SETTINGS:\n\u2022 Update Gmail node 'sendTo' field\n\u2022 Customize subject and message template\n\n\ud83e\ude9d WEBHOOK PATH:\n\u2022 Can be customized in Webhook node\n\n\ud83d\udcc4 SCRAPING FORMAT:\n\u2022 Currently set to markdown + html\n\u2022 Modify in Firecrawl node if needed"
      },
      "typeVersion": 1
    },
    {
      "id": "6b09600c-1a63-4b96-bf3a-eaeb6dfd02f0",
      "name": "\ud83e\uddea TESTING & ACTIVATION",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        980,
        -840
      ],
      "parameters": {
        "width": 400,
        "height": 460,
        "content": "\u2705 TESTING STEPS:\n\n1\ufe0f\u20e3 MANUAL TEST:\n\u2022 Click 'Execute Workflow' button\n\u2022 Check if all nodes execute successfully\n\u2022 Verify Google Sheets get populated\n\u2022 Check if email is sent (if content differs)\n\n2\ufe0f\u20e3 WEBHOOK TEST:\n\u2022 Activate workflow (toggle switch)\n\u2022 Copy webhook URL from Webhook node\n\u2022 Test with curl or Postman:\n  curl -X POST [your-webhook-url]\n\n3\ufe0f\u20e3 TROUBLESHOOTING:\n\u2022 Check node execution logs for errors\n\u2022 Verify all credentials are properly configured\n\u2022 Ensure Google Sheets permissions are correct"
      },
      "typeVersion": 1
    },
    {
      "id": "a43347e4-f5b3-4122-b3b8-45ff925a3402",
      "name": "\ud83e\udd16 AUTOMATION SETUP",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -780,
        -840
      ],
      "parameters": {
        "width": 400,
        "height": 460,
        "content": "\u23f0 SCHEDULING OPTIONS:\n\n\ud83d\udd04 CRON JOB (Recommended):\n\u2022 Set up external cron job to call webhook\n\u2022 Example: */30 * * * * (every 30 minutes)\n\u2022 Command: curl -X POST [webhook-url]\n\n\u26a1 N8N CRON TRIGGER:\n\u2022 Replace Webhook with Cron Trigger node\n\u2022 Set desired interval\n\u2022 Remove Respond nodes (not needed)\n\n\ud83c\udf10 EXTERNAL MONITORING:\n\u2022 Use services like UptimeRobot\n\u2022 Configure to call webhook at intervals\n\u2022 Provides additional monitoring layer"
      },
      "typeVersion": 1
    },
    {
      "id": "8184238c-654e-4b3e-b5f9-e9e8f423fe0f",
      "name": "\ud83d\udd27 MAINTENANCE & MONITORING",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -340,
        -840
      ],
      "parameters": {
        "width": 400,
        "height": 460,
        "content": "\ud83d\udcc8 MONITORING:\n\n\ud83d\udcca EXECUTION HISTORY:\n\u2022 Check n8n execution log regularly\n\u2022 Monitor for failed executions\n\u2022 Set up n8n error notifications\n\n\ud83d\udccb LOG REVIEW:\n\u2022 Check Google Sheets 'Log' tab\n\u2022 Verify timestamps are updating\n\u2022 Monitor content changes over time\n\n\ud83d\udea8 ERROR HANDLING:\n\u2022 All nodes have 'Continue on Error' enabled\n\u2022 Failed nodes won't stop the workflow\n\u2022 Check individual node outputs for issues"
      },
      "typeVersion": 1
    },
    {
      "id": "4b6fd3db-6276-4885-b704-d5709a9ad630",
      "name": "\ud83d\udd12 SECURITY & BEST PRACTICES",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        100,
        -840
      ],
      "parameters": {
        "width": 400,
        "height": 460,
        "content": "\ud83d\udee1\ufe0f SECURITY CONSIDERATIONS:\n\n\ud83d\udd10 API KEYS:\n\u2022 Store all credentials securely in n8n\n\u2022 Never hardcode API keys in workflow\n\u2022 Regularly rotate API keys\n\n\ud83d\udce7 EMAIL SECURITY:\n\u2022 Use dedicated email for notifications\n\u2022 Consider email filtering rules\n\u2022 Monitor for spam/bounce issues\n\n\ud83c\udf10 WEBHOOK SECURITY:\n\u2022 Consider adding authentication\n\u2022 Use HTTPS endpoints only\n\u2022 Monitor webhook access logs\n\n\ud83d\udcbe DATA PRIVACY:\n\u2022 Regularly clean old log entries\n\u2022 Be mindful of scraped content sensitivity"
      },
      "typeVersion": 1
    },
    {
      "id": "10a36c1e-34ef-46dd-83a7-0cd4c6034a6c",
      "name": "\ud83d\udd0d COMMON ISSUES & SOLUTIONS",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        540,
        -840
      ],
      "parameters": {
        "width": 400,
        "height": 460,
        "content": "\u26a0\ufe0f COMMON PROBLEMS:\n\n\ud83d\udeab FIRECRAWL ERRORS:\n\u2022 Check API key validity\n\u2022 Verify target URL is accessible\n\u2022 Check rate limits on Firecrawl account\n\n\ud83d\udcca GOOGLE SHEETS ISSUES:\n\u2022 Verify sheet ID and tab names\n\u2022 Check OAuth permissions\n\u2022 Ensure sheets have correct structure\n\n\ud83d\udce7 EMAIL PROBLEMS:\n\u2022 Check Gmail API quotas\n\u2022 Verify recipient email address\n\u2022 Check spam folders\n\n\ud83e\ude9d WEBHOOK ISSUES:\n\u2022 Ensure workflow is activated\n\u2022 Check webhook URL format\n\u2022 Verify n8n instance is accessible"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "732c1f33-081b-46d4-8fa3-1b497856198b",
  "connections": {
    "Gmail": {
      "main": [
        [
          {
            "node": "Respond Changed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook": {
      "main": [
        [
          {
            "node": "Firecrawl HTTP Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Equal?": {
      "main": [
        [
          {
            "node": "Respond Unchanged",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Read Latest and Latest Content",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Timestamp": {
      "main": [
        [
          {
            "node": "Update Current Content",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append Log Row": {
      "main": [
        [
          {
            "node": "Respond Changed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Differences": {
      "main": [
        [
          {
            "node": "Gmail",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Latest Content": {
      "main": [
        [
          {
            "node": "Respond Changed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Firecrawl HTTP Request": {
      "main": [
        [
          {
            "node": "Get Timestamp",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Current Content": {
      "main": [
        [
          {
            "node": "Read Current and Latest Content",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Latest and Latest Content": {
      "main": [
        [
          {
            "node": "Extract Differences",
            "type": "main",
            "index": 0
          },
          {
            "node": "Append Log Row",
            "type": "main",
            "index": 0
          },
          {
            "node": "Update Latest Content",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Current and Latest Content": {
      "main": [
        [
          {
            "node": "Is Equal?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}