This workflow corresponds to n8n.io template #15887 — we link there as the canonical source.
This workflow follows the Agent → Google Sheets recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "t7c5EWQNzBVrEayH",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Data quality checker",
"tags": [],
"nodes": [
{
"id": "07c0c9f5-4958-470b-8df6-9920a9a39190",
"name": "Groq Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatGroq",
"position": [
1296,
-64
],
"parameters": {
"model": "openai/gpt-oss-safeguard-20b",
"options": {}
},
"credentials": {
"groqApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "80ec759f-3af8-41fb-99cd-7b5400daf1a9",
"name": "Start Data Check",
"type": "n8n-nodes-base.manualTrigger",
"position": [
0,
-224
],
"parameters": {},
"typeVersion": 1
},
{
"id": "6604b97e-6b47-46bb-ad0d-61230b7440c0",
"name": "Get Pricing Data",
"type": "n8n-nodes-base.googleSheets",
"position": [
208,
-224
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1D6mxmcUrhNKZwD2bH_OKe3IZmqYOm8x9d6EAXs_kQBY/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1D6mxmcUrhNKZwD2bH_OKe3IZmqYOm8x9d6EAXs_kQBY",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1D6mxmcUrhNKZwD2bH_OKe3IZmqYOm8x9d6EAXs_kQBY/edit?usp=drivesdk",
"cachedResultName": "Data quality checker"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "2417d119-4ce6-4605-b033-6e962b86de14",
"name": "Process Each Row",
"type": "n8n-nodes-base.splitInBatches",
"position": [
400,
-208
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "2c77d75e-616f-4107-b1f1-97dfa33d0a52",
"name": "Check Price Issues",
"type": "n8n-nodes-base.code",
"position": [
608,
-160
],
"parameters": {
"jsCode": "const price = Number($json.price);\nconst prev = Number($json.previous_price);\n\nlet anomaly = \"\";\nlet status = \"OK\"; // default\n\nif (!price) {\n anomaly = \"Missing Value\";\n status = \"FLAGGED\";\n} else if (prev && prev !== 0) {\n const change = (price - prev) / prev;\n\n if (change > 0.2) {\n anomaly = \"Sudden Spike\";\n status = \"FLAGGED\";\n } else if (change < -0.2) {\n anomaly = \"Sudden Drop\";\n status = \"FLAGGED\";\n }\n}\n\nreturn [{ ...$json, anomaly, status }];"
},
"typeVersion": 2
},
{
"id": "462bf36c-14cd-4893-9b6b-228861bd9dd8",
"name": "Is Issue Found?",
"type": "n8n-nodes-base.if",
"position": [
832,
-240
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "d8b332bf-1a5e-484c-a126-14294de01208",
"operator": {
"type": "string",
"operation": "notEmpty",
"singleValue": true
},
"leftValue": "={{ $json.anomaly }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.3
},
{
"id": "b3f249b0-0448-43cd-a3fe-8dd4e3375f13",
"name": "Generate Issue Reason",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
1264,
-256
],
"parameters": {
"text": "=Anomaly: {{$json.anomaly}}\nPrice:{{ $json.price }}\n\nGive short reason in 3-4 lines",
"options": {},
"promptType": "define"
},
"typeVersion": 3.1
},
{
"id": "e7805735-cce8-467e-b9fe-799c21289add",
"name": "Prepare Flag Data",
"type": "n8n-nodes-base.set",
"position": [
1664,
-192
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "fd821e8a-fc38-48d9-a898-d80cfad36a36",
"name": "reason ",
"type": "string",
"value": "={{ $json.output }}"
},
{
"id": "b48c5a91-6149-477d-9145-7a135ee8e13a",
"name": "status",
"type": "string",
"value": "={{ $('Check Price Issues').item.json.status }}"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "30053d26-5476-453b-a9ea-e8447420a287",
"name": "Update Flagged Row",
"type": "n8n-nodes-base.googleSheets",
"position": [
1888,
-96
],
"parameters": {
"columns": {
"value": {
"reason": "={{ $json['reason '] }}",
"status": "={{ $json.status }}",
"row_number": "={{ $('Check Price Issues').item.json.row_number }}"
},
"schema": [
{
"id": "price",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "price",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "previous_price",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "previous_price",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "status",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "reason",
"type": "string",
"display": true,
"required": false,
"displayName": "reason",
"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/1D6mxmcUrhNKZwD2bH_OKe3IZmqYOm8x9d6EAXs_kQBY/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1D6mxmcUrhNKZwD2bH_OKe3IZmqYOm8x9d6EAXs_kQBY",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1D6mxmcUrhNKZwD2bH_OKe3IZmqYOm8x9d6EAXs_kQBY/edit?usp=drivesdk",
"cachedResultName": "Data quality checker"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "8b709dda-0a0e-46cb-a89d-8a81dfe88a50",
"name": "Update Normal Row",
"type": "n8n-nodes-base.googleSheets",
"position": [
1040,
-144
],
"parameters": {
"columns": {
"value": {
"reason": "Price change is within normal range. No anomaly detected.",
"status": "={{ $json.status }}",
"row_number": "={{ $json.row_number }}"
},
"schema": [
{
"id": "price",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "price",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "previous_price",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "previous_price",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "status",
"type": "string",
"display": true,
"required": false,
"displayName": "status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "reason",
"type": "string",
"display": true,
"required": false,
"displayName": "reason",
"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/1D6mxmcUrhNKZwD2bH_OKe3IZmqYOm8x9d6EAXs_kQBY/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1D6mxmcUrhNKZwD2bH_OKe3IZmqYOm8x9d6EAXs_kQBY",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1D6mxmcUrhNKZwD2bH_OKe3IZmqYOm8x9d6EAXs_kQBY/edit?usp=drivesdk",
"cachedResultName": "Data quality checker"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "2856c0b5-f249-4254-9c20-04f636f904e8",
"name": "Send Slack Alert",
"type": "n8n-nodes-base.slack",
"position": [
2080,
-240
],
"parameters": {
"text": "= Anomaly Detected! Price: {{ $('Get Pricing Data').item.json.price }} Previous Price: {{ $('Get Pricing Data').item.json.previous_price }} Issue: {{ $('Check Price Issues').item.json.anomaly }} Reason: {{$json.reason}}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "C0AQLRM87RS",
"cachedResultName": "data-quality-checker"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.4
},
{
"id": "27c34aca-24ab-4518-9d68-7df7874e79c6",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-432,
-672
],
"parameters": {
"width": 352,
"height": 944,
"content": "# Data Quality Checker\n# How It Works\n\nThis workflow monitors pricing data from Google Sheets and detects anomalies automatically. It reads each row, checks for missing values or sudden price changes and marks them as \u201cFLAGGED\u201d if an issue is found. An AI model generates a short explanation for the anomaly. Flagged rows are updated in the sheet with status and reason and a Slack alert is sent. If no issue is detected, the row is marked \u201cOK\u201d with a normal status message.\n \n# Setup Steps\n## Prepare Google Sheet\nEnsure columns: price, previous_price, status, reason, row_number.\n\n## Connect Accounts in n8n\nAdd Google Sheets, Slack and Groq AI credentials.\n\n## Start Workflow\nUse trigger (manual/webhook).\n\n## Process Data\nCheck anomalies and generate AI reason.\n\n## Update & Alert\nUpdate sheet and send Slack alert for flagged rows."
},
"typeVersion": 1
},
{
"id": "da9c0c7e-ece0-4e3a-9606-b8a554291e45",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-32,
-384
],
"parameters": {
"color": 7,
"width": 784,
"height": 512,
"content": "## Data Fetch & Validation\n\nThe workflow starts by triggering the process, fetches price data from the sheet, processes each row individually and checks for issues like missing values or sudden price changes. This ensures all data is ready for further anomaly detection."
},
"typeVersion": 1
},
{
"id": "9cd0c525-6cc7-4db3-bc44-6a9fb3165a6d",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
784,
-384
],
"parameters": {
"color": 7,
"width": 784,
"height": 512,
"content": "## Anomaly Handling & Updates\n\nThe workflow checks each price for anomalies using the \u201cIf\u201d node. Detected issues are sent to the AI node to generate a short reason and if the value is ok then the Google Sheet is updated with the status ok. "
},
"typeVersion": 1
},
{
"id": "bff886f0-cd45-46bd-a881-db932e6963be",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1616,
-384
],
"parameters": {
"color": 7,
"width": 656,
"height": 528,
"content": "## Flagging & Alerts\n\nThis part of the workflow prepares flagged data with reasons, updates the corresponding rows in the Google Sheet and sends a Slack alert for any anomalies. It ensures all issues are recorded."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "435934de-b0e3-4d0b-ba4f-217c29186d9b",
"connections": {
"Groq Chat Model": {
"ai_languageModel": [
[
{
"node": "Generate Issue Reason",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Is Issue Found?": {
"main": [
[
{
"node": "Generate Issue Reason",
"type": "main",
"index": 0
}
],
[
{
"node": "Update Normal Row",
"type": "main",
"index": 0
}
]
]
},
"Get Pricing Data": {
"main": [
[
{
"node": "Process Each Row",
"type": "main",
"index": 0
}
]
]
},
"Process Each Row": {
"main": [
[],
[
{
"node": "Check Price Issues",
"type": "main",
"index": 0
}
]
]
},
"Start Data Check": {
"main": [
[
{
"node": "Get Pricing Data",
"type": "main",
"index": 0
}
]
]
},
"Prepare Flag Data": {
"main": [
[
{
"node": "Update Flagged Row",
"type": "main",
"index": 0
}
]
]
},
"Update Normal Row": {
"main": [
[
{
"node": "Process Each Row",
"type": "main",
"index": 0
}
]
]
},
"Check Price Issues": {
"main": [
[
{
"node": "Is Issue Found?",
"type": "main",
"index": 0
}
]
]
},
"Update Flagged Row": {
"main": [
[
{
"node": "Process Each Row",
"type": "main",
"index": 0
},
{
"node": "Send Slack Alert",
"type": "main",
"index": 0
}
]
]
},
"Generate Issue Reason": {
"main": [
[
{
"node": "Prepare Flag Data",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
googleSheetsOAuth2ApigroqApislackApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow automatically monitors pricing data in Google Sheets, detects anomalies such as missing values or sudden spikes/drops, generates AI-based short explanations for flagged rows, updates the sheet with status and reason and sends Slack alerts for critical issues.
Source: https://n8n.io/workflows/15887/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Triggered every 4 hours (or manually) to check all active products in Google Sheets Each product is evaluated for stock level and urgency against its reorder threshold Products with sufficient stock a
New hire submits an onboarding form with their details Groq AI generates personalised welcome content, Slack messages, and IT access request Welcome email sent to the new hire via Gmail Automated emai
This workflow automatically analyzes newly uploaded proposals by comparing them with past winning proposals using AI. It extracts proposal content, identifies the client, fetches reference data from G
This workflow automatically generates an AI-powered revenue forecast whenever a new deal is created in HubSpot. It collects all active deals, standardizes key sales data, and sends it to an AI model f
BoomerBobBot.TP. Uses agent, telegramTrigger, telegram, memoryBufferWindow. Event-driven trigger; 95 nodes.