Competitor price change monitor

Check public product pages daily and get notified when a price changes.

Advanced Saves ~5 hours/month MarketingBy Flowngn team

Works with n8n · Make · Zapier

How it works

Trigger: Schedule — every day
  1. Read the list of product URLs from a sheet.
  2. Fetch each page and extract the price with a CSS selector.
  3. Compare with yesterday's price stored in the sheet.
  4. Email yourself any changes and update the sheet.

Diagram

trueEvery day 10:00Schedule TriggerGRead watchlistGoogle SheetsFetch product pageHTTP Request</>Extract priceHTML{ }Compare pricesCodeGSave new priceGoogle Sheets⑂Price changed?IfGEmail meGmail
Trigger App Logic Code

Code

JavaScript used in the Code step — already included in the template below.

Compare prices · Code node
// Mode: Run Once for Each Item
// Watchlist sheet columns: name | url | selector | last_price
const row = $("Read watchlist").item.json;
const newPrice = parseFloat(String($json.price).replace(/[^0-9.]/g, ""));
const oldPrice = parseFloat(row.last_price);

return {
  json: {
    name: row.name,
    url: row.url,
    old_price: oldPrice,
    last_price: newPrice,
    changed: !isNaN(oldPrice) && !isNaN(newPrice) && newPrice !== oldPrice,
  },
};

Build it

Pick your tool — same automation, step by step.

Copy and paste straight into an n8n canvas (Ctrl+V), or download and use Import from File. Then connect your own credentials and replace every YOUR_… placeholder.

Workflow JSON
Show code (279 lines)
{
  "name": "Competitor price change monitor (Flowngn)",
  "nodes": [
    {
      "parameters": {
        "content": "## Competitor price change monitor\nCheck public product pages daily and get notified when a price changes.\n\n**Setup**\n1. Open each node and connect your own credentials.\n2. Replace every YOUR_… placeholder.\n3. Test once, then activate.\n\nFree template from Flowngn",
        "height": 260,
        "width": 340
      },
      "id": "2c527986-e9cb-4ca8-a3d3-d49e3763bac8",
      "name": "Setup notes",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -420,
        -60
      ]
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 10
            }
          ]
        }
      },
      "id": "2c527986-e9cb-4ca8-a3d3-d49e3763bac8",
      "name": "Every day 10:00",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "operation": "read",
        "documentId": {
          "__rl": true,
          "value": "YOUR_SPREADSHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Watchlist",
          "mode": "name"
        },
        "options": {}
      },
      "id": "2c527986-e9cb-4ca8-a3d3-d49e3763bac8",
      "name": "Read watchlist",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        300,
        0
      ]
    },
    {
      "parameters": {
        "url": "={{ $json.url }}",
        "options": {}
      },
      "id": "2c527986-e9cb-4ca8-a3d3-d49e3763bac8",
      "name": "Fetch product page",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        600,
        0
      ]
    },
    {
      "parameters": {
        "operation": "extractHtmlContent",
        "extractionValues": {
          "values": [
            {
              "key": "price",
              "cssSelector": "={{ $('Read watchlist').item.json.selector }}"
            }
          ]
        },
        "options": {
          "trimValues": true
        }
      },
      "id": "2c527986-e9cb-4ca8-a3d3-d49e3763bac8",
      "name": "Extract price",
      "type": "n8n-nodes-base.html",
      "typeVersion": 1.2,
      "position": [
        900,
        0
      ]
    },
    {
      "parameters": {
        "jsCode": "// Mode: Run Once for Each Item\n// Watchlist sheet columns: name | url | selector | last_price\nconst row = $(\"Read watchlist\").item.json;\nconst newPrice = parseFloat(String($json.price).replace(/[^0-9.]/g, \"\"));\nconst oldPrice = parseFloat(row.last_price);\n\nreturn {\n  json: {\n    name: row.name,\n    url: row.url,\n    old_price: oldPrice,\n    last_price: newPrice,\n    changed: !isNaN(oldPrice) && !isNaN(newPrice) && newPrice !== oldPrice,\n  },\n};",
        "mode": "runOnceForEachItem"
      },
      "id": "2c527986-e9cb-4ca8-a3d3-d49e3763bac8",
      "name": "Compare prices",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1200,
        0
      ]
    },
    {
      "parameters": {
        "operation": "update",
        "documentId": {
          "__rl": true,
          "value": "YOUR_SPREADSHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Watchlist",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "autoMapInputData",
          "value": {},
          "matchingColumns": [
            "url"
          ]
        },
        "options": {}
      },
      "id": "2c527986-e9cb-4ca8-a3d3-d49e3763bac8",
      "name": "Save new price",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        1500,
        0
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose"
          },
          "conditions": [
            {
              "id": "c1",
              "leftValue": "={{ $json.changed }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "2c527986-e9cb-4ca8-a3d3-d49e3763bac8",
      "name": "Price changed?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1500,
        220
      ]
    },
    {
      "parameters": {
        "sendTo": "you@yourcompany.com",
        "subject": "=Price change: {{ $json.name }}",
        "emailType": "text",
        "message": "={{ $json.name }} changed from {{ $json.old_price }} to {{ $json.last_price }}\n{{ $json.url }}",
        "options": {
          "appendAttribution": false
        }
      },
      "id": "2c527986-e9cb-4ca8-a3d3-d49e3763bac8",
      "name": "Email me",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        1800,
        0
      ]
    }
  ],
  "connections": {
    "Every day 10:00": {
      "main": [
        [
          {
            "node": "Read watchlist",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read watchlist": {
      "main": [
        [
          {
            "node": "Fetch product page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch product page": {
      "main": [
        [
          {
            "node": "Extract price",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract price": {
      "main": [
        [
          {
            "node": "Compare prices",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compare prices": {
      "main": [
        [
          {
            "node": "Save new price",
            "type": "main",
            "index": 0
          },
          {
            "node": "Price changed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Price changed?": {
      "main": [
        [
          {
            "node": "Email me",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "tags": []
}

Open in the playground to edit →

Tips

  • Only check a handful of pages, once a day, and respect each site's terms and robots.txt.

Related flows