I used to open 8 browser tabs every morning to check competitor prices on Amazon and eBay. Same products. Same tabs. Same copy-paste into a spreadsheet. Every. Single. Day.
This is 100% automatable. Here's the n8n workflow I built to do it.
What it does
- Runs 3× per day (9am, 3pm, 9pm) or any schedule you set
- Reads a list of product URLs from a Google Sheet
- Fetches each page and extracts the current price
- Compares against the last recorded price
- Emails you instantly if anything changed
- Logs every price check to a history sheet for trend analysis
Zero manual checking. If a competitor drops their price, you know within hours.
The workflow (7 nodes, copy-paste ready)
{
"name": "Price Monitor",
"nodes": [
{
"parameters": { "rule": { "interval": [{ "field": "cronExpression", "expression": "0 9,15,21 * * *" }] } },
"id": "pm1", "name": "Check 3x Daily", "type": "n8n-nodes-base.scheduleTrigger", "typeVersion": 1.2, "position": [240, 300]
},
{
"parameters": {
"operation": "read",
"documentId": { "__rl": true, "value": "YOUR_SHEET_ID", "mode": "id" },
"sheetName": { "__rl": true, "value": "Products", "mode": "name" }
},
"id": "pm2", "name": "Get Product URLs", "type": "n8n-nodes-base.googleSheets", "typeVersion": 4.5, "position": [460, 300]
},
{
"parameters": { "url": "={{ $json.url }}", "options": { "redirect": { "redirect": { "followRedirects": true } } } },
"id": "pm3", "name": "Fetch Product Page", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [680, 300]
},
{
"parameters": {
"jsCode": "const html = $input.first().json.data || '';\nconst prev = $('Get Product URLs').first().json;\nconst priceMatch = html.match(/\\$([\\d,]+\\.?\\d{0,2})/) || html.match(/price['\"]?\\s*[:>]\\s*\\$?([\\d,]+\\.?\\d{0,2})/i);\nconst currentPrice = priceMatch ? parseFloat(priceMatch[1].replace(',', '')) : null;\nconst previousPrice = prev.lastPrice ? parseFloat(prev.lastPrice) : null;\nconst changed = currentPrice !== null && previousPrice !== null && currentPrice !== previousPrice;\nconst direction = changed ? (currentPrice > previousPrice ? 'increased' : 'decreased') : 'unchanged';\nreturn [{ json: { productName: prev.name, url: prev.url, currentPrice, previousPrice, changed, direction, checkedAt: new Date().toISOString() } }];"
},
"id": "pm4", "name": "Extract & Compare Price", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [900, 300]
},
{
"parameters": {
"conditions": { "conditions": [
{ "leftValue": "={{ $json.changed }}", "rightValue": true, "operator": { "type": "boolean", "operation": "true" } }
]}
},
"id": "pm5", "name": "Price Changed?", "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [1120, 300]
},
{
"parameters": {
"sendTo": "your-email@example.com",
"subject": "=Price Alert: {{ $json.productName }} {{ $json.direction }}!",
"message": "=Price change detected!\n\nProduct: {{ $json.productName }}\nPrevious: ${{ $json.previousPrice }}\nCurrent: ${{ $json.currentPrice }}\nDirection: {{ $json.direction }}\nURL: {{ $json.url }}\n\nChecked at: {{ $json.checkedAt }}"
},
"id": "pm6", "name": "Send Alert", "type": "n8n-nodes-base.gmail", "typeVersion": 2.1, "position": [1340, 200]
},
{
"parameters": {
"operation": "append",
"documentId": { "__rl": true, "value": "YOUR_SHEET_ID", "mode": "id" },
"sheetName": { "__rl": true, "value": "PriceHistory", "mode": "name" },
"columns": { "mappingMode": "autoMapInputData" }
},
"id": "pm7", "name": "Log Price History", "type": "n8n-nodes-base.googleSheets", "typeVersion": 4.5, "position": [1340, 420]
}
],
"connections": {
"Check 3x Daily": { "main": [[{ "node": "Get Product URLs", "type": "main", "index": 0 }]] },
"Get Product URLs": { "main": [[{ "node": "Fetch Product Page", "type": "main", "index": 0 }]] },
"Fetch Product Page": { "main": [[{ "node": "Extract & Compare Price", "type": "main", "index": 0 }]] },
"Extract & Compare Price": { "main": [[{ "node": "Price Changed?", "type": "main", "index": 0 }]] },
"Price Changed?": { "main": [[{ "node": "Send Alert", "type": "main", "index": 0 }], [{ "node": "Log Price History", "type": "main", "index": 0 }]] }
},
"settings": { "executionOrder": "v1" },
"tags": [{ "name": "monitoring" }, { "name": "ecommerce" }]
}
Setup (15 minutes)
1. Create the Google Sheet
Make a new sheet with two tabs:
Products tab columns:
| name | url | lastPrice |
|------|-----|-----------|
| Competitor Widget | https://example.com/product | |
| My Amazon Listing | https://amazon.com/dp/B0... | |
PriceHistory tab columns:
| productName | url | currentPrice | previousPrice | changed | direction | checkedAt |
|---|---|---|---|---|---|---|
2. Connect Google Sheets in n8n
Add your Google Sheets credential (OAuth2). Replace YOUR_SHEET_ID in the two Sheets nodes with your actual spreadsheet ID (from the URL: docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit).
3. Connect Gmail
The Send Alert node uses Gmail. Connect your Gmail credential and update the sendTo address to yours.
4. Import the workflow
In n8n: New Workflow → ⋮ menu → Import from JSON → paste the JSON above → Save → Activate.
Done. The workflow runs at 9am, 3pm, and 9pm automatically.
Pro tips
Multiple products at once
The Get Product URLs node returns all rows, and n8n processes each one in sequence via the HTTP Request node. Add 50 products to your sheet — it handles them all in one run.
Adjust the schedule
Change 0 9,15,21 * * * in the Schedule Trigger to any cron expression. For near-real-time monitoring: */30 * * * * (every 30 minutes). For daily digest: 0 8 * * *.
Handle sites that block scrapers
Some sites return 403. Options: (1) Add a User-Agent header in the HTTP Request node → Options → Headers → User-Agent: Mozilla/5.0. (2) Use their public API if available (Amazon has a Product Advertising API, eBay has the Browse API).
Price regex customization
The code node uses two regex patterns that catch most formats. For sites with unusual markup (like €19,99 or 19.99 USD), adjust the regex in pm4.
What I use this for
I track 12 products — mix of my own Amazon listings and 4 direct competitors. When a competitor drops price more than 10%, I usually match within the hour. Before this workflow, I'd notice 3–4 days later (if at all).
The price history log is also useful — after 30 days you start to see patterns. One competitor drops every Friday afternoon. Now I preemptively lower my price Thursday night.
If you want this as a packaged download with the full setup guide, it's part of my FlowKit n8n template collection along with 14 other automations (email auto-responder, Telegram AI bot, invoice generator, customer support bot, and more).
Free to use the JSON above though — that's the whole workflow.
What are you monitoring with n8n? Drop the use case in the comments — curious what variations people are running.
Top comments (0)