This workflow follows the Agent → 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 →
{
"name": "My workflow",
"nodes": [
{
"parameters": {
"promptType": "define",
"text": "={{ $('Get Data').item.json.prompt }}",
"options": {
"systemMessage": "=CURRENT GOAL: {{ $('Get Data').item.json.prompt }}\n\nYou are Stealth OS, an autonomous AI pilot. Your primary mission is to achieve the goal WITHOUT HALLUCINATING COORDINATES.\n\nSTRICT RULES \u2014 VIOLATION = CRITICAL ERROR:\n- STEP 1: Scan the ENTIRE UI-tree for an exact match to the target (by text, type, or description). If found, use its cx,cy coordinates 1:1 WITHOUT ANY CHANGES.\n- STEP 2: If the element is NOT FOUND after a full scan, check if scrolling is required (if the page/list is scrollable). Only then use \"searching\" status.\n- FORBIDDEN: Do not invent numbers, approximate, calculate offsets, or \"click near the center.\" Copy cx,cy AS IS from the list.\nCLEAN BEFORE TYPE: If an input field (i, ta) has a non-empty value, you MUST use {\"action\": \"clear\", \"x\": ..., \"y\": ..., \"reason\": \"...\"} before using type.\n- SAFETY: If the target is missing, use ONLY \"scroll\", \"key\", \"search-url\", or \"searching\". NEVER CLICK INTO EMPTY SPACE.\n- NAVIGATION: Always prefer {\"action\": \"search-url\"} for navigating to websites or performing searches.\n-SAFETY: Never click into empty space. If lost, use error.\n- OUTPUT: Respond ONLY with one valid JSON object. No text before or after the JSON.\n- VISIBILITY LOGIC: \n 1. If element has \"v:1\": It is visible. Proceed with action (click, type, etc.) using its exact cx,cy.\n 2. If element has \"v:0\": It is out of viewport. DO NOT click. You MUST use {\"action\": \"scroll\", \"amount\": -1000, \"reason\": \"Target found with v:0, scrolling to bring into view\"} first.\n 3. If element is NOT in the UI-tree: Use \"scroll\" or \"searching\" status to find it.\n\nAVAILABLE ACTIONS (Only one JSON per response):\n{\"action\": \"clear\", \"x\": NUMBER, \"y\": NUMBER, \"reason\": \"...\"}\n{\"action\": \"click\", \"x\": NUMBER_FROM_LIST, \"y\": NUMBER_FROM_LIST, \"reason\": \"...\"}\n{\"action\": \"type\", \"text\": \"text_to_type\", \"x\": NUMBER_FROM_LIST, \"y\": NUMBER_FROM_LIST, \"reason\": \"...\"} (x,y only if field focus is needed)\n{\"action\": \"key\", \"text\": \"ENTER\", \"reason\": \"...\"}\n{\"action\": \"scroll\", \"amount\": -1000, \"x\": NUMBER, \"y\": NUMBER, \"reason\": \"...\"} (use -1000 to scroll DOWN to the bottom, +1000 to scroll UP to the top)\n{\"action\": \"search-url\", \"url\": \"https://...\", \"reason\": \"...\"} OR {\"action\": \"search-url\", \"q\": \"search query\", \"reason\": \"...\"}\n{\"status\": \"searching\", \"target\": \"element name\", \"reason\": \"...\"}\n{\"status\": \"success\", \"message\": \"briefly describe what was done or provide requested info\"}\n{\"status\": \"error\", \"message\": \"detailed reason why the goal cannot be achieved\"}\n\nCURRENT SCREEN STRUCTURE (Includes CURRENT_URL and SCREEN_SIZE):\n{{ $('Get UI Tree').item.json.data }}"
}
},
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 3.1,
"position": [
160,
256
],
"id": "c4ba099d-ed95-4672-af53-f6a78b50fdf3",
"name": "AI Agent"
},
{
"parameters": {
"url": "={{ $('GLOBAL_CONFIG').item.json.url }}/list",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-Stealth-Token",
"value": "={{ $('GLOBAL_CONFIG').item.json.authToken }}"
}
]
},
"options": {}
},
"id": "fb6923f5-07b4-44ed-88ef-0db8443061ff",
"name": "Get UI Tree",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
-288,
288
]
},
{
"parameters": {
"url": "={{ $('GLOBAL_CONFIG').item.json.url }}",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "action",
"value": "={{ $('Code in JavaScript').item.json.action }}"
},
{
"name": "x",
"value": "={{ $('Code in JavaScript').item.json.x }}"
},
{
"name": "y",
"value": "={{ $('Code in JavaScript').item.json.y }}"
},
{
"name": "isNormalized",
"value": "={{ $json.isNormalized }}"
},
{
"name": "text",
"value": "={{ $json.text }}"
},
{
"name": "amount",
"value": "={{ $json.amount }}"
}
]
},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-Stealth-Token",
"value": "={{ $('GLOBAL_CONFIG').item.json.authToken }}"
}
]
},
"options": {}
},
"id": "46314402-860b-4afa-b6bc-74a032a4d503",
"name": "Send Command to Launcher",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
960,
208
]
},
{
"parameters": {
"jsCode": "let rawContent = $input.first().json.output;\n\ntry {\n let cleaned = rawContent\n .replace(/```json\\s*/gi, '')\n .replace(/```\\s*$/gm, '')\n .replace(/^`{3}[\\s\\S]*?`{3}$/s, '$1')\n .trim();\n\n const jsonRegex = /\\{[\\s\\S]*?\\}(?![^{]*\\})/;\n const match = cleaned.match(jsonRegex);\n if (!match || !match[0]) {\n throw new Error(\"\u0412 \u043e\u0442\u0432\u0435\u0442\u0435 \u0418\u0418 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d \u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439 JSON\");\n }\n\n const cleanJson = JSON.parse(match[0]);\n if (typeof cleanJson !== 'object' || cleanJson === null) {\n throw new Error(\"\u0421\u043f\u0430\u0440\u0441\u0435\u043d\u043d\u044b\u0439 JSON \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c\");\n }\n\n\n if (cleanJson.status === \"success\") {\n return [{\n json: {\n action: \"success\",\n message: cleanJson.message || \"\u0417\u0430\u0434\u0430\u0447\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430\",\n reason: cleanJson.reason || \"\u0410\u0433\u0435\u043d\u0442 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u043b \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\",\n is_searching: false\n }\n }];\n }\n\n if (cleanJson.status === \"error\") {\n return [{\n json: {\n action: \"error\",\n message: cleanJson.message || \"\u0417\u0430\u0434\u0430\u0447\u0430 \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430\",\n reason: cleanJson.reason || \"\u0410\u0433\u0435\u043d\u0442 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u043b \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\",\n is_searching: false\n }\n }];\n }\n\n\n if (cleanJson.status === \"searching\") {\n return [{\n json: {\n action: \"vision_needed\",\n target: cleanJson.target || \"\u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\",\n reason: cleanJson.reason || \"\u042d\u043b\u0435\u043c\u0435\u043d\u0442 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d \u0432 UI-\u0434\u0435\u0440\u0435\u0432\u0435, \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0432\u0438\u0437\u0443\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u043e\u0438\u0441\u043a\",\n is_searching: true\n }\n }];\n }\n\n\n if (!cleanJson.action) {\n throw new Error(\"\u0412 JSON \u043d\u0435\u0442 \u043d\u0438 'status', \u043d\u0438 'action'\");\n }\n\n\n let result = {\n action: cleanJson.action,\n reason: cleanJson.reason || \"\u0412\u044b\u043f\u043e\u043b\u043d\u044f\u044e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435\",\n is_searching: false\n };\n\n\n if (cleanJson.x !== undefined) result.x = parseFloat(cleanJson.x);\n if (cleanJson.y !== undefined) result.y = parseFloat(cleanJson.y);\n if (cleanJson.text !== undefined) result.text = cleanJson.text;\n if (cleanJson.amount !== undefined) result.amount = parseInt(cleanJson.amount, 10);\n\n if (cleanJson.action === \"search-url\") {\n if (cleanJson.url) {\n result.queryText = cleanJson.url;\n result.queryType = \"url\"; \n } else if (cleanJson.q) {\n result.queryText = cleanJson.q;\n result.queryType = \"q\";\n } else {\n throw new Error(\"\u0414\u043b\u044f search-url \u043d\u0443\u0436\u0435\u043d \u043b\u0438\u0431\u043e 'url', \u043b\u0438\u0431\u043e 'q'\");\n }\n }\n\n\n if (cleanJson.isNormalized === true || cleanJson.normalized === true) {\n result.isNormalized = true;\n }\n\n return [{\n json: result\n }];\n\n} catch (e) {\n throw new Error(\n \"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 \u043e\u0442\u0432\u0435\u0442\u0430 \u0418\u0418:\\n\" +\n \"\u0421\u044b\u0440\u043e\u0439 \u043e\u0442\u0432\u0435\u0442: \" + rawContent.substring(0, 300) + \"...\\n\" +\n \"\u0414\u0435\u0442\u0430\u043b\u0438: \" + e\n );\n}"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
512,
288
],
"id": "5651873b-0867-42c1-98bd-785f6cc37445",
"name": "Code in JavaScript"
},
{
"parameters": {},
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
-2240,
1312
],
"id": "f750b951-2f3c-41e6-b369-b918569445f1",
"name": "When clicking \u2018Execute workflow\u2019"
},
{
"parameters": {
"mode": "raw",
"jsonOutput": "{\n \"url\": \"http://host.docker.internal:5050\",\n \"authToken\": \"\"\n}\n",
"options": {}
},
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
-2032,
960
],
"id": "9708dce1-116c-4bf6-9e6c-3d9213a35f81",
"name": "GLOBAL_CONFIG"
},
{
"parameters": {
"sessionIdType": "customKey",
"sessionKey": "={{ $execution.id }}",
"contextWindowLength": 10
},
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"typeVersion": 1.3,
"position": [
656,
512
],
"id": "e85ae3af-b5ee-4d10-9b53-7319b005d568",
"name": "Simple Memory"
},
{
"parameters": {
"promptType": "define",
"text": "=Goal: [{{ $json.target }}]",
"options": {
"systemMessage": "=GOAL: [{{ $json.target }}]\n\nYou are a Visual Screen Analyzer for mobile/web interfaces. You are provided with a screenshot and a target goal. Your task is to return exactly ONE JSON action that brings you closer to that goal.\n\nCOORDINATE SYSTEM: Normalized (0.000 to 1.000), always use three decimal places.\n\nSTRICT RULES (VIOLATION = CRITICAL ERROR):\n1. STEP 1: If the target is VISIBLE on the screenshot, click EXACTLY in the center of its bounding box.\n2. STEP 2: If the target is NOT VISIBLE, perform ONE intermediate action: scroll, or click a \"More/Menu\" button. Do not hallucinate coordinates.\n3. LOGIC: Every action must have a clear \"Reason\" stating: What is visible, why this action was chosen, and what the expected next step is.\n4. FORMAT: Return ONLY a valid JSON object. No markdown blocks, no conversational text, no explanations outside the JSON.\n5. SUCCESS: Use {\"status\": \"success\"} only if the goal is fully completed and no further interaction is required.\n\nAVAILABLE ACTIONS (JSON ONLY):\n\n- CLICK:\n {\"action\": \"click\", \"x\": 0.521, \"y\": 0.342, \"normalized\": true, \"reason\": \"The 'Submit' button is visible at these coordinates. Goal is to send the form. Action: click center of button. Expecting a confirmation screen next.\"}\n\n- TYPE TEXT:\n {\"action\": \"type\", \"text\": \"example_text\", \"x\": 0.180, \"y\": 0.450, \"normalized\": true, \"reason\": \"The email input field is visible. Goal is to enter the recipient address. Action: click and type into the field. Expecting the field to populate and the 'Next' button to become active.\"}\n\n- SCROLL:\n {\"action\": \"scroll\", \"amount\": -400, \"reason\": \"The 'Payoneer' option is not visible in the current list. Goal is below the fold. Action: scroll down. Expecting the 'Payoneer' button to appear in the next screenshot.\"}\n\n- SUCCESS:\n {\"status\": \"success\", \"message\": \"The 'Send' button was pressed and the transfer has been successfully initiated.\"}\n\nReturn ONLY the JSON object."
}
},
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 3.1,
"position": [
1200,
192
],
"id": "a618adaf-128a-48a3-9619-accb51033a36",
"name": "AI Agent1"
},
{
"parameters": {
"url": "={{ $('GLOBAL_CONFIG').item.json.url }}/wait-for-load",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-Stealth-Token",
"value": "={{ $('GLOBAL_CONFIG').item.json.authToken }}"
}
]
},
"options": {}
},
"id": "29e11d80-40eb-46ce-a6fa-ffc0cb623069",
"name": "Wait For Load",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
-64,
288
]
},
{
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "1eb318dc-a87a-4ca1-8626-a3abbfebe9cb",
"leftValue": "={{ $json.action }}",
"rightValue": "vision_needed",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "Vision"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"leftValue": "={{ $json.action }}",
"rightValue": "search-url",
"operator": {
"type": "string",
"operation": "equals"
},
"id": "685cc087-2e0f-440c-9549-1d2a1f05e851"
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "SearchUrl"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "b2a49429-809f-49fd-aadc-64f2c1f738b4",
"leftValue": "={{ $json.action }}",
"rightValue": "success",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "Success"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "6f1f87b8-993a-47a8-9bf5-c0cd16927ca5",
"leftValue": "={{ $json.action }}",
"rightValue": "error",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "Error"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "0db89682-2508-444f-b997-070eddc5ac3f",
"leftValue": "={{ $json.action }}",
"rightValue": "success",
"operator": {
"type": "string",
"operation": "notEquals"
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "Action"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.switch",
"typeVersion": 3.4,
"position": [
672,
-208
],
"id": "a88c10dd-c47e-4949-95f5-78c423102385",
"name": "Switch"
},
{
"parameters": {
"url": "={{ $('GLOBAL_CONFIG').item.json.url }}/screenshot",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-Stealth-Token",
"value": "={{ $('GLOBAL_CONFIG').item.json.authToken }}"
}
]
},
"options": {}
},
"id": "6f1164f7-9581-4bec-adda-7cb243aad674",
"name": "Get ScreenShot",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
960,
-176
]
},
{
"parameters": {
"url": "={{ $('GLOBAL_CONFIG').item.json.url }}/search-url",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "={{ $('Code in JavaScript').item.json.queryType }}",
"value": "={{ $json.queryText }}"
}
]
},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-Stealth-Token",
"value": "={{ $('GLOBAL_CONFIG').item.json.authToken }}"
}
]
},
"options": {}
},
"id": "5e798bc4-99fd-4569-b7d0-866a58cf1b0c",
"name": "Search in Edge",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
960,
16
]
},
{
"parameters": {
"amount": 2
},
"id": "db7732bb-33fb-4a4c-ad03-fb3e825807e1",
"name": "Wait1",
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
-528,
288
]
},
{
"parameters": {
"chatId": "={{ $('Get Data').item.json.tgchatid }}",
"text": "=SUCCESS\n{{ $('Code in JavaScript').item.json.message }}",
"additionalFields": {}
},
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
416,
-192
],
"id": "0b38dadf-62af-458e-b8ba-05bca0c4909c",
"name": "Send a text message",
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"typeVersion": 1,
"position": [
880,
480
],
"id": "8659a38f-8819-4149-9b91-311dd321236d",
"name": "Google Gemini Chat Model",
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "8b84aa68-4d16-4a7c-a5ea-1f52fa5a3527",
"leftValue": "={{ $json.running }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
},
{
"id": "274cd337-32ce-4369-ac77-a09e8b02f8e8",
"leftValue": "={{ $json.msedge_running }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
},
{
"id": "094a5abb-12d9-448a-8c1b-c25ef6dcdd9f",
"leftValue": "={{ $json.cdp_working }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
-1696,
1312
],
"id": "e1bf31f7-9114-46ee-9ec9-9c28a5ff65e6",
"name": "If1"
},
{
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "claude-sonnet-4-5-20250929",
"cachedResultName": "Claude Sonnet 4.5"
},
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"typeVersion": 1.3,
"position": [
464,
512
],
"id": "f8b656b8-d8f7-473c-8abd-d18c44af6fcf",
"name": "Anthropic Chat Model",
"credentials": {
"anthropicApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"chatId": "={{ $('Get Data').item.json.tgchatid }}",
"text": "=ERROR\n{{ $('Code in JavaScript').item.json.message }}",
"additionalFields": {}
},
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
208,
-192
],
"id": "a705f486-40e1-47fd-a0a5-368e88ccac10",
"name": "Send a text message1",
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"url": "={{ $json.url }}/status",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
-1840,
1312
],
"id": "03de15ee-4b01-44ba-a3b2-604753d66ac2",
"name": "Check Health"
},
{
"parameters": {
"url": "={{ $('GLOBAL_CONFIG').item.json.url }}/mydata",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
-1488,
1312
],
"id": "a52344e9-a1ac-4ab5-9036-623b416564c4",
"name": "Get Data"
},
{
"parameters": {
"jsCode": "const profiles = $input.first().json.profiles || [];\n\n// 1. Format text\nlet content = `Profiles found: ${profiles.length}\\n`;\ncontent += `Date: ${new Date().toLocaleString('en-US')}\\n`;\ncontent += `${'='.repeat(40)}\\n\\n`;\n\nprofiles.forEach((p, i) => {\n content += `${i + 1}. ${p.name || 'No Name'}\\n`;\n content += ` Title: ${p.title || '\u2014'}\\n`;\n content += ` Location: ${p.location || '\u2014'}\\n`;\n content += ` Link: ${p.url || '\u2014'}\\n\\n`;\n});\n\n// 2. Encoding (passed as is to match your original logic)\nconst encoded = content;\n\n// 3. Return result\nreturn [{\n json: {\n fileName: `linkedin_${Date.now()}.txt`,\n data: encoded\n }\n}];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
448,
1616
],
"id": "ed14c021-c4f6-4a97-8ef6-8669fc5a4674",
"name": "Code in JavaScript1"
},
{
"parameters": {
"operation": "toText",
"sourceProperty": "=data",
"options": {
"fileName": "={{ $json.fileName }}"
}
},
"type": "n8n-nodes-base.convertToFile",
"typeVersion": 1.1,
"position": [
64,
1872
],
"id": "7c0d2c88-a922-4f33-9109-12a7a87bb2aa",
"name": "Convert to File"
},
{
"parameters": {
"operation": "sendDocument",
"chatId": "={{ $('Get Data').item.json.tgchatid }}",
"binaryData": true,
"additionalFields": {}
},
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
208,
1872
],
"id": "b4f19aef-72dc-4111-b4b0-82f2a1ce3507",
"name": "Send a document",
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"promptType": "define",
"text": "={{ $('Get Data').item.json.prompt }}",
"options": {
"systemMessage": "=goal {{ $('Get Data').item.json.prompt }}\n\nSCRAPING MODE:\n\nLINKEDIN SCRAPING MODE:\n1. MANDATORY LINKEDIN FOCUS: Treat EVERY goal (e.g., \"Google Earth\", \"Apple\", \"John Doe\") EXCLUSIVELY as a request to find LinkedIn profiles. You are FORBIDDEN from navigating to official websites (.com, .org, etc.) or summarizing company info.\n2. INITIAL SEARCH FORCING: If you are not on LinkedIn, you MUST search for the company's LinkedIn page. Never navigate to the goal's direct URL.\n3. NAVIGATION: If CURRENT_URL is a Google search, IGNORE all non-LinkedIn results. You MUST find a LinkedIn link (profile or company) and use {\"action\": \"search-url\", \"url\": \"...\"} to go there.\n4. COMPANY PAGE LOGIC: If you land on a LinkedIn Company page, your ONLY next move is to find and CLICK \"People\" or \"See all employees\".\n\nScan UI-tree for all profile cards (v:1).\n\nEXTRACT each profile strictly into: {\"name\": \"...\", \"title\": \"...\", \"location\": \"...\", \"url\": \"...\"}\n\nSCROLL & COLLECT LOOP:\n1. Scan UI-tree for all profile cards (v:1).\n2. EXTRACT profiles into: {\"name\": \"...\", \"title\": \"...\", \"location\": \"...\", \"url\": \"...\"}\n3. LIMIT: Perform MAX 3 scrolls total. If reached, STOP and return profiles.\n4. ACTION: If under limit, use {\"action\": \"scroll\", \"amount\": -1000, \"reason\": \"Step N of 3\"}.\n\n5. MANDATORY OUTPUT: You MUST return a JSON with a \"profiles\" array. A \"success\" status without a \"profiles\" array is considered a FAILURE if profiles are visible on screen or reachable.\n\nSTRICT RULES \u2014 STEALTH OS PROTOCOL:\n- NO CLICKING: Do not enter individual profiles. Collect only data visible on the search results page.\n- DEDUPLICATION: Maintain a unique list of profiles by their URL.\n- NO HALLUCINATIONS: Use coordinates and text strictly from the UI-tree.\n- OUTPUT: Respond ONLY with one valid JSON object. No prose.\nSTRICT RULES \u2014 VIOLATION = CRITICAL ERROR:\n- STEP 1: Scan the ENTIRE UI-tree for an exact match to the target (by text, type, or description). If found, use its cx,cy coordinates 1:1 WITHOUT ANY CHANGES.\n- STEP 2: If the element is NOT FOUND after a full scan, check if scrolling is required (if the page/list is scrollable).\n- FORBIDDEN: Do not invent numbers, approximate, calculate offsets, or \"click near the center.\" Copy cx,cy AS IS from the list.\nCLEAN BEFORE TYPE: If an input field (i, ta) has a non-empty value, you MUST use {\"action\": \"clear\", \"x\": ..., \"y\": ..., \"reason\": \"...\"} before using type.\n- SAFETY: If the target is missing, use ONLY \"scroll\", \"key\", \"search-url\", or \"searching\". NEVER CLICK INTO EMPTY SPACE.\n- NAVIGATION: Always prefer {\"action\": \"search-url\"} for navigating to websites or performing searches.\n-SAFETY: Never click into empty space. If lost, use error.\n- OUTPUT: Respond ONLY with one valid JSON object. No text before or after the JSON.\n- VISIBILITY LOGIC: \n 1. If element has \"v:1\": It is visible. Proceed with action (click, type, etc.) using its exact cx,cy.\n 2. If element has \"v:0\": It is out of viewport. DO NOT click. You MUST use {\"action\": \"scroll\", \"amount\": 400, \"reason\": \"Target found with v:0, scrolling to bring into view\"} first.\n\n\nAVAILABLE ACTIONS (Only one JSON per response):\n{\"action\": \"clear\", \"x\": NUMBER, \"y\": NUMBER, \"reason\": \"...\"}\n{\"action\": \"click\", \"x\": NUMBER_FROM_LIST, \"y\": NUMBER_FROM_LIST, \"reason\": \"...\"}\n{\"action\": \"type\", \"text\": \"text_to_type\", \"x\": NUMBER_FROM_LIST, \"y\": NUMBER_FROM_LIST, \"reason\": \"...\"} (x,y only if field focus is needed)\n{\"action\": \"key\", \"text\": \"ENTER\", \"reason\": \"...\"}\n{\"action\": \"scroll\", \"amount\": -1000, \"x\": 500, \"y\": 500, \"reason\": \"Scrolling DOWN to load more content\"} (CRITICAL: Use NEGATIVE values like -1000 to scroll DOWN to the bottom. Use POSITIVE values like +1000 to scroll UP to the top)\n{\"action\": \"search-url\", \"url\": \"https://...\", \"reason\": \"...\"} OR {\"action\": \"search-url\", \"q\": \"search query\", \"reason\": \"...\"}\n\n{\"status\": \"success\", \"message\": \"briefly describe what was done or provide requested info\"}\n{\"status\": \"error\", \"message\": \"detailed reason why the goal cannot be achieved\"}\n\nCURRENT SCREEN STRUCTURE (Includes CURRENT_URL and SCREEN_SIZE):\n{{ $('Get UI Tree1').item.json.data }}"
}
},
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 3.1,
"position": [
-208,
2288
],
"id": "b17fd8b7-4c31-4a7d-a15a-1da9b82423fa",
"name": "AI Agent2"
},
{
"parameters": {
"url": "={{ $('GLOBAL_CONFIG').item.json.url }}/list",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-Stealth-Token",
"value": "={{ $('GLOBAL_CONFIG').item.json.authToken }}"
}
]
},
"options": {}
},
"id": "41e7f92c-8371-412d-a91d-0298086c3e1e",
"name": "Get UI Tree1",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
-656,
2320
]
},
{
"parameters": {
"url": "={{ $('GLOBAL_CONFIG').item.json.url }}",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "action",
"value": "={{ $('Code in JavaScript2').item.json.action }}"
},
{
"name": "x",
"value": "={{ $('Code in JavaScript2').item.json.x }}"
},
{
"name": "y",
"value": "={{ $('Code in JavaScript2').item.json.y }}"
},
{
"name": "isNormalized",
"value": "={{ $json.isNormalized }}"
},
{
"name": "text",
"value": "={{ $json.text }}"
},
{
"name": "amount",
"value": "={{ $json.amount }}"
}
]
},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-Stealth-Token",
"value": "={{ $('GLOBAL_CONFIG').item.json.authToken }}"
}
]
},
"options": {}
},
"id": "dcee8bb9-8f02-46ba-a56c-caeb0685c0ac",
"name": "Send Command to Launcher1",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
800,
2240
]
},
{
"parameters": {
"jsCode": "// \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432\u0445\u043e\u0434\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435\nlet rawContent = $input.first().json.output;\n\ntry {\n // 1. \u041e\u0447\u0438\u0441\u0442\u043a\u0430 \u043e\u0442 markdown-\u043e\u0431\u0435\u0440\u0442\u043e\u043a \u0438 \u043b\u0438\u0448\u043d\u0438\u0445 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432\n let cleaned = rawContent\n .replace(/```json\\s*/gi, '')\n .replace(/```\\s*$/gm, '')\n .trim();\n\n // 2. \u0418\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u043b\u0430 JSON\n const jsonRegex = /\\{[\\s\\S]*\\}/;\n const match = cleaned.match(jsonRegex);\n if (!match) {\n throw new Error(\"JSON \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d \u0432 \u043e\u0442\u0432\u0435\u0442\u0435\");\n }\n\n const cleanJson = JSON.parse(match[0]);\n\n // 3. \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u0442\u0430\u0442\u0443\u0441\u043e\u0432 (Success / Error / Searching)\n if (cleanJson.status === \"success\") {\n return [{\n json: {\n action: \"success\",\n message: cleanJson.message || \"Done\",\n profiles: cleanJson.profiles || [],\n is_searching: false\n }\n }];\n }\n\n if (cleanJson.status === \"error\") {\n return [{\n json: {\n action: \"error\",\n message: cleanJson.message || \"\u041e\u0448\u0438\u0431\u043a\u0430\",\n reason: cleanJson.reason || \"\u0410\u0433\u0435\u043d\u0442 \u0441\u043e\u043e\u0431\u0449\u0438\u043b \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435\",\n is_searching: false\n }\n }];\n }\n\n if (cleanJson.status === \"searching\") {\n return [{\n json: {\n action: \"vision_needed\",\n target: cleanJson.target || \"element\",\n reason: cleanJson.reason || \"\u041f\u043e\u0438\u0441\u043a \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430...\",\n is_searching: true\n }\n }];\n }\n\n // 4. \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 (Click, Type, Search-URL \u0438 \u0442.\u0434.)\n if (!cleanJson.action) {\n throw new Error(\"\u0412 \u043e\u0442\u0432\u0435\u0442\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 action \u0438\u043b\u0438 status\");\n }\n\n let result = {\n action: cleanJson.action,\n reason: cleanJson.reason || \"\u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\",\n is_searching: false\n };\n\n // \u041d\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438\n if (cleanJson.x !== undefined) result.x = parseFloat(cleanJson.x);\n if (cleanJson.y !== undefined) result.y = parseFloat(cleanJson.y);\n if (cleanJson.text !== undefined) result.text = cleanJson.text;\n if (cleanJson.amount !== undefined) result.amount = parseInt(cleanJson.amount, 10);\n\n if (cleanJson.action === \"search-url\") {\n if (cleanJson.url) {\n result.queryText = cleanJson.url;\n result.queryType = \"url\";\n } else if (cleanJson.q) {\n result.queryText = cleanJson.q;\n result.queryType = \"q\";\n }\n }\n\n return [{ json: result }];\n\n} catch (e) {\n throw new Error(\"\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430: \" + e.message);\n}"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
144,
2320
],
"id": "f5d28156-d22a-421c-9908-eb7ac2635e1f",
"name": "Code in JavaScript2"
},
{
"parameters": {
"sessionIdType": "customKey",
"sessionKey": "={{ $execution.id }}",
"contextWindowLength": 10
},
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"typeVersion": 1.3,
"position": [
336,
2592
],
"id": "7b12bdf5-3069-40b2-876a-1ad3678afc98",
"name": "Simple Memory1"
},
{
"parameters": {
"promptType": "define",
"text": "=Goal: [{{ $json.target }}]",
"options": {
"systemMessage": "=GOAL: [{{ $json.target }}]\n\nYou are a Visual Screen Analyzer for mobile/web interfaces. You are provided with a screenshot and a target goal. Your task is to return exactly ONE JSON action that brings you closer to that goal.\n\nCOORDINATE SYSTEM: Normalized (0.000 to 1.000), always use three decimal places.\n\nSTRICT RULES (VIOLATION = CRITICAL ERROR):\n1. STEP 1: If the target is VISIBLE on the screenshot, click EXACTLY in the center of its bounding box.\n2. STEP 2: If the target is NOT VISIBLE, perform ONE intermediate action: scroll, or click a \"More/Menu\" button. Do not hallucinate coordinates.\n3. LOGIC: Every action must have a clear \"Reason\" stating: What is visible, why this action was chosen, and what the expected next step is.\n4. FORMAT: Return ONLY a valid JSON object. No markdown blocks, no conversational text, no explanations outside the JSON.\n5. SUCCESS: Use {\"status\": \"success\"} only if the goal is fully completed and no further interaction is required.\n\nAVAILABLE ACTIONS (JSON ONLY):\n\n- CLICK:\n {\"action\": \"click\", \"x\": 0.521, \"y\": 0.342, \"normalized\": true, \"reason\": \"The 'Submit' button is visible at these coordinates. Goal is to send the form. Action: click center of button. Expecting a confirmation screen next.\"}\n\n- TYPE TEXT:\n {\"action\": \"type\", \"text\": \"example_text\", \"x\": 0.180, \"y\": 0.450, \"normalized\": true, \"reason\": \"The email input field is visible. Goal is to enter the recipient address. Action: click and type into the field. Expecting the field to populate and the 'Next' button to become active.\"}\n\n- SCROLL:\n {\"action\": \"scroll\", \"amount\": -400, \"reason\": \"The 'Payoneer' option is not visible in the current list. Goal is below the fold. Action: scroll down. Expecting the 'Payoneer' button to appear in the next screenshot.\"}\n\n- SUCCESS:\n {\"status\": \"success\", \"message\": \"The 'Send' button was pressed and the transfer has been successfully initiated.\"}\n\nReturn ONLY the JSON object."
}
},
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 3.1,
"position": [
1040,
2224
],
"id": "1a63f651-8c87-48f8-8a20-44c614da8e3a",
"name": "AI Agent3"
},
{
"parameters": {
"url": "={{ $('GLOBAL_CONFIG').item.json.url }}/wait-for-load",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-Stealth-Token",
"value": "={{ $('GLOBAL_CONFIG').item.json.authToken }}"
}
]
},
"options": {}
},
"id": "ef13069c-95d1-4aa0-bfc7-f146c0b8ec51",
"name": "Wait For Load1",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
-432,
2320
]
},
{
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "1eb318dc-a87a-4ca1-8626-a3abbfebe9cb",
"leftValue": "={{ $json.action }}",
"rightValue": "vision_needed",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "Vision"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"leftValue": "={{ $json.action }}",
"rightValue": "search-url",
"operator": {
"type": "string",
"operation": "equals"
},
"id": "685cc087-2e0f-440c-9549-1d2a1f05e851"
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "SearchUrl"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "b2a49429-809f-49fd-aadc-64f2c1f738b4",
"leftValue": "={{ $json.action }}",
"rightValue": "success",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "Success"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "6f1f87b8-993a-47a8-9bf5-c0cd16927ca5",
"leftValue": "={{ $json.action }}",
"rightValue": "error",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "Error"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "0db89682-2508-444f-b997-070eddc5ac3f",
"leftValue": "={{ $json.action }}",
"rightValue": "success",
"operator": {
"type": "string",
"operation": "notEquals"
}
}
],
"combinator": "and"
},
"renameOutput": true,
"outputKey": "Action"
}
]
},
"options": {}
},
"type": "n8n-nodes-base.switch",
"typeVersion": 3.4,
"position": [
448,
1904
],
"id": "5824f35b-4383-4493-bf1e-7d873ccf2e2f",
"name": "Switch1"
},
{
"parameters": {
"url": "={{ $('GLOBAL_CONFIG').item.json.url }}/screenshot",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-Stealth-Token",
"value": "={{ $('GLOBAL_CONFIG').item.json.authToken }}"
}
]
},
"options": {}
},
"id": "90c3393e-1ea4-443b-b031-0bfe99d5f341",
"name": "Get ScreenShot1",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
800,
1856
]
},
{
"parameters": {
"url": "={{ $('GLOBAL_CONFIG').item.json.url }}/search-url",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "={{ $('Code in JavaScript2').item.json.queryType }}",
"value": "={{ $json.queryText }}"
}
]
},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-Stealth-Token",
"value": "={{ $('GLOBAL_CONFIG').item.json.authToken }}"
}
]
},
"options": {}
},
"id": "1508216a-4599-4fb3-a4d1-931da95a0d0a",
"name": "Search in Edge1",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
800,
2048
]
},
{
"parameters": {
"amount": 2
},
"id": "63e963c2-dddc-4a8a-828e-dd5306936e32",
"name": "Wait",
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
-896,
2320
]
},
{
"parameters": {
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"typeVersion": 1,
"position": [
768,
2560
],
"id": "e228b502-01f2-4f18-b873-49cc2ebadf98",
"name": "Google Gemini Chat Model1",
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "claude-sonnet-4-5-20250929",
"cachedResultName": "Claude Sonnet 4.5"
},
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"typeVersion": 1.3,
"position": [
144,
2592
],
"id": "fceb9951-9089-4dc1-8765-15b6820f4041",
"name": "Anthropic Chat Model1",
"credentials": {
"anthropicApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"chatId": "={{ $('Get Data').item.json.tgchatid }}",
"text": "=ERROR\n{{ $('Code in JavaScript2').item.json.message }}",
"additionalFields": {}
},
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
-48,
1616
],
"id": "70b920b1-6cfc-49bd-8ca9-afc3266e6d0c",
"name": "Send a text message2",
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"content": "# Enter your URL here",
"height": 288,
"width": 368,
"color": "#CE0909"
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-2176,
848
],
"id": "2eecd719-a69a-4a02-b9a8-b59aa5d2df70",
"name": "Sticky Note"
},
{
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"leftValue": "={{ $json.tab }}",
"rightValue": "browser",
"operator": {
"type": "string",
"operation": "equals"
},
"id": "8aba0f91-0d7a-47f6-90f4-80f3a5808226"
}
],
"combinator": "and"
}
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "70f0f371-4018-4fcf-9d53-84550d311d20",
"leftValue": "={{ $json.tab }}",
"rightValue": "indeed",
"operator": {
"type": "string",
"operation": "equals",
"name": "filter.operator.equals"
}
}
],
"combinator": "and"
}
},
{
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "2987331b-279d-47a3-90ab-53f87c3cfba1",
"leftValue": "={{ $json.tab }}",
"rightValue": "linkedin",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
}
}
]
},
"options": {}
},
"type": "n8n-nodes-base.switch",
"typeVersion": 3.4,
"position": [
-1280,
1312
],
"id": "58ccaac1-b56b-40a7-be99-eab514c490fe",
"name": "Switch3"
},
{
"parameters": {
"promptType": "define",
"text": "={{ $('Get Data').item.json.prompt }}",
"options": {
"systemMessage": "=goal {{ $('Get Data').item.json.prompt }}\n\nINDEED JOB SEARCH MODE (STRICT):\n\n1. Parse ONLY the FIRST 5 jobs from the search results page. Do not collect more than 5.\n\n2. For each job extract this exact structure:\n {\n \"title\": \"...\",\n \"company\": \"...\",\n \"location\": \"...\",\n \"link\": \"full clean URL\",\n \"snippet\": \"short description or salary if available\",\n \"posted\": \"...\",\n \"cover_letter\": \"A well-written short response / cover letter (3-6 sentences)\"\n }\n\n3. Generate \"cover_letter\" intelligently:\n - If the user prompt contains any information about the candidate's experience, skills, years of experience, technologies or background, use that information to personalize the cover letter.\n - If the prompt does not contain any experience information, generate a professional, generic but strong cover letter.\n\n4. After collecting exactly 5 jobs, return success.\n\nFinal output must be ONLY this valid JSON (no extra text):\n{\n \"status\": \"success\",\n \"jobs\": [ array of 5 jobs with cover_letter inside each ],\n \"message\": \"Collected 5 jobs and generated cover letters\"\n}\n\nSTRICT RULES:\n- Collect maximum 5 jobs only.\n- Never click into individual job pages. Collect everything from the search results page.\n- Deduplication by link.\n- Use exact coordinates (cx, cy) from the UI-tree.\n- Visibility logic: if v:1 \u2192 perform action, if v:0 \u2192 scroll first.\n- Output ONLY valid JSON. No explanations, no prose.\n\n\nAVAILABLE ACTIONS: same as your current (search-url, scroll, click, type, clear, etc.)\nAVAILABLE ACTIONS (Only one JSON per response):\n{\"action\": \"clear\", \"x\": NUMBER, \"y\": NUMBER, \"reason\": \"...\"}\n{\"action\": \"click\", \"x\": NUMBER_FROM_LIST, \"y\": NUMBER_FROM_LIST, \"reason\": \"...\"}\n{\"action\": \"type\", \"text\": \"text_to_type\", \"x\": NUMBER_FROM_LIST, \"y\": NUMBER_FROM_LIST, \"reason\": \"...\"} (x,y only if field focus is needed)\n{\"action\": \"key\", \"text\": \"ENTER\", \"reason\": \"...\"}\n{\"action\": \"scroll\", \"amount\": -1000, \"x\": NUMBER, \"y\": NUMBER, \"reason\": \"...\"} (use -1000 to scroll DOWN to the bottom, +1000 to scroll UP to the top)\n{\"action\": \"search-url\", \"url\": \"https://...\", \"reason\": \"...\"} OR {\"action\": \"search-url\", \"q\": \"search query\", \"reason\": \"...\"}\n\n{\"status\": \"success\", \"message\": \"briefly describe what was done or provide requested info\"}\n{\"status\": \"error\", \"message\": \"detailed reason why the goal cannot be achieved\"}\n\nCURRENT SCREEN STRUCTURE (Includes CURRENT_URL and SCREEN_SIZE):\n{{ $('Get UI Tree3').item.json.data }}"
}
},
"type": "@n8n/n8n-nodes-langchain.agent",
"typeVersion": 3.1,
"position": [
1344,
1216
],
"id": "5c3eb95e-54c3-4bfa-b235-5101a5e622ce",
"name": "AI Agent6"
},
{
"parameters": {
"url": "={{ $('GLOBAL_CONFIG').item.json.url }}/list",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-Stealth-Token",
"value": "={{ $('GLOBAL_CONFIG').item.json.authToken }}"
}
]
},
"options": {}
},
"id": "12d68b85-6556-40d3-94c9-67a479d395d8",
"name": "Get UI Tree3",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
896,
1248
]
},
{
"parameters": {
"url": "={{ $('GLOBAL_CONFIG').item.json.url }}",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "action",
"value": "={{ $('Code in JavaScript4').item.json.action }}"
},
{
"name": "x",
"value": "={{ $('Code in JavaScript4').item.json.x }}"
},
{
"name": "y",
"value": "={{ $('Code in JavaScript4').item.json.y }}"
},
{
"name": "isNormalized",
"value": "={{ $json.isNormalized }}"
},
{
"name": "text",
"value": "={{ $json.text }}"
},
{
"name": "amount",
"value": "={{ $json.amount }}"
}
]
},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "X-Stealth-Token",
"value": "={{ $('GLOBAL_CONFIG').item.json.authToken }}"
}
]
},
"options": {}
},
"id": "93c52430-f218-4ba3-823b-74ae3e74aa73",
"name": "Send Command to Launcher3",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
2352,
1168
]
},
{
"parameters": {
"jsCode": "// \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432\u0445\u043e\u0434\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442 AI Agent\nlet rawContent = $input.first().json.output;\n\ntry {\n // 1. \u041e\u0447\u0438\u0441\u0442\u043a\u0430 \u043e\u0442 markdown-\u043e\u0431\u0435\u0440\u0442\u043e\u043a \u0438 \u043b\u0438\u0448\u043d\u0438\u0445 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432\n let cleaned = rawContent\n .replace(/```json\\s*/gi, '')\n .replace(/```\\s*$/gm, '')\n .trim();\n\n // 2. \u0418\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u043b\u0430 JSON\n const jsonRegex = /\\{[\\s\\S]*\\}/;\n const match = cleaned.match(jsonRegex);\n if (!match) {\n throw new Error(\"JSON \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d \u0432 \u043e\u0442\u0432\u0435\u0442\u0435\");\n }\n\n const cleanJson = JSON.parse(match[0]);\n\n // 3. \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u0442\u0430\u0442\u0443\u0441\u043e\u0432\n if (cleanJson.status === \"success\") {\n return [{\n json: {\n action: \"success\",\n message: cleanJson.message || \"Done\",\n jobs: cleanJson.jobs || [], // \u2190 \u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435\n profiles: [], // \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0434\u043b\u044f \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u043e\u0441\u0442\u0438\n is_searching: false\n }\n }];\n }\n\n if (cleanJson.status === \"error\") {\n return [{\n json: {\n action: \"error\",\n message: cleanJson.message || \"\u041e\u0448\u0438\u0431\u043a\u0430\",\n reason: cleanJson.reason || \"\u0410\u0433\u0435\u043d\u0442 \u0441\u043e\u043e\u0431\u0449\u0438\u043b \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435\",\n is_searching: false\n }\n }];\n }\n\n if (cleanJson.status === \"searching\") {\n return [{\n json: {\n action: \"vision_needed\",\n target: cleanJson.target || \"element\",\n reason: cleanJson.reason || \"\u041f\u043e\u0438\u0441\u043a \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430...\",\n is_searching: true\n }\n }];\n }\n\n // 4. \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 (click, type, scroll, search-url \u0438 \u0442.\u0434.)\n if (!cleanJson.action) {\n throw new Error(\"\u0412 \u043e\u0442\u0432\u0435\u0442\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 action \u0438\u043b\u0438 status\");\n }\n\n let result = {\n action: cleanJson.action,\n reason: cleanJson.reason || \"\u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f\",\n is_searching: false\n };\n\n // \u041d\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432\n if (cleanJson.x !== undefined) result.x = parseFloat(cleanJson.x);\n if (cleanJson.y !== undefined) result.y = parseFloat(cleanJson.y);\n if (cleanJson.text !== undefined) result.text = cleanJson.text;\n if (cleanJson.amount !== undefined) result.amount = parseInt(cleanJson.amount, 10);\n\n // \u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u04
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.
anthropicApigooglePalmApitelegramApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Example. Uses agent, httpRequest, memoryBufferWindow, telegram. Event-driven trigger; 55 nodes.
Source: https://github.com/Indext-Data-Lab/executive-secretary-agent-framework/blob/88a48fcd000ca97274d0465232ffa53c88538554/n8n/example.json — 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 workflow is for beauty salons who want consistent, high‑quality social media content without writing every post manually. It also suits agencies and automation builders who manage multiple beauty
This automation is designed to help you generate AI-powered music tracks, cover art, and fully rendered music videos — all triggered from a simple Telegram chat and managed via Google Sheets.
This workflow is designed for marketers, content creators, agencies, and solo founders who want to publish long‑form posts with visuals on autopilot using n8n and AI agents.
Template Carnaval - time instagram. Uses toolWorkflow, lmChatOpenAi, memoryBufferWindow, agent. Event-driven trigger; 56 nodes.
This workflow contains community nodes that are only compatible with the self-hosted version of n8n.