{
  "id": "jtgXNhQVsYEsbwPj",
  "name": "Template 7: Sneaker & Limited Drop Availability Alert",
  "tags": [],
  "nodes": [
    {
      "id": "47b6ab0e-714f-4ea8-b42e-0e80a0939cee",
      "name": "Sneaker Monitor Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -672,
        144
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes"
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "292bb755-f438-4b88-aa57-8c91fb6e39b0",
      "name": "Get Product 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/1Hvk4WqCeZ8hiN_654QI2E9XO25HjKIU1Qo5kKMPMgow/edit#gid=0",
          "cachedResultName": "Products"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1Hvk4WqCeZ8hiN_654QI2E9XO25HjKIU1Qo5kKMPMgow",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1Hvk4WqCeZ8hiN_654QI2E9XO25HjKIU1Qo5kKMPMgow/edit?usp=drivesdk",
          "cachedResultName": "Sneaker Drop Monitor"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "6ee1794c-a9d3-4249-ac4d-1fd86209e6af",
      "name": "Fetch Product Page",
      "type": "n8n-nodes-scrapeunblocker.scrapeUnblocker",
      "position": [
        32,
        16
      ],
      "parameters": {
        "url": "={{ $json[\"Product URL\"] }}",
        "proxy_country": "US"
      },
      "credentials": {},
      "typeVersion": 1
    },
    {
      "id": "3062cabc-c846-456c-bb16-ddbf2e698115",
      "name": "Loop Through Products",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -224,
        144
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "f91913ea-c86c-43eb-b486-c254a6165d60",
      "name": "Extract Product Details",
      "type": "n8n-nodes-base.code",
      "position": [
        304,
        0
      ],
      "parameters": {
        "jsCode": "const html = items[0].json;\n\n// ---------- Product Name ----------\nconst nameMatch = html.match(\n  /<div class=\"col-sm-6 product_main\">[\\s\\S]*?<h1>\\s*([^<]+)\\s*<\\/h1>/i\n);\n\nconst productName = nameMatch\n  ? nameMatch[1].trim()\n  : \"\";\n\n// ---------- Price ----------\nconst priceMatch = html.match(\n  /<p class=\"price_color\">\\s*\u00a3([\\d.]+)\\s*<\\/p>/i\n);\n\nconst price = priceMatch\n  ? parseFloat(priceMatch[1])\n  : null;\n\n// ---------- Stock ----------\nconst stockMatch = html.match(\n  /<p class=\"instock availability\">([\\s\\S]*?)<\\/p>/i\n);\n\nlet stockText = \"\";\n\nif (stockMatch) {\n  stockText = stockMatch[1]\n    .replace(/<[^>]+>/g, \" \")\n    .replace(/\\s+/g, \" \")\n    .trim();\n}\n\nconst currentStatus = stockText.toLowerCase().includes(\"in stock\")\n  ? \"In Stock\"\n  : \"Out of Stock\";\n\n// ---------- Quantity ----------\nconst qtyMatch = stockText.match(/(\\d+)\\s+available/i);\n\nconst quantity = qtyMatch\n  ? Number(qtyMatch[1])\n  : 0;\n\n// ---------- Rating ----------\nconst ratingMatch = html.match(\n  /<p class=\"star-rating\\s+(One|Two|Three|Four|Five)\"/i\n);\n\nconst ratingMap = {\n  One: 1,\n  Two: 2,\n  Three: 3,\n  Four: 4,\n  Five: 5\n};\n\nconst rating = ratingMatch\n  ? ratingMap[ratingMatch[1]]\n  : 0;\n\n// ---------- Previous Status ----------\nconst previousStatus =\n$(\"Get Product URLs\").first().json[\"Last Known Status\"] || \"Out of Stock\";\n\n// ---------- Output ----------\nreturn [{\n  json: {\n    productName,\n    price,\n    stockText,\n    quantity,\n    rating,\n    currentStatus,\n    previousStatus,\n    statusChanged: previousStatus !== currentStatus,\n    lastChecked: new Date().toISOString()\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "28557dd1-b706-4aee-922e-a91ae0cce7f3",
      "name": "Stock Status Changed?",
      "type": "n8n-nodes-base.if",
      "position": [
        512,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "9302dd11-b67e-4f60-b671-ac64c48b465a",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.statusChanged }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "c4e09fc8-ec53-4154-8289-e463ed3e614e",
      "name": "Update Product Status",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        784,
        -16
      ],
      "parameters": {
        "columns": {
          "value": {
            "Last Price": "={{ $json.price }}",
            "row_number": "={{ $('Loop Through Products').item.json.row_number }}",
            "Last Checked": "={{ $json.lastChecked }}",
            "Product Name": "={{ $json.productName }}",
            "Last Known Status": "={{ $json.currentStatus }}"
          },
          "schema": [
            {
              "id": "Product Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Product Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Product URL",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Product URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Last Known Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Last Known Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Last Price",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Last Price",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Available Sizes",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Available Sizes",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Last Checked",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Last Checked",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "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": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1Hvk4WqCeZ8hiN_654QI2E9XO25HjKIU1Qo5kKMPMgow/edit#gid=0",
          "cachedResultName": "Products"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1Hvk4WqCeZ8hiN_654QI2E9XO25HjKIU1Qo5kKMPMgow",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1Hvk4WqCeZ8hiN_654QI2E9XO25HjKIU1Qo5kKMPMgow/edit?usp=drivesdk",
          "cachedResultName": "Sneaker Drop Monitor"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "1269d7a7-236d-4dec-be39-57bcdc5863a9",
      "name": "Send Restock Alert",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1040,
        144
      ],
      "parameters": {
        "sendTo": "YOUR EMAIL",
        "message": "=<p>Hello,</p>  <p>A monitored product has changed its availability status.</p>  <table border=\"1\" cellpadding=\"8\" cellspacing=\"0\" style=\"border-collapse:collapse;\">   <tr>     <td><strong>Product</strong></td>     <td>{{ $('Stock Status Changed?').item.json.productName }}</td>   </tr>   <tr>     <td><strong>Status</strong></td>     <td>{{ $('Stock Status Changed?').item.json.currentStatus }}</td>   </tr>   <tr>     <td><strong>Price</strong></td>     <td>\u00a3{{ $('Stock Status Changed?').item.json.price }}</td>   </tr>   <tr>     <td><strong>Available Quantity</strong></td>     <td>{{ $('Stock Status Changed?').item.json.quantity }}</td>   </tr>   <tr>     <td><strong>Rating</strong></td>     <td>{{ $('Stock Status Changed?').item.json.rating }} / 5</td>   </tr>   <tr>     <td><strong>Last Checked</strong></td>     <td>{{ $('Stock Status Changed?').item.json.lastChecked }}</td>   </tr> </table>  <p> <a href=\"{{$('Get Product URLs').item.json['Product URL']}}\"> View Product </a> </p>  <p>This notification was automatically generated by the Sneaker / Limited Drop Availability Monitor.</p>",
        "options": {},
        "subject": "=\ud83d\udea8 Restock Alert: {{ $json[\"Product Name\"] }} is Back in Stock"
      },
      "typeVersion": 2.2
    },
    {
      "id": "f184f3a1-d46f-46e2-b03e-e628f413efec",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1456,
        -288
      ],
      "parameters": {
        "width": 608,
        "height": 688,
        "content": "## Sneaker / Limited Drop Availability Monitor\n\n### How It Works\n* **Schedule & Source:** Triggers on a minute-based interval, reading target product URLs and their last known statuses from a Google Sheet.\n* **Batch Scraping:** Loops through each product item sequentially and fetches product page HTML using **ScrapeUnblocker** with a US proxy.\n* **Data Extraction:** Parses raw HTML via regex to extract product name, price, stock status, available quantity, and star rating.\n\n\n### Quick Setup Checklist\n1. **Google Sheets:** Connect credentials and verify spreadsheet ID, tab name (`Products`), and columns (`Product URL`, `Last Known Status`, `row_number`).\n2. **ScrapeUnblocker:** Connect active API credentials for proxy-enabled scraping.\n3. **Gmail:** Authenticate your Google account and replace `YOUR EMAIL` in the **Send Restock Alert** node.\n\n### Customization\n* **Interval:** Adjust the trigger frequency in `Sneaker Monitor Trigger` based on drop urgency and API limits.\n* **Regex Selectors:** Update parsing patterns in `Extract Product Details` if monitoring e-commerce sites with different HTML layouts."
      },
      "typeVersion": 1
    },
    {
      "id": "6147c1e6-7eed-487d-86a7-8793573fabf5",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -752,
        -160
      ],
      "parameters": {
        "color": 7,
        "width": 912,
        "height": 576,
        "content": "## 1. Trigger & Target Products Fetch\nTriggers periodically based on the set interval, retrieves product links from Google Sheets, and initializes the processing loop."
      },
      "typeVersion": 1
    },
    {
      "id": "8c0b3498-d45d-4b41-9c07-3ffd37ab7cdf",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        192,
        -176
      ],
      "parameters": {
        "color": 7,
        "width": 496,
        "height": 592,
        "content": "## 2. Scraping & State Evaluation\nScrapes product pages via ScrapeUnblocker, extracts pricing and stock metrics using JS regex, and checks if the availability status has changed."
      },
      "typeVersion": 1
    },
    {
      "id": "90256c7a-35c2-4f12-8447-8c042dd64703",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        -176
      ],
      "parameters": {
        "color": 7,
        "width": 544,
        "height": 592,
        "content": "## 3. Sheet Update & Restock Alerting\nUpdates the Google Sheet record with the latest status and timestamp, then dispatches an automated HTML alert email via Gmail when a restock is detected."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "5b870d20-878d-457e-9aa3-ef0bd03002b4",
  "nodeGroups": [],
  "connections": {
    "Get Product URLs": {
      "main": [
        [
          {
            "node": "Loop Through Products",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Product Page": {
      "main": [
        [
          {
            "node": "Extract Product Details",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Restock Alert": {
      "main": [
        [
          {
            "node": "Loop Through Products",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Through Products": {
      "main": [
        [],
        [
          {
            "node": "Fetch Product Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Stock Status Changed?": {
      "main": [
        [
          {
            "node": "Update Product Status",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Loop Through Products",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Product Status": {
      "main": [
        [
          {
            "node": "Send Restock Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Product Details": {
      "main": [
        [
          {
            "node": "Stock Status Changed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sneaker Monitor Trigger": {
      "main": [
        [
          {
            "node": "Get Product URLs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}