Send daily price-drop digest emails for Amazon, Walmart and Google via ScraperAPI
Pull contacts, verify each address with BillionVerify, and continue to ScraperAPI — only deliverable addresses get through.
Why verify before the send
Sending to invalid, risky, catch-all, or disposable addresses spikes your bounce rate and erodes sender reputation. A verification gate before the ScraperAPI step removes that risk automatically — only deliverable addresses continue, the rest are flagged.
The workflow
BillionVerify — verification sits right before the send.
Node by node
- 1Morning Schedule TriggerTrigger· n8n
Starts the workflow — on a schedule, a webhook, or manually while you test.
- 2Manual Trigger SetupTrigger· n8n
Starts the workflow — on a schedule, a webhook, or manually while you test.
- 3Send Digest via GmailSend· n8n
Sends only to verified, deliverable addresses. Swap in your own provider node if you send elsewhere.
- 4Fetch Products DataSource· n8n
Provides or transforms the contact data flowing through the workflow.
- 5Initialize Products TableSource· n8n
Provides or transforms the contact data flowing through the workflow.
- 6Iterate Products BatchSource· n8n
Provides or transforms the contact data flowing through the workflow.
- 7Initialize History TableSource· n8n
Provides or transforms the contact data flowing through the workflow.
- 8Retrieve Today's Price DropsSource· n8n
Provides or transforms the contact data flowing through the workflow.
- 9Extract Product URLsSource· n8n
Provides or transforms the contact data flowing through the workflow.
- 10Read Existing ProductsSource· n8n
Provides or transforms the contact data flowing through the workflow.
- 11Compile Price Drop DigestSource· n8n
Provides or transforms the contact data flowing through the workflow.
- 12Scrape Amazon DataSource· n8n
Provides or transforms the contact data flowing through the workflow.
- 13Generate Sample ProductsSource· n8n
Provides or transforms the contact data flowing through the workflow.
- 14Verify Email (BillionVerify)Verify· billionverify
The BillionVerify node verifies the address — status (valid / invalid / risky / catch-all / role / disposable), is_deliverable, and a confidence score — before anything is sent.
- 15Scrape Walmart DataSource· n8n
Provides or transforms the contact data flowing through the workflow.
- 16Add Samples to Products TableSource· n8n
Provides or transforms the contact data flowing through the workflow.
- 17IF deliverableLogic· n8n
Branches on the verification result: only deliverable addresses continue to the send; the rest are skipped and flagged.
- 18Scrape Google Shopping DataSource· n8n
Provides or transforms the contact data flowing through the workflow.
- 19Email Price Drop NoticeSend· n8n
Sends only to verified, deliverable addresses. Swap in your own provider node if you send elsewhere.
- 20Analyze Product DataSource· n8n
Provides or transforms the contact data flowing through the workflow.
- 21Divide History ResultsSource· n8n
Provides or transforms the contact data flowing through the workflow.
- 22Refresh Product PricesSource· n8n
Provides or transforms the contact data flowing through the workflow.
- 23Add to Price HistorySource· n8n
Provides or transforms the contact data flowing through the workflow.
Workflow JSON
Copy or download this workflow, then import it in n8n (Workflows → Import from File / Paste). Install the BillionVerify community node first, then add your API key credential.
{
"name": "Send daily price-drop digest emails for Amazon, Walmart and Google via ScraperAPI + BillionVerify",
"nodes": [
{
"id": "d18bd12f-e041-449a-8bca-a8906a2e71cd",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1696,
112
],
"parameters": {
"width": 480,
"height": 896,
"content": "## Email daily price-drop digests from Amazon, Walmart and Google via ScraperAPI\n\n### How it works\n\n1. Triggers the workflow every morning at 8 am or manually during setup.\n2. Initializes or reads product and price tables.\n3. Loops through each product to fetch current product data from various sources.\n4. Compares fetched data and updates product prices.\n5. Checks for price drops, compiles a digest, and sends an email.\n6. Provides an option to send Gmail digest emails.\n\n### Setup steps\n\n- [ ] Set up and verify scheduler trigger timing\n- [ ] Configure database credentials\n- [ ] Set API keys for Amazon, Walmart, Google Shopping\n- [ ] Link an email service provider or SMTP\n- [ ] Ensure that the Gmail module is authenticated\n\n### Customization\n\nYou can customize the schedule to a different time and modify data sources or email templates."
},
"typeVersion": 1
},
{
"id": "a4648c97-6bbd-4dec-a84b-808032d6e46d",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1136,
608
],
"parameters": {
"color": 7,
"width": 416,
"height": 304,
"content": "## Morning trigger setup\n\nTriggers the workflow every morning at 8 am."
},
"typeVersion": 1
},
{
"id": "fe082e45-1237-44e0-91e8-85d220940959",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
0,
0
],
"parameters": {
"color": 7,
"width": 1088,
"height": 272,
"content": "## Manual setup and table initialization\n\nManual trigger to set up product and price history tables."
},
"typeVersion": 1
},
{
"id": "f170729a-c66e-42cf-bb59-ced6db967535",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-688,
608
],
"parameters": {
"color": 7,
"width": 1536,
"height": 320,
"content": "## Fetch and iterate products\n\nFetches all products and prepares for individual product processing."
},
"typeVersion": 1
},
{
"id": "5a425a67-d3db-40d2-9b26-60e9efb40a30",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-464,
304
],
"parameters": {
"color": 7,
"width": 864,
"height": 272,
"content": "## Parse and fetch product data\n\nParses product URLs and fetches data from Amazon, Walmart, and Google Shopping APIs."
},
"typeVersion": 1
},
{
"id": "51e1d161-93c1-488b-b642-7309a7a9f949",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
432,
304
],
"parameters": {
"color": 7,
"width": 640,
"height": 272,
"content": "## Process and compare product data\n\nCompares fetched product data and updates the database with new prices."
},
"typeVersion": 1
},
{
"id": "bf40277a-85a9-4921-8e8d-c13f0f02d0b3",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
448,
1072
],
"parameters": {
"color": 7,
"width": 640,
"height": 272,
"content": "## Price drop analysis and email\n\nFetches today's price drops, creates a digest, and sends out an email notification."
},
"typeVersion": 1
},
{
"id": "b8bdcf9d-8b4f-47d0-9de6-5a2c780793ad",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
896,
1376
],
"parameters": {
"color": 7,
"height": 304,
"content": "## Standalone Gmail email\n\nHandles sending the digest email via Gmail independently."
},
"typeVersion": 1
},
{
"id": "daily-trigger",
"name": "Morning Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-1088,
720
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 8 * * *"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "setup-trigger",
"name": "Manual Trigger Setup",
"type": "n8n-nodes-base.manualTrigger",
"position": [
48,
112
],
"parameters": {},
"typeVersion": 1
},
{
"id": "create-products-table",
"name": "Initialize Products Table",
"type": "n8n-nodes-base.dataTable",
"position": [
240,
112
],
"parameters": {
"columns": {
"column": [
{
"name": "name",
"type": "string"
},
{
"name": "amazon_url",
"type": "string"
},
{
"name": "walmart_url",
"type": "string"
},
{
"name": "track_google_shopping",
"type": "boolean"
},
{
"name": "target_price",
"type": "number"
},
{
"name": "last_amazon_price",
"type": "number"
},
{
"name": "last_walmart_price",
"type": "number"
},
{
"name": "last_google_min_price",
"type": "number"
}
]
},
"options": {
"createIfNotExists": true
},
"resource": "table",
"operation": "create",
"tableName": "products"
},
"typeVersion": 1.1
},
{
"id": "create-history-table",
"name": "Initialize History Table",
"type": "n8n-nodes-base.dataTable",
"position": [
416,
112
],
"parameters": {
"columns": {
"column": [
{
"name": "timestamp",
"type": "string"
},
{
"name": "product_name",
"type": "string"
},
{
"name": "platform",
"type": "string"
},
{
"name": "current_price",
"type": "number"
},
{
"name": "previous_price",
"type": "number"
},
{
"name": "dropped",
"type": "boolean"
},
{
"name": "pct_drop",
"type": "number"
},
{
"name": "error",
"type": "string"
}
]
},
"options": {
"createIfNotExists": true
},
"resource": "table",
"operation": "create",
"tableName": "price_history"
},
"typeVersion": 1.1
},
{
"id": "read-existing-products",
"name": "Read Existing Products",
"type": "n8n-nodes-base.dataTable",
"position": [
592,
112
],
"parameters": {
"filters": {
"conditions": []
},
"resource": "row",
"matchType": "anyCondition",
"operation": "get",
"returnAll": true,
"dataTableId": {
"__rl": true,
"mode": "name",
"value": "products"
}
},
"typeVersion": 1.1,
"alwaysOutputData": true
},
{
"id": "seed-sample-products",
"name": "Generate Sample Products",
"type": "n8n-nodes-base.code",
"position": [
768,
112
],
"parameters": {
"jsCode": "const existingNames = new Set(\n $input.all()\n .map(i => (i.json && i.json.name ? String(i.json.name).trim().toLowerCase() : ''))\n .filter(Boolean)\n);\n\nconst samples = [\n {\n name: 'Samsung Galaxy Watch Ultra',\n amazon_url: 'https://www.amazon.com/dp/B0F7Q4L81N?th=1',\n walmart_url: 'https://www.walmart.com/ip/Samsung-Galaxy-Watch-Ultra-47mm-2025-Edition-Bluetooth-Wi-Fi-4GLTE-Smart-Fitness-Watch-International-Version-Titanium-Blue/17452806183',\n track_google_shopping: true,\n target_price: null,\n last_amazon_price: null,\n last_walmart_price: null,\n last_google_min_price: null,\n },\n {\n name: 'Apple Watch Series 11',\n amazon_url: 'https://www.amazon.com/dp/B0FQFL8PZ5?th=1',\n walmart_url: 'https://www.walmart.com/ip/Apple-Watch-Series-11-GPS-Cellular-42mm-Gold-Titanium-Case-with-Gold-Milanese-Loop/17828855921',\n track_google_shopping: true,\n target_price: null,\n last_amazon_price: null,\n last_walmart_price: null,\n last_google_min_price: null,\n },\n {\n name: 'XIAOMI Redmi Watch 5',\n amazon_url: 'https://www.amazon.com/dp/B0DFZPR9Z4?th=1',\n walmart_url: 'https://www.walmart.com/ip/Redmi-Watch-5-Active-Midnight-Black-18-Day-Battery-Life-2-Inch-Display-5ATM-Waterproof-Bluetooth-Calling-Alexa-Built-In/15893513091',\n track_google_shopping: true,\n target_price: null,\n last_amazon_price: null,\n last_walmart_price: null,\n last_google_min_price: null,\n },\n];\n\nreturn samples\n .filter(s => !existingNames.has(s.name.toLowerCase()))\n .map(s => ({ json: s }));\n",
"language": "javaScript"
},
"typeVersion": 2
},
{
"id": "insert-sample-products",
"name": "Add Samples to Products Table",
"type": "n8n-nodes-base.dataTable",
"position": [
944,
112
],
"parameters": {
"columns": {
"value": {
"name": "={{ $json.name }}",
"amazon_url": "={{ $json.amazon_url }}",
"walmart_url": "={{ $json.walmart_url }}",
"target_price": "={{ $json.target_price }}",
"last_amazon_price": "={{ $json.last_amazon_price }}",
"last_walmart_price": "={{ $json.last_walmart_price }}",
"last_google_min_price": "={{ $json.last_google_min_price }}",
"track_google_shopping": "={{ $json.track_google_shopping }}"
},
"mappingMode": "defineBelow"
},
"options": {},
"resource": "row",
"operation": "insert",
"dataTableId": {
"__rl": true,
"mode": "name",
"value": "products"
}
},
"typeVersion": 1.1
},
{
"id": "read-products",
"name": "Fetch Products Data",
"type": "n8n-nodes-base.dataTable",
"position": [
-864,
720
],
"parameters": {
"filters": {
"conditions": []
},
"resource": "row",
"matchType": "anyCondition",
"operation": "get",
"returnAll": true,
"dataTableId": {
"__rl": true,
"mode": "name",
"value": "products"
}
},
"typeVersion": 1.1
},
{
"id": "per-product-loop",
"name": "Iterate Products Batch",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-544,
720
],
"parameters": {
"options": {},
"batchSize": 1
},
"typeVersion": 3
},
{
"id": "parse-urls",
"name": "Extract Product URLs",
"type": "n8n-nodes-base.code",
"position": [
-416,
416
],
"parameters": {
"jsCode": "const row = $input.first().json;\n\nconst stripQs = (u) => (u || '').split(/[?#]/)[0];\nconst amazonUrl = stripQs(row.amazon_url);\nconst walmartUrl = stripQs(row.walmart_url);\n\nconst asinMatch = amazonUrl.match(/\\/(?:dp|gp\\/product)\\/([A-Z0-9]{10})/i);\nconst walmartMatch = walmartUrl.match(/walmart\\.com\\/ip\\/(?:[^/]+\\/)?(\\d+)/i);\n\nconst trackGoogle = row.track_google_shopping === true || row.track_google_shopping === 'true' || row.track_google_shopping === 1;\n\nreturn [{\n json: {\n id: row.id,\n name: row.name || '',\n amazon_asin: asinMatch ? asinMatch[1].toUpperCase() : '',\n walmart_product_id: walmartMatch ? walmartMatch[1] : '',\n google_query: trackGoogle ? (row.name || '') : '',\n target_price: row.target_price ?? null,\n last_amazon_price: row.last_amazon_price ?? null,\n last_walmart_price: row.last_walmart_price ?? null,\n last_google_min_price: row.last_google_min_price ?? null,\n },\n}];\n",
"language": "javaScript"
},
"typeVersion": 2
},
{
"id": "amazon-sde",
"name": "Scrape Amazon Data",
"type": "n8n-nodes-scraperapi-official.scraperApi",
"maxTries": 2,
"position": [
-192,
416
],
"parameters": {
"sdeAsin": "={{ $('Extract Product URLs').item.json.amazon_asin }}",
"resource": "sde",
"operation": "amazonProduct",
"sdePlatform": "amazon",
"sdeAmazonOptions": {}
},
"retryOnFail": true,
"typeVersion": 1,
"continueOnFail": true,
"waitBetweenTries": 2000
},
{
"id": "walmart-sde",
"name": "Scrape Walmart Data",
"type": "n8n-nodes-scraperapi-official.scraperApi",
"maxTries": 2,
"position": [
32,
416
],
"parameters": {
"resource": "sde",
"operation": "walmartProduct",
"sdePlatform": "walmart",
"sdeProductId": "={{ $('Extract Product URLs').item.json.walmart_product_id }}",
"sdeWalmartOptions": {}
},
"retryOnFail": true,
"typeVersion": 1,
"continueOnFail": true,
"waitBetweenTries": 2000
},
{
"id": "google-shopping-sde",
"name": "Scrape Google Shopping Data",
"type": "n8n-nodes-scraperapi-official.scraperApi",
"maxTries": 2,
"position": [
256,
416
],
"parameters": {
"resource": "sde",
"sdeQuery": "={{ $('Extract Product URLs').item.json.google_query }}",
"operation": "googleShopping",
"sdePlatform": "google",
"sdeGoogleOptions": {}
},
"retryOnFail": true,
"typeVersion": 1,
"continueOnFail": true,
"waitBetweenTries": 2000
},
{
"id": "compare-results",
"name": "Analyze Product Data",
"type": "n8n-nodes-base.code",
"position": [
480,
416
],
"parameters": {
"jsCode": "const parsed = $('Extract Product URLs').item.json;\n\nconst numOrNull = (v) => {\n if (v === null || v === undefined || v === '') return null;\n const s = typeof v === 'string' ? v.replace(/[^0-9.]/g, '') : v;\n const n = parseFloat(s);\n return Number.isFinite(n) ? n : null;\n};\n\nconst getBody = (item) => (item && item.response && item.response.body) || (item && item.body) || item;\n\nconst readPrice = (nodeName, paths) => {\n try {\n const item = $(nodeName).item.json;\n if (!item) return { price: null, error: null };\n if (item.error) {\n const msg = (item.error && (item.error.message || item.error.description)) || String(item.error);\n return { price: null, error: msg };\n }\n const body = getBody(item);\n for (const path of paths) {\n const parts = path.split('.');\n let cur = body;\n for (const p of parts) cur = cur == null ? cur : cur[p];\n const n = numOrNull(cur);\n if (n !== null) return { price: n, error: null };\n }\n return { price: null, error: null };\n } catch (e) {\n return { price: null, error: e.message };\n }\n};\n\nconst amazon = readPrice('Amazon Product', ['pricing', 'list_price', 'price']);\nconst walmart = readPrice('Walmart Product', ['price', 'current_price.price', 'pricing']);\n\nlet google = { price: null, error: null };\ntry {\n const g = $('Scrape Google Shopping Data').item.json;\n if (g && g.error) {\n google.error = (g.error && (g.error.message || g.error.description)) || String(g.error);\n } else if (g) {\n const body = getBody(g);\n const items = body.shopping_results || body.results || [];\n const prices = items\n .map(it => numOrNull(it && (it.extracted_price !== undefined ? it.extracted_price : it.price)))\n .filter(p => p !== null);\n google.price = prices.length ? Math.min(...prices) : null;\n }\n} catch (e) {\n google.error = e.message;\n}\n\nconst ts = new Date().toISOString();\nconst target = parsed.target_price;\n\nconst evaluate = (platform, current, previous, error) => {\n const dropped = current !== null && previous !== null && previous > 0 && current < previous;\n const pct_drop = dropped ? Number((((previous - current) / previous) * 100).toFixed(2)) : 0;\n const crossed_target = Number.isFinite(target) && Number.isFinite(current) && Number.isFinite(previous) && previous > target && current <= target;\n return {\n timestamp: ts,\n product_name: parsed.name,\n platform,\n current_price: current,\n previous_price: previous,\n dropped: dropped || crossed_target,\n pct_drop,\n error: error || '',\n };\n};\n\nconst results = [];\nif (parsed.amazon_asin) results.push(evaluate('amazon', amazon.price, parsed.last_amazon_price, amazon.error));\nif (parsed.walmart_product_id) results.push(evaluate('walmart', walmart.price, parsed.last_walmart_price, walmart.error));\nif (parsed.google_query) results.push(evaluate('google_shopping', google.price, parsed.last_google_min_price, google.error));\n\nconst update = {\n id: parsed.id,\n last_amazon_price: amazon.price !== null ? amazon.price : (parsed.last_amazon_price != null ? parsed.last_amazon_price : null),\n last_walmart_price: walmart.price !== null ? walmart.price : (parsed.last_walmart_price != null ? parsed.last_walmart_price : null),\n last_google_min_price: google.price !== null ? google.price : (parsed.last_google_min_price != null ? parsed.last_google_min_price : null),\n};\n\nreturn [{ json: { results, update } }];\n",
"language": "javaScript"
},
"typeVersion": 2
},
{
"id": "split-history",
"name": "Divide History Results",
"type": "n8n-nodes-base.splitOut",
"position": [
704,
416
],
"parameters": {
"include": "noOtherFields",
"options": {},
"fieldToSplitOut": "results"
},
"typeVersion": 1
},
{
"id": "append-history",
"name": "Add to Price History",
"type": "n8n-nodes-base.dataTable",
"position": [
928,
416
],
"parameters": {
"columns": {
"value": {
"error": "={{ $json.error }}",
"dropped": "={{ $json.dropped }}",
"pct_drop": "={{ $json.pct_drop }}",
"platform": "={{ $json.platform }}",
"timestamp": "={{ $json.timestamp }}",
"product_name": "={{ $json.product_name }}",
"current_price": "={{ $json.current_price }}",
"previous_price": "={{ $json.previous_price }}"
},
"mappingMode": "defineBelow"
},
"options": {},
"resource": "row",
"operation": "insert",
"dataTableId": {
"__rl": true,
"mode": "name",
"value": "price_history"
}
},
"typeVersion": 1.1
},
{
"id": "update-products",
"name": "Refresh Product Prices",
"type": "n8n-nodes-base.dataTable",
"position": [
608,
720
],
"parameters": {
"columns": {
"value": {
"last_amazon_price": "={{ $json.update.last_amazon_price }}",
"last_walmart_price": "={{ $json.update.last_walmart_price }}",
"last_google_min_price": "={{ $json.update.last_google_min_price }}"
},
"mappingMode": "defineBelow"
},
"filters": {
"conditions": [
{
"keyName": "id",
"keyValue": "={{ $json.update.id }}",
"condition": "eq"
}
]
},
"options": {},
"resource": "row",
"matchType": "allConditions",
"operation": "update",
"dataTableId": {
"__rl": true,
"mode": "name",
"value": "products"
}
},
"typeVersion": 1.1
},
{
"id": "read-todays-drops",
"name": "Retrieve Today's Price Drops",
"type": "n8n-nodes-base.dataTable",
"position": [
496,
1184
],
"parameters": {
"filters": {
"conditions": [
{
"keyName": "dropped",
"keyValue": "true",
"condition": "eq"
},
{
"keyName": "timestamp",
"keyValue": "={{ $now.startOf('day').toISO() }}",
"condition": "gte"
}
]
},
"resource": "row",
"matchType": "allConditions",
"operation": "get",
"returnAll": true,
"dataTableId": {
"__rl": true,
"mode": "name",
"value": "price_history"
}
},
"executeOnce": true,
"typeVersion": 1.1
},
{
"id": "build-digest",
"name": "Compile Price Drop Digest",
"type": "n8n-nodes-base.code",
"position": [
720,
1184
],
"parameters": {
"jsCode": "const drops = $input.all().map(i => i.json);\nif (drops.length === 0) return [];\n\ndrops.sort((a, b) => (b.pct_drop || 0) - (a.pct_drop || 0));\n\nconst esc = (s) => String(s == null ? '' : s).replace(/[&<>\"']/g, c => ({'&':'&','<':'<','>':'>','\"':'"',\"'\":'''}[c]));\nconst fmt = (n) => n == null || n === '' ? '—' : '$' + Number(n).toFixed(2);\n\nconst rowsHtml = drops.map(d => `<tr>\n <td>${esc(d.product_name)}</td>\n <td>${esc(d.platform)}</td>\n <td style=\"text-align:right;\">${fmt(d.previous_price)}</td>\n <td style=\"text-align:right;color:#0a7d27;font-weight:600;\">${fmt(d.current_price)}</td>\n <td style=\"text-align:right;\">${d.pct_drop ? d.pct_drop + '%' : '—'}</td>\n</tr>`).join('');\n\nconst subject = `Price drop alert — ${drops.length} product${drops.length === 1 ? '' : 's'} dropped today`;\nconst html = `<div style=\"font-family:-apple-system,Segoe UI,sans-serif;max-width:680px;\">\n <h2 style=\"margin:0 0 12px;\">${subject}</h2>\n <p style=\"color:#555;margin:0 0 16px;\">Fresh prices from Amazon, Walmart, and Google Shopping — collected on autopilot by ScraperAPI.</p>\n <table cellpadding=\"8\" cellspacing=\"0\" style=\"border-collapse:collapse;width:100%;font-size:14px;\">\n <thead><tr style=\"background:#f4f4f6;text-align:left;\">\n <th>Product</th><th>Marketplace</th><th style=\"text-align:right;\">Was</th><th style=\"text-align:right;\">Now</th><th style=\"text-align:right;\">Drop</th>\n </tr></thead>\n <tbody>${rowsHtml}</tbody>\n </table>\n</div>`;\n\nreturn [{ json: { count: drops.length, subject, html } }];\n",
"language": "javaScript"
},
"typeVersion": 2
},
{
"id": "send-email",
"name": "Email Price Drop Notice",
"type": "n8n-nodes-base.emailSend",
"position": [
944,
1184
],
"parameters": {
"html": "={{ $json.html }}",
"options": {},
"subject": "={{ $json.subject }}",
"toEmail": "",
"fromEmail": "",
"emailFormat": "html"
},
"typeVersion": 2.1
},
{
"id": "send-email-gmail",
"name": "Send Digest via Gmail",
"type": "n8n-nodes-base.gmail",
"position": [
944,
1504
],
"parameters": {
"sendTo": "",
"message": "={{ $json.html }}",
"options": {},
"subject": "={{ $json.subject }}",
"emailType": "html"
},
"typeVersion": 2.1
},
{
"parameters": {
"operation": "verify",
"email": "={{ $json.email || $json.Email }}",
"additionalOptions": {}
},
"type": "n8n-nodes-billionverify.billionVerify",
"typeVersion": 1,
"position": [
584,
1184
],
"name": "Verify Email (BillionVerify)",
"credentials": {
"billionVerifyApi": {
"id": "",
"name": "BillionVerify account"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "is-deliverable",
"leftValue": "={{ $json.is_deliverable }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
]
}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
764,
1184
],
"name": "IF deliverable"
}
],
"connections": {
"Scrape Amazon Data": {
"main": [
[
{
"node": "Scrape Walmart Data",
"type": "main",
"index": 0
}
]
]
},
"Fetch Products Data": {
"main": [
[
{
"node": "Iterate Products Batch",
"type": "main",
"index": 0
}
]
]
},
"Scrape Walmart Data": {
"main": [
[
{
"node": "Scrape Google Shopping Data",
"type": "main",
"index": 0
}
]
]
},
"Analyze Product Data": {
"main": [
[
{
"node": "Divide History Results",
"type": "main",
"index": 0
},
{
"node": "Refresh Product Prices",
"type": "main",
"index": 0
}
]
]
},
"Extract Product URLs": {
"main": [
[
{
"node": "Scrape Amazon Data",
"type": "main",
"index": 0
}
]
]
},
"Manual Trigger Setup": {
"main": [
[
{
"node": "Initialize Products Table",
"type": "main",
"index": 0
}
]
]
},
"Divide History Results": {
"main": [
[
{
"node": "Add to Price History",
"type": "main",
"index": 0
}
]
]
},
"Iterate Products Batch": {
"main": [
[
{
"node": "Retrieve Today's Price Drops",
"type": "main",
"index": 0
}
],
[
{
"node": "Extract Product URLs",
"type": "main",
"index": 0
}
]
]
},
"Read Existing Products": {
"main": [
[
{
"node": "Generate Sample Products",
"type": "main",
"index": 0
}
]
]
},
"Refresh Product Prices": {
"main": [
[
{
"node": "Iterate Products Batch",
"type": "main",
"index": 0
}
]
]
},
"Generate Sample Products": {
"main": [
[
{
"node": "Add Samples to Products Table",
"type": "main",
"index": 0
}
]
]
},
"Initialize History Table": {
"main": [
[
{
"node": "Read Existing Products",
"type": "main",
"index": 0
}
]
]
},
"Morning Schedule Trigger": {
"main": [
[
{
"node": "Fetch Products Data",
"type": "main",
"index": 0
}
]
]
},
"Compile Price Drop Digest": {
"main": [
[
{
"node": "Verify Email (BillionVerify)",
"type": "main",
"index": 0
}
]
]
},
"Initialize Products Table": {
"main": [
[
{
"node": "Initialize History Table",
"type": "main",
"index": 0
}
]
]
},
"Scrape Google Shopping Data": {
"main": [
[
{
"node": "Analyze Product Data",
"type": "main",
"index": 0
}
]
]
},
"Retrieve Today's Price Drops": {
"main": [
[
{
"node": "Compile Price Drop Digest",
"type": "main",
"index": 0
}
]
]
},
"Verify Email (BillionVerify)": {
"main": [
[
{
"node": "IF deliverable",
"type": "main",
"index": 0
}
]
]
},
"IF deliverable": {
"main": [
[
{
"node": "Email Price Drop Notice",
"type": "main",
"index": 0
}
],
[]
]
}
},
"settings": {}
}When to use this
- Cleaning a list before a ScraperAPI send or sync.
- Protecting ScraperAPI deliverability and sender reputation.
- Keeping bounce rates low so your sending is never throttled.
FAQ
Why verify before sending in ScraperAPI?
Verifying first keeps your bounce rate low, which protects your sender reputation and your results.
How do I import this workflow?
Download the JSON, then in n8n go to Workflows → Import from File (or paste it). Install the BillionVerify community node and add your API key credential.
What happens to risky or catch-all addresses?
They are routed to the false branch and excluded from the send. You decide whether to retry, review, or drop them.
Add verification to your workflow
Create a free account, grab your API key, and stop bounces before they happen.
Get started free