This workflow corresponds to n8n.io template #13186 — we link there as the canonical source.
This workflow follows the Google Sheets → HTTP Request 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 →
{
"nodes": [
{
"id": "5d647c78-50ae-4c73-84d8-2a75c895154b",
"name": "Run Workflow Manually",
"type": "n8n-nodes-base.manualTrigger",
"position": [
0,
0
],
"parameters": {},
"typeVersion": 1
},
{
"id": "c24a19f6-a041-4d24-b169-907f45e762ef",
"name": "Read PBN Sites from Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
208,
0
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": 879625869,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1N9xfOX8V6JFATJFaoc-_0xUnYWt-gWD9FmvHKQ0hNfc/edit#gid=879625869",
"cachedResultName": "PBNs"
},
"documentId": {
"__rl": true,
"mode": "url",
"value": "https://docs.google.com/spreadsheets/d/1N9xfOX8V6JFATJFaoc-_0xUnYWt-gWD9FmvHKQ0hNfc/edit?gid=879625869#gid=879625869"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "2c18d612-aa4f-4cae-81f6-5b3744eba319",
"name": "Filter Unprocessed PBN Rows",
"type": "n8n-nodes-base.code",
"position": [
416,
0
],
"parameters": {
"jsCode": "// Input: All rows from Google Sheet\n// Output: Rows starting from the first row where \"Offboarded Links\" is blank\n\nlet rows = items.map(item => item.json);\n\n// Find the index of the first row where \"Offboarded Links\" is blank or empty\nlet startIndex = rows.findIndex(row => \n row[\"Offboarded Links\"] === \"\" || row[\"Offboarded Links\"] === null || row[\"Offboarded Links\"] === undefined\n);\n\n// \u0905\u0917\u0930 \u0915\u094b\u0908 match \u0928\u0939\u0940\u0902 \u092e\u093f\u0932\u093e \u0924\u094b \u0916\u093e\u0932\u0940 array return \u0915\u0930\u094b\nif (startIndex === -1) {\n return [];\n}\n\n// \u0909\u0938 row \u0938\u0947 \u0932\u0947\u0915\u0930 \u092c\u093e\u0915\u0940 \u0938\u092d\u0940 rows return \u0915\u0930\u094b\nlet filteredRows = rows.slice(startIndex);\n\n// Output \u0915\u094b n8n \u0915\u0947 \u0932\u093f\u090f format \u0915\u0930\u094b\nreturn filteredRows.map(row => ({ json: row }));\n"
},
"typeVersion": 2
},
{
"id": "a66eb36b-46ef-4cc0-89be-2e53c32d5d24",
"name": "Loop Through Each PBN",
"type": "n8n-nodes-base.splitInBatches",
"position": [
624,
0
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "f48e6d1c-5ff6-45c3-9ca0-780b01ce4640",
"name": "Fetch PBN Site HTML",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueRegularOutput",
"position": [
864,
16
],
"parameters": {
"url": "=https://{{ $json['Site URL'] }}",
"options": {}
},
"retryOnFail": true,
"typeVersion": 4.2,
"waitBetweenTries": 3000
},
{
"id": "404d6187-7fd6-4811-8844-fc4e3712b6fe",
"name": "Read Offboarded Project Domains",
"type": "n8n-nodes-base.googleSheets",
"position": [
1072,
16
],
"parameters": {
"options": {
"dataLocationOnSheet": {
"values": {
"range": "A1:A",
"rangeDefinition": "specifyRangeA1"
}
}
},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1N9xfOX8V6JFATJFaoc-_0xUnYWt-gWD9FmvHKQ0hNfc/edit#gid=0",
"cachedResultName": "offboard projects"
},
"documentId": {
"__rl": true,
"mode": "url",
"value": "https://docs.google.com/spreadsheets/d/1N9xfOX8V6JFATJFaoc-_0xUnYWt-gWD9FmvHKQ0hNfc/edit?gid=879625869#gid=879625869"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "05c73580-d4c0-4da1-973b-e5e5e2a10f7b",
"name": "Match Domains in HTML",
"type": "n8n-nodes-base.code",
"position": [
1280,
16
],
"parameters": {
"jsCode": "// Get input domains\nconst inputItems = $input.all();\nconst domains = inputItems.map(item => {\n try {\n const url = new URL(item.json[\"Website URLs\"]);\n return url.hostname.replace(/^www\\./, \"\"); // Remove www.\n } catch (e) {\n return null;\n }\n}).filter(Boolean);\n\n// Get HTML Data\nconst htmlData = $('Fetch PBN Site HTML').first().json.data;\n\n// Check matches\nlet matched = [];\nfor (const domain of domains) {\n if (htmlData.includes(domain)) {\n matched.push(domain);\n }\n}\n\n// Return result\nif (matched.length > 0) {\n return matched.map(d => ({ json: { matched_domain: d } }));\n} else {\n return [{ json: { matched_domain: 0 } }];\n}\n"
},
"typeVersion": 2
},
{
"id": "30df9e6e-4ca4-4f50-8021-6d76ee8ebdab",
"name": "Prepare Row Update Payload",
"type": "n8n-nodes-base.set",
"position": [
1488,
16
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "3efc5b75-e346-45df-8cb9-e9efd6aa8bcd",
"name": "url",
"type": "string",
"value": "={{ $('Loop Through Each PBN').first().json[\"row_number\"] }}\n"
},
{
"id": "fca4ac9b-3ee6-4aba-b0a4-ef0782caa373",
"name": "mach",
"type": "string",
"value": "={{ $json.matched_domain }}"
},
{
"id": "035b2872-896c-4c52-9216-c7f5bc5a4963",
"name": "HTML",
"type": "string",
"value": "={{ $('Fetch PBN Site HTML').first().json[\"data\"] }}\n"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "db8377d6-1fe3-4ec6-916f-1794aef3b426",
"name": "Write Matched Domain to PBNs Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
1680,
16
],
"parameters": {
"columns": {
"value": {
"row_number": "={{ $json.url }}",
"Offboarded Links": "={{ $json.mach }}"
},
"schema": [
{
"id": "Site URL",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Site URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Offboarded Links",
"type": "string",
"display": true,
"required": false,
"displayName": "Offboarded Links",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "HTML",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "HTML",
"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": 879625869,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1N9xfOX8V6JFATJFaoc-_0xUnYWt-gWD9FmvHKQ0hNfc/edit#gid=879625869",
"cachedResultName": "PBNs"
},
"documentId": {
"__rl": true,
"mode": "url",
"value": "https://docs.google.com/spreadsheets/d/1N9xfOX8V6JFATJFaoc-_0xUnYWt-gWD9FmvHKQ0hNfc/edit?gid=0#gid=0"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7,
"alwaysOutputData": true
},
{
"id": "17a1feff-ba0f-4323-b817-83b7f34b9ed5",
"name": "Pause Before Next Iteration",
"type": "n8n-nodes-base.wait",
"position": [
1856,
16
],
"parameters": {},
"typeVersion": 1.1
},
{
"id": "bdbdc364-db6a-4cfe-aee2-2c8dc244bbbf",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-480,
-240
],
"parameters": {
"width": 432,
"height": 656,
"content": "## PBN Offboarded Link Checker\n\nThis workflow automatically checks all PBN sites to detect\nif any offboarded client domain is still linked on them.\nIt runs row by row, fetches live HTML of each PBN, and\ncompares it against your offboard project list. If a match\nis found, it writes the matched domain directly into the\n\"Offboarded Links\" column in your PBNs sheet \u2014 so you\nalways know which PBN still carries a dead link.\n\n## How it works\n1. Reads all PBN sites from the \"PBNs\" Google Sheet.\n2. Skips rows already processed (where \"Offboarded Links\" is filled).\n3. Loops one by one \u2014 fetches live HTML of each PBN site.\n4. Pulls the offboarded project domain list from a separate sheet.\n5. Checks if any offboarded domain exists inside that HTML.\n6. Writes the matched domain into the PBNs sheet & moves to next.\n\n## Setup steps\n1. Connect your Google account in credentials.\n2. Set the correct Google Sheet URL & sheet names.\n3. Make sure \"offboard projects\" sheet has domains in Column A.\n4. Run manually using the trigger node."
},
"typeVersion": 1
},
{
"id": "742384c7-ca32-484b-845c-30c6ccfddd79",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
208,
-144
],
"parameters": {
"color": 7,
"width": 304,
"height": 192,
"content": "## Data Fetching\n\nReads all PBN rows from Google Sheets,\nthen filters out already-processed rows\nso only new/unchecked PBNs move forward."
},
"typeVersion": 1
},
{
"id": "10e0cfbe-8107-4e4d-9ec4-9c4d65783514",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
624,
-144
],
"parameters": {
"color": 7,
"width": 752,
"height": 208,
"content": "## HTML Fetch & Domain Matching\n\nLoops through each PBN one by one, fetches\nits live HTML, then checks if any offboarded\nclient domain is present inside that HTML."
},
"typeVersion": 1
},
{
"id": "eac0c950-5152-44e3-b124-2845a12826d0",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1488,
-144
],
"parameters": {
"color": 7,
"width": 464,
"height": 208,
"content": "## Update & Loop Back\n\nStructures the matched result, writes it\ninto the PBNs sheet, then pauses briefly\nbefore moving to the next PBN in the loop."
},
"typeVersion": 1
}
],
"connections": {
"Fetch PBN Site HTML": {
"main": [
[
{
"node": "Read Offboarded Project Domains",
"type": "main",
"index": 0
}
]
]
},
"Loop Through Each PBN": {
"main": [
[],
[
{
"node": "Fetch PBN Site HTML",
"type": "main",
"index": 0
}
]
]
},
"Match Domains in HTML": {
"main": [
[
{
"node": "Prepare Row Update Payload",
"type": "main",
"index": 0
}
]
]
},
"Run Workflow Manually": {
"main": [
[
{
"node": "Read PBN Sites from Sheet",
"type": "main",
"index": 0
}
]
]
},
"Read PBN Sites from Sheet": {
"main": [
[
{
"node": "Filter Unprocessed PBN Rows",
"type": "main",
"index": 0
}
]
]
},
"Prepare Row Update Payload": {
"main": [
[
{
"node": "Write Matched Domain to PBNs Sheet",
"type": "main",
"index": 0
}
]
]
},
"Filter Unprocessed PBN Rows": {
"main": [
[
{
"node": "Loop Through Each PBN",
"type": "main",
"index": 0
}
]
]
},
"Pause Before Next Iteration": {
"main": [
[
{
"node": "Loop Through Each PBN",
"type": "main",
"index": 0
}
]
]
},
"Read Offboarded Project Domains": {
"main": [
[
{
"node": "Match Domains in HTML",
"type": "main",
"index": 0
}
]
]
},
"Write Matched Domain to PBNs Sheet": {
"main": [
[
{
"node": "Pause Before Next Iteration",
"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.
googleSheetsOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Automatically scan every PBN site in your Google Sheet, check if any removed client domain is still linked in the live HTML, and log all matches back into your tracking sheet — row by row, hands-free.
Source: https://n8n.io/workflows/13186/ — 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.
This template is ideal for solo store owners, eCommerce marketers, automation beginners, or anyone using Shopify and Gmail who wants to recover lost revenue without coding.
PCN. Uses googleSheets, httpRequest, @n-octo-n/n8n-nodes-json-database, itemLists. Event-driven trigger; 60 nodes.
The workflow automates the process of gathering extensive keyword data for a "Main Keyword." It starts by reading initial parameters from a Google Sheets template, creates a new dedicated Google Sheet
🔥 March Sale – n8n Community Members Get ideoGener8r for Just $27! (Reg. $47) Use Coupon Code: (Valid until 3/31/2025 for n8n community members)
📄 Documentation: Notion Guide