{"id":"UsBaGY83vnyZjRoB","meta":{"instanceId":"workflow-d4ec16e1","versionId":"1.0.0","createdAt":"2025-09-29T07:07:59.496285","updatedAt":"2025-09-29T07:07:59.496294","owner":"n8n-user","license":"MIT","category":"automation","status":"active","priority":"high","environment":"production"},"name":"TopSourcer - Finds LinkedIn Profiles using natural language","nodes":[{"id":"trigger-0f3d32a3","name":"Manual Trigger","type":"n8n-nodes-base.manualTrigger","typeVersion":1,"position":[100,100],"parameters":{}},{"id":"16a5f4a2-6e00-40f5-bab7-35526550eacd","name":"Wait","type":"n8n-nodes-base.wait","position":[3240,-280],"webhookId":"88c6a5cc-4b33-438c-ba85-2e075a276a78","parameters":{},"typeVersion":1.1,"notes":"This wait node performs automated tasks as part of the workflow."},{"id":"f9ff2e4f-176b-453d-8743-cab4d9fd408d","name":"When chat message received","type":"n8n-nodes-base.noOp","position":[1040,-180],"webhookId":"475042df-7c36-4658-ab1c-ff55c237621f","parameters":{"options":{}},"typeVersion":1,"notes":"This chatTrigger node performs automated tasks as part of the workflow."},{"id":"b988c049-2400-4a3a-b615-f4048832bd8d","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[980,-340],"parameters":{"content":"Click \"Open Chat\" after activating the workflow.\n\nHere, paste in a job description or describe your ideal candidate."},"typeVersion":1,"notes":"This stickyNote node performs automated tasks as part of the workflow."},{"id":"74cec892-07d6-4e7d-9c6f-becfb51241c8","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[1300,-300],"parameters":{"width":300,"content":"Under \"Credential to connect with\" add your openAI API key. Find at: {{ $env.API_BASE_URL }}\n"},"typeVersion":1,"notes":"This stickyNote node performs automated tasks as part of the workflow."},{"id":"940373af-ca88-44f1-b3c3-fb125ab6daf9","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[2800,-360],"parameters":{"width":300,"content":"For the first condition: {{ $json.start }} is less than 50, so change \"50\" to your desired number of results. \n\nEach loop fetches the next page, returning 10 results per iteration."},"typeVersion":1,"notes":"This stickyNote node performs automated tasks as part of the workflow."},{"id":"c2bc0757-753b-4fee-b42b-65e5a0ff4750","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[3160,-440],"parameters":{"color":5,"width":200,"content":"Waits 5 seconds to avoid rate limiting by Google. While it's unlikely you'll be rate-limited since you're authenticated with your cookie, this is just a precaution."},"typeVersion":1,"notes":"This stickyNote node performs automated tasks as part of the workflow."},{"id":"9007b42b-1a79-4b98-9d75-71894d660c1d","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[3400,-600],"parameters":{"color":4,"width":380,"height":280,"content":"Get this Cookie-Editor. {{ $env.WEBHOOK_URL }}\n\nDo a google search --> click this extension --> Export --> Header string.\n\nThen, open this node --> under Header Auth --> edit --> and under cookie value paste in your header string.  \n\nThis is to perform an authenticated google search.\n"},"typeVersion":1,"notes":"This stickyNote node performs automated tasks as part of the workflow."},{"id":"b1d2f9dd-227d-4372-89f8-e6d54e94f2fc","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[1680,-320],"parameters":{"content":"Connect your google sheets account and create a document."},"typeVersion":1,"notes":"This stickyNote node performs automated tasks as part of the workflow."},{"id":"df0fb397-55d0-41ec-a9df-2c39019ad68e","name":"Create a new sheet","type":"n8n-nodes-base.googleSheets","position":[1740,-180],"parameters":{"title":"={{ $('Generate a Boolean Search String').item.json.choices[0].message.content.sheet_name + ' ' + $now }}\n","options":{},"operation":"create","documentId":{"__rl":true,"mode":"list","value":"1M9UUgw1wPZIBSoPiGTvNIgA19ERgOo5KmD9wx__Y8ZY","cachedResultUrl":"{{ $env.WEBHOOK_URL }}","cachedResultName":"Candidates"}},"credentials":{"googleSheetsOAuth2Api":{"id":"6wBRjmD77d71tAqP","name":"Google Sheets account"}},"typeVersion":4.5,"notes":"This googleSheets node performs automated tasks as part of the workflow."},{"id":"678a0b65-de67-41f0-ada6-23cef1226228","name":"Add columns to new sheet","type":"n8n-nodes-base.googleSheets","position":[2220,-180],"parameters":{"columns":{"value":{},"schema":[{"id":"linkedin_url","type":"string","display":true,"removed":false,"required":false,"displayName":"linkedin_url","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"autoMapInputData","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"append","sheetName":{"__rl":true,"mode":"id","value":"={{ $('Create a new sheet').item.json.sheetId }}"},"documentId":{"__rl":true,"mode":"list","value":"1M9UUgw1wPZIBSoPiGTvNIgA19ERgOo5KmD9wx__Y8ZY","cachedResultUrl":"{{ $env.WEBHOOK_URL }}","cachedResultName":"Candidates"}},"credentials":{"googleSheetsOAuth2Api":{"id":"6wBRjmD77d71tAqP","name":"Google Sheets account"}},"typeVersion":4.5,"notes":"This googleSheets node performs automated tasks as part of the workflow."},{"id":"767491ab-f7dd-4e23-816b-840bc24e5268","name":"set page number for google search","type":"n8n-nodes-base.code","position":[2480,-180],"parameters":{"jsCode":"return [{ json: { start: 0 } }];\n"},"typeVersion":2,"notes":"This code node performs automated tasks as part of the workflow."},{"id":"f76f28a5-8444-4ff9-b62c-0d94a07c6447","name":"Extracts all linkedin urls from the google http response","type":"n8n-nodes-base.code","position":[3740,-280],"parameters":{"jsCode":"// Extract LinkedIn profile URLs from HTML\nfunction extractLinkedInUrls(html) {\n    // First decode any encoded HTML entities\n    html = html.replace(/&amp;/g, '&')\n               .replace(/\\\\u003d/g, '=')\n               .replace(/\\\\x22/g, '\"')\n               .replace(/\\\\x26/g, '&')\n               .replace(/\\\\x3e/g, '>')\n               .replace(/\\\\x3c/g, '<');\n\n    const patterns = [\n        // Standard LinkedIn URLs in href\n        /(?:https?:)?\\/\\/(?:[a-z]{2,}\\.)?linkedin\\.com\\/in\\/[a-zA-Z0-9._-]+(?:\\/[a-z]{2})?/gi,\n        // URLs in encoded strings\n        /(?:\"url\"|url=)(?:[^\"&]*?)(?:https?:)?\\/\\/(?:[a-z]{2,}\\.)?linkedin\\.com\\/in\\/[a-zA-Z0-9._-]+(?:\\/[a-z]{2})?/gi,\n        // URLs in JSON strings\n        /\"(?:https?:)?\\/\\/(?:[a-z]{2,}\\.)?linkedin\\.com\\/in\\/[a-zA-Z0-9._-]+(?:\\/[a-z]{2})?\"/gi\n    ];\n\n    const urls = new Set();\n    \n    patterns.forEach(pattern => {\n        const matches = html.matchAll(pattern);\n        for (const match of matches) {\n            let url = match[0];\n            \n            // Clean up the URL\n            url = url.replace(/^\"url\"|^url=|\"$/g, '') // Remove url= prefix and quotes\n                    .replace(/^[\"']|[\"']$/g, '')      // Remove surrounding quotes\n                    .replace(/\\\\+/g, '')              // Remove backslashes\n                    .trim();\n            \n            // Ensure URL has protocol\n            if (!url.startsWith('http')) {\n                url = 'https://' + url.replace(/^\\/\\//, '');\n            }\n            \n            // Only include if it's a LinkedIn profile URL\n            if (url.includes('linkedin.com/in/')) {\n                // Clean the URL: remove tracking parameters and fragments\n                url = url.split(/[?#&]/)[0];\n                \n                // Remove any trailing slashes\n                url = url.replace(/\\/$/, '');\n                \n                // Add to Set to remove duplicates\n                urls.add(url);\n            }\n        }\n    });\n\n    return Array.from(urls);\n}\n\n// Get the HTML from input\nconst html = $input.first().json.data;\n\n// Extract URLs and create array of objects\nconst linkedInProfiles = extractLinkedInUrls(html)\n    .filter(url => !url.includes('google.com')) // Extra safety check to remove any Google URLs\n    .map(url => ({\n        linkedin_url: url\n    }));\n\n// Return the array of objects directly\nreturn linkedInProfiles;"},"typeVersion":2,"notes":"This code node performs automated tasks as part of the workflow."},{"id":"5a93c8f2-f55b-4d0e-92f8-0d86147f8d13","name":"Google Boolean Search","type":"n8n-nodes-base.httpRequest","position":[3500,-300],"parameters":{"url":"{{ $env.WEBHOOK_URL }}","options":{},"sendQuery":true,"sendHeaders":true,"authentication":"{{ $credentials.genericCredentialType }}","genericAuthType":"httpHeaderAuth","queryParameters":{"parameters":[{"name":"q","value":"={{ $('Generate a Boolean Search String').first().json.choices[0].message.content.search_string }}\n"},{"name":"start","value":"={{ $json.start }}"}]},"headerParameters":{"parameters":[{"name":"User-Agent","value":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36"}]}},"credentials":{"httpHeaderAuth":{"id":"5T6POWjsPfV558Ta","name":"Header Auth account"}},"typeVersion":4.2,"notes":"This httpRequest node performs automated tasks as part of the workflow."},{"id":"37b4f264-34f0-47bb-9b1b-fa53beafb2a9","name":"Generate a Boolean Search String","type":"n8n-nodes-base.noOp","position":[1320,-180],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-4o-mini","cachedResultName":"GPT-4O-MINI"},"options":{},"messages":{"values":[{"role":"system","content":"You are an expert in Boolean search techniques for Google. When the user send a job description, generate a search string specifically for finding LinkedIn profiles. Your response must always follow this exact format:\nsite:linkedin.com/in [Boolean search string]\nCreate the Boolean search string using precise operators (AND, OR, \"\", *, -) to match the job requirements. Focus only on generating the search string - provide no additional commentary or explanations unless specifically requested.\n\nAlso return sheet_name (less than 100 char)"},{"content":"={{ $json.chatInput }}"}]},"simplify":false,"jsonOutput":true},"credentials":{"openAiApi":{"id":"EX7mky4RGLDD6udW","name":"OpenAi account"}},"retryOnFail":false,"typeVersion":1,"notes":"This openAi node performs automated tasks as part of the workflow."},{"id":"99041eff-f094-4c2a-a75a-4b01faf33d1b","name":"If desired results not reached","type":"n8n-nodes-base.if","position":[2920,-200],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"da9f8de0-1e75-4ff3-9f81-8e911251416b","operator":{"type":"number","operation":"lt"},"leftValue":"={{ $json.start }}","rightValue":50},{"id":"a891c085-7f49-4523-8610-40577b3ffd3b","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"","rightValue":""}]}},"typeVersion":2.2,"notes":"This if node performs automated tasks as part of the workflow."},{"id":"d218a1e8-2959-4b7c-a84d-f8e0df82c5e7","name":"Appends the results to the sheet","type":"n8n-nodes-base.googleSheets","position":[4040,-280],"parameters":{"columns":{"value":{"linkedin_url":"{{ $env.BASE_URL }}"},"schema":[{"id":"linkedin_url","type":"string","display":true,"removed":false,"required":false,"displayName":"linkedin_url","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Full Name","type":"string","display":true,"required":false,"displayName":"Full Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"First Name","type":"string","display":true,"required":false,"displayName":"First Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Headline","type":"string","display":true,"required":false,"displayName":"Headline","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Candidate Summary","type":"string","display":true,"required":false,"displayName":"Candidate Summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Experiences Summary","type":"string","display":true,"removed":false,"required":false,"displayName":"Experiences Summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Education Summary","type":"string","display":true,"removed":false,"required":false,"displayName":"Education Summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Skills","type":"string","display":true,"required":false,"displayName":"Skills","defaultMatch":false,"canBeUsedToMatch":true},{"id":"City","type":"string","display":true,"removed":false,"required":false,"displayName":"City","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Country","type":"string","display":true,"removed":false,"required":false,"displayName":"Country","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Criteria_Assessment","type":"string","display":true,"removed":false,"required":false,"displayName":"Criteria_Assessment","defaultMatch":false,"canBeUsedToMatch":true},{"id":"overall_fit_score","type":"string","display":true,"removed":false,"required":false,"displayName":"overall_fit_score","defaultMatch":false,"canBeUsedToMatch":true},{"id":"score_justification","type":"string","display":true,"removed":false,"required":false,"displayName":"score_justification","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company","type":"string","display":true,"required":false,"displayName":"Company","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company Industry","type":"string","display":true,"required":false,"displayName":"Company Industry","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company Size","type":"string","display":true,"required":false,"displayName":"Company Size","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company LinkedIn URL","type":"string","display":true,"required":false,"displayName":"Company LinkedIn URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company Website","type":"string","display":true,"required":false,"displayName":"Company Website","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Current Company Join Date","type":"string","display":true,"required":false,"displayName":"Current Company Join Date","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Certifications","type":"string","display":true,"required":false,"displayName":"Certifications","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Courses Taken","type":"string","display":true,"required":false,"displayName":"Courses Taken","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Email","type":"string","display":true,"required":false,"displayName":"Email","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Phone","type":"string","display":true,"required":false,"displayName":"Phone","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Connections Count","type":"string","display":true,"required":false,"displayName":"Connections Count","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Followers Count","type":"string","display":true,"required":false,"displayName":"Followers Count","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Languages Spoken","type":"string","display":true,"required":false,"displayName":"Languages Spoken","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Projects","type":"string","display":true,"required":false,"displayName":"Projects","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Date Created","type":"string","display":true,"required":false,"displayName":"Date Created","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"append","sheetName":{"__rl":true,"mode":"id","value":"={{ $('Create a new sheet').first().json.sheetId }}"},"documentId":{"__rl":true,"mode":"list","value":"1M9UUgw1wPZIBSoPiGTvNIgA19ERgOo5KmD9wx__Y8ZY","cachedResultUrl":"{{ $env.WEBHOOK_URL }}","cachedResultName":"Candidates"}},"credentials":{"googleSheetsOAuth2Api":{"id":"6wBRjmD77d71tAqP","name":"Google Sheets account"}},"typeVersion":4.5,"notes":"This googleSheets node performs automated tasks as part of the workflow."},{"id":"7a56e7d7-31f8-4115-b993-227bd7221c07","name":"Adds 10 to start - Go to next page","type":"n8n-nodes-base.code","position":[4340,-220],"parameters":{"jsCode":"// Get the start value from 'Edit Fields2' node\nconst startValue =$('If desired results not reached').first().json.start;\n\n// Add 10 to the start value\nconst start = startValue + 10;\n\n// Return the new value\nreturn [{ json: { start } }];\n"},"typeVersion":2,"notes":"This code node performs automated tasks as part of the workflow."},{"id":"afe22fc0-c9c1-4aab-a11d-d91740f812bb","name":"Columns to add","type":"n8n-nodes-base.code","position":[1980,-180],"parameters":{"jsCode":"return [{\n  json: {\n    \"linkedin_url\": \"\"\n  }\n}];\n"},"typeVersion":2,"notes":"This code node performs automated tasks as part of the workflow."}],"active":true,"settings":{"executionOrder":"v1","saveManualExecutions":true,"callerPolicy":"workflowsFromSameOwner","errorWorkflow":null,"timezone":"UTC","executionTimeout":3600,"maxExecutions":1000,"retryOnFail":true,"retryCount":3,"retryDelay":1000},"versionId":"ce389fd9-7697-4e36-8346-6be9414aecf2","connections":{"Google Boolean Search":{"main":[[],[],[],[],[],[],[],[],[]]},"Create a new sheet":{"main":[[]]},"Add columns to new sheet":{"main":[[]]},"Generate a Boolean Search String":{"main":[[]]},"Appends the results to the sheet":{"main":[[]]}},"description":"Automated workflow: TopSourcer - Finds LinkedIn Profiles using natural language. This workflow integrates 9 different services: stickyNote, httpRequest, wait, code, stopAndError. It contains 24 nodes and follows best practices for error handling and security.","notes":"Excellent quality workflow: TopSourcer - Finds LinkedIn Profiles using natural language. This workflow has been optimized for production use with comprehensive error handling, security, and documentation."}