From ff4fb090e63967f46357c31abc77e9e5f4fd3092 Mon Sep 17 00:00:00 2001 From: nusquama Date: Sun, 15 Mar 2026 12:01:41 +0800 Subject: [PATCH] creation --- ...th_scrapercity_and_save_contact_details_to_google_sheets.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 workflows/Skip trace people with ScraperCity and save contact details to Google Sheets-13883/skip_trace_people_with_scrapercity_and_save_contact_details_to_google_sheets.json diff --git a/workflows/Skip trace people with ScraperCity and save contact details to Google Sheets-13883/skip_trace_people_with_scrapercity_and_save_contact_details_to_google_sheets.json b/workflows/Skip trace people with ScraperCity and save contact details to Google Sheets-13883/skip_trace_people_with_scrapercity_and_save_contact_details_to_google_sheets.json new file mode 100644 index 000000000..8ef2315ec --- /dev/null +++ b/workflows/Skip trace people with ScraperCity and save contact details to Google Sheets-13883/skip_trace_people_with_scrapercity_and_save_contact_details_to_google_sheets.json @@ -0,0 +1 @@ +{"meta":{"templateCredsSetupCompleted":false},"nodes":[{"id":"a1000000-0000-0000-0000-000000000001","name":"When clicking 'Execute workflow'","type":"n8n-nodes-base.manualTrigger","position":[-2000,400],"parameters":{},"typeVersion":1},{"id":"a1000000-0000-0000-0000-000000000002","name":"Configure Search Inputs","type":"n8n-nodes-base.set","position":[-1750,400],"parameters":{"options":{},"assignments":{"assignments":[{"id":"b1000001","name":"names","type":"string","value":"John Smith,Jane Doe"},{"id":"b1000002","name":"phones","type":"string","value":""},{"id":"b1000003","name":"emails","type":"string","value":""},{"id":"b1000004","name":"max_results","type":"number","value":1}]}},"typeVersion":3.4},{"id":"a1000000-0000-0000-0000-000000000003","name":"Build Request Body","type":"n8n-nodes-base.code","position":[-1500,400],"parameters":{"jsCode":"// Split comma-separated inputs into arrays, filtering empty strings\nconst toArr = val => val ? val.split(',').map(s => s.trim()).filter(Boolean) : [];\n\nconst cfg = $input.first().json;\n\nreturn [{\n json: {\n name: toArr(cfg.names),\n email: toArr(cfg.emails),\n phone_number: toArr(cfg.phones),\n street_citystatezip: [],\n max_results: cfg.max_results || 1\n }\n}];"},"typeVersion":2},{"id":"a1000000-0000-0000-0000-000000000004","name":"Submit Skip Trace Job","type":"n8n-nodes-base.httpRequest","position":[-1250,400],"parameters":{"url":"https://app.scrapercity.com/api/v1/scrape/people-finder","method":"POST","options":{},"jsonBody":"={{ JSON.stringify($json) }}","sendBody":true,"specifyBody":"json","authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"credential-id","name":"ScraperCity API Key"}},"typeVersion":4.2},{"id":"a1000000-0000-0000-0000-000000000005","name":"Store Run ID","type":"n8n-nodes-base.set","position":[-1000,400],"parameters":{"options":{},"assignments":{"assignments":[{"id":"b2000001","name":"runId","type":"string","value":"={{ $json.runId }}"}]}},"typeVersion":3.4},{"id":"a1000000-0000-0000-0000-000000000006","name":"Polling Loop","type":"n8n-nodes-base.splitInBatches","position":[-750,400],"parameters":{"options":{"reset":false},"batchSize":1},"typeVersion":3,"alwaysOutputData":false},{"id":"a1000000-0000-0000-0000-000000000007","name":"Wait 60 Seconds","type":"n8n-nodes-base.wait","position":[-500,400],"webhookId":"a1000000-wait-0000-0000-000000000007","parameters":{"amount":60},"typeVersion":1.1},{"id":"a1000000-0000-0000-0000-000000000008","name":"Check Scrape Status","type":"n8n-nodes-base.httpRequest","position":[-250,400],"parameters":{"url":"=https://app.scrapercity.com/api/v1/scrape/status/{{ $('Store Run ID').item.json.runId }}","method":"GET","options":{},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"credential-id","name":"ScraperCity API Key"}},"typeVersion":4.2},{"id":"a1000000-0000-0000-0000-000000000009","name":"Is Scrape Complete?","type":"n8n-nodes-base.if","position":[0,400],"parameters":{"options":{},"conditions":{"options":{"version":2,"caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"c1000001","operator":{"type":"string","operation":"equals"},"leftValue":"={{ $json.status }}","rightValue":"SUCCEEDED"}]}},"typeVersion":2.2},{"id":"a1000000-0000-0000-0000-000000000010","name":"Download Results CSV","type":"n8n-nodes-base.httpRequest","position":[250,400],"parameters":{"url":"=https://app.scrapercity.com/api/downloads/{{ $('Store Run ID').item.json.runId }}","method":"GET","options":{"response":{"response":{"responseFormat":"text"}}},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"credential-id","name":"ScraperCity API Key"}},"typeVersion":4.2},{"id":"a1000000-0000-0000-0000-000000000011","name":"Parse and Format CSV Results","type":"n8n-nodes-base.code","position":[500,400],"parameters":{"jsCode":"// Parse CSV text into structured records\nconst csvText = $input.first().json.data || $input.first().json.body || '';\n\nif (!csvText || typeof csvText !== 'string') {\n return [{ json: { error: 'No CSV data returned', runId: $('Store Run ID').item.json.runId } }];\n}\n\nconst lines = csvText.trim().split('\\n');\nif (lines.length < 2) {\n return [{ json: { error: 'Empty CSV', runId: $('Store Run ID').item.json.runId } }];\n}\n\n// Parse header row, handling quoted fields\nconst parseRow = row => {\n const result = [];\n let inQuotes = false;\n let current = '';\n for (let i = 0; i < row.length; i++) {\n const ch = row[i];\n if (ch === '\"') {\n inQuotes = !inQuotes;\n } else if (ch === ',' && !inQuotes) {\n result.push(current.trim());\n current = '';\n } else {\n current += ch;\n }\n }\n result.push(current.trim());\n return result;\n};\n\nconst headers = parseRow(lines[0]);\nconst records = [];\nconst seenKeys = new Set();\n\nfor (let i = 1; i < lines.length; i++) {\n const values = parseRow(lines[i]);\n if (values.length < 2) continue;\n const record = {};\n headers.forEach((h, idx) => {\n record[h] = values[idx] || '';\n });\n // Deduplicate by name + primary_phone combination\n const dedupeKey = (record['name'] || '') + '|' + (record['primary_phone'] || record['phone'] || '');\n if (!seenKeys.has(dedupeKey)) {\n seenKeys.add(dedupeKey);\n records.push({ json: record });\n }\n}\n\nreturn records.length > 0 ? records : [{ json: { error: 'No records parsed', raw: csvText.substring(0, 200) } }];"},"typeVersion":2},{"id":"a1000000-0000-0000-0000-000000000012","name":"Remove Duplicate Contacts","type":"n8n-nodes-base.removeDuplicates","position":[750,400],"parameters":{"compare":"selectedFields","options":{},"fieldsToCompare":{"fields":[{"fieldName":"name"},{"fieldName":"primary_phone"}]}},"typeVersion":2},{"id":"a1000000-0000-0000-0000-000000000013","name":"Write Results to Google Sheets","type":"n8n-nodes-base.googleSheets","position":[1000,400],"parameters":{"columns":{"value":{},"mappingMode":"autoMapInputData"},"options":{},"operation":"appendOrUpdate","sheetName":{"__rl":true,"mode":"id","value":"="},"documentId":{"__rl":true,"mode":"id","value":"="}},"credentials":{"googleSheetsOAuth2Api":{"id":"credential-id","name":"googleSheetsOAuth2Api Credential"}},"typeVersion":4.6},{"id":"a1000000-0000-0000-0000-000000000020","name":"Overview","type":"n8n-nodes-base.stickyNote","position":[-2600,100],"parameters":{"width":450,"height":580,"content":"## How it works\n1. You enter names, phone numbers, or emails in the Configure Search Inputs node.\n2. The workflow submits a skip trace job to the ScraperCity People Finder API.\n3. It polls for completion every 60 seconds (jobs take 10-60 min).\n4. Once done, it downloads the CSV, parses each contact, deduplicates, and writes rows to Google Sheets.\n\n## Setup steps\n1. Create a Header Auth credential named **ScraperCity API Key** -- set header to `Authorization`, value to `Bearer YOUR_KEY`.\n2. Connect a Google Sheets OAuth2 credential.\n3. Edit **Configure Search Inputs** with your lookup targets.\n4. Set your Google Sheet ID in **Write Results to Google Sheets**.\n5. Click Execute workflow."},"typeVersion":1},{"id":"a1000000-0000-0000-0000-000000000021","name":"Section - Configuration","type":"n8n-nodes-base.stickyNote","position":[-2040,-160],"parameters":{"color":7,"width":980,"height":330,"content":"## Configuration\nEnter comma-separated names, phones, or emails in **Configure Search Inputs**. **Build Request Body** converts them into arrays for the API."},"typeVersion":1},{"id":"a1000000-0000-0000-0000-000000000022","name":"Section - Submit Job","type":"n8n-nodes-base.stickyNote","position":[-1040,-160],"parameters":{"color":7,"width":980,"height":330,"content":"## Submit Job\n**Submit Skip Trace Job** POSTs to the ScraperCity People Finder endpoint. **Store Run ID** saves the returned job ID for later polling."},"typeVersion":1},{"id":"a1000000-0000-0000-0000-000000000023","name":"Section - Async Polling Loop","type":"n8n-nodes-base.stickyNote","position":[-40,-160],"parameters":{"color":7,"width":980,"height":330,"content":"## Async Polling Loop\n**Wait 60 Seconds** pauses between checks. **Check Scrape Status** hits the status endpoint. **Is Scrape Complete?** routes to download on success or loops back."},"typeVersion":1},{"id":"a1000000-0000-0000-0000-000000000024","name":"Section - Download and Output","type":"n8n-nodes-base.stickyNote","position":[960,-160],"parameters":{"color":7,"width":300,"height":330,"content":"## Download and Output\n**Download Results CSV** fetches the file. **Parse and Format CSV Results** splits into records. **Remove Duplicate Contacts** dedupes. **Write Results to Google Sheets** appends rows."},"typeVersion":1}],"settings":{"executionOrder":"v1"},"connections":{"Polling Loop":{"main":[[{"node":"Wait 60 Seconds","type":"main","index":0}],[]]},"Store Run ID":{"main":[[{"node":"Polling Loop","type":"main","index":0}]]},"Wait 60 Seconds":{"main":[[{"node":"Check Scrape Status","type":"main","index":0}]]},"Build Request Body":{"main":[[{"node":"Submit Skip Trace Job","type":"main","index":0}]]},"Check Scrape Status":{"main":[[{"node":"Is Scrape Complete?","type":"main","index":0}]]},"Is Scrape Complete?":{"main":[[{"node":"Download Results CSV","type":"main","index":0}],[{"node":"Polling Loop","type":"main","index":0}]]},"Download Results CSV":{"main":[[{"node":"Parse and Format CSV Results","type":"main","index":0}]]},"Submit Skip Trace Job":{"main":[[{"node":"Store Run ID","type":"main","index":0}]]},"Configure Search Inputs":{"main":[[{"node":"Build Request Body","type":"main","index":0}]]},"Remove Duplicate Contacts":{"main":[[{"node":"Write Results to Google Sheets","type":"main","index":0}]]},"Parse and Format CSV Results":{"main":[[{"node":"Remove Duplicate Contacts","type":"main","index":0}]]},"When clicking 'Execute workflow'":{"main":[[{"node":"Configure Search Inputs","type":"main","index":0}]]}}} \ No newline at end of file