This workflow corresponds to n8n.io template #9005 — 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 →
{
"meta": {
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "b522f688-3201-468f-878c-96575adeef55",
"name": "Append or update row in sheet1",
"type": "n8n-nodes-base.googleSheets",
"position": [
-832,
1584
],
"parameters": {
"columns": {
"value": {
"url": "={{ $json.url }}",
"text": "={{ $json.text }}",
"author": "={{ $json.author.userName }}",
"location": "={{ $json.author.location }}",
"url author": "={{ $json.author.url }}"
},
"schema": [
{
"id": "url",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "text",
"type": "string",
"display": true,
"required": false,
"displayName": "text",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "author",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "author",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "url author",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "url author",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "location",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "location",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"url"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1b87NBYctXlv5e-cfjF8XrGgtfLElgnELyDBcumoM2bE/edit#gid=0",
"cachedResultName": "X"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1b87NBYctXlv5e-cfjF8XrGgtfLElgnELyDBcumoM2bE",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1b87NBYctXlv5e-cfjF8XrGgtfLElgnELyDBcumoM2bE/edit?usp=drivesdk",
"cachedResultName": "X and threads"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "92929cdf-2771-4e86-bd78-9d1cd7c8c4ba",
"name": "Edit Fields",
"type": "n8n-nodes-base.set",
"position": [
-1888,
1680
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "946aeca1-2f8e-418d-9970-45a0c3c768c0",
"name": "url",
"type": "string",
"value": "={{ $json.url }}"
},
{
"id": "9c6a1f7e-5975-47bf-bebd-42eab220ccf1",
"name": "text",
"type": "string",
"value": "={{ $json.text }}"
},
{
"id": "1796f734-f0d9-430b-bce9-2c7fe9fa50c6",
"name": "author.userName",
"type": "string",
"value": "={{ $json.author.userName }}"
},
{
"id": "dcbda70c-ce37-4c6e-971b-d25a0cc1ef59",
"name": "author.url",
"type": "string",
"value": "={{ $json.author.url }}"
},
{
"id": "edaa24fe-eb31-4caa-a67f-2bfd6649752f",
"name": "author.location",
"type": "string",
"value": "={{ $json.author.location }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "d8ed862b-a231-46ea-ba29-eeddb19a6b1e",
"name": "6 hours",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-2336,
1680
],
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 12
}
]
}
},
"typeVersion": 1.2
},
{
"id": "ad8fa0da-5452-4de7-849c-56920740d38d",
"name": "HTTP Request",
"type": "n8n-nodes-base.httpRequest",
"position": [
-2112,
1680
],
"parameters": {
"url": "https://api.apify.com/v2/acts/apidojo~tweet-scraper/run-sync-get-dataset-items?",
"method": "POST",
"options": {
"redirect": {
"redirect": {}
}
},
"jsonBody": "{\n \"maxItems\": 50,\n \"searchTerms\": [\n \"n8n developer\", \n \"looking for n8n\",\n \"n8n expert\",\n \"hire AI automation\", \n \"looking for AI automation\"\n ],\n \"sort\": \"Latest\"\n}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"headerParameters": {
"parameters": [
{
"name": "Accept",
"value": "application/json"
},
{
"name": "Authorization",
"value": "Bearer "
}
]
}
},
"typeVersion": 4.2
},
{
"id": "c7442722-6a28-4e0e-b8bd-09fc95cd6a2f",
"name": "Send a text message1",
"type": "n8n-nodes-base.telegram",
"position": [
-832,
1744
],
"parameters": {
"text": "=Tweet URL: {{ $json.url }} \nAuthor:{{ $json.author.userName }}\nAuthor URL: {{ $json.author.url }}\nLocation:{{ $json.author.location }}\nText: {{ $json.text }}",
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "0745d915-2372-4ae4-af55-10f659327f68",
"name": "AI Agent1",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-1664,
1680
],
"parameters": {
"text": "=This is the text that you have to check {{ $json.text }}{{ $json.url }}{{ $json.author }}\n",
"options": {
"systemMessage": "=<goal> You are **Hiring Post Classifier & Extractor**. Read short social posts (Twitter/Threads), plus author bio and any link-preview text, and return **only** posts where the **author is hiring an n8n/AI automation engineer** in allowed geographies. Deduplicate against Google Sheets by `url`. If non-passing or duplicate \u2192 **output nothing**. </goal>\n\n<format_rules>\n\nInput (exact shape):\n\n{\n \"url\": \"https://twitter.com/... or https://www.threads.net/...\",\n \"text\": \"raw post text\",\n \"author\": {\n \"userName\": \"handle or display name\",\n \"url\": \"author profile url\",\n \"location\": \"free-text location from bio (optional)\"\n }\n}\n\n\nOutput: strict JSON (see <output>) for passing, non-duplicate posts; otherwise no output (empty response).\n\nNo extra fields, arrays, prose, or explanations.\n</format_rules>\n\n\n<decision_rules>\n\nReduce tokens where ever possible\n\nHire-only by the author (no replies/retweets unless the author restates as the hirer).\nAccept only if text clearly signals an open n8n/AI automation engineer role.\nStrong hire cues (any): hiring, we\u2019re hiring, opening, role, position, join our team, bring on an automation engineer, seeking n8n engineer, need an AI automation engineer, apply, send your portfolio/resume, email to, link to job.\nHelpful (not required): full-time, part-time, contract, paid, salary, compensation.\nRole scope (accept): n8n engineer, AI automation engineer, workflow automation engineer, automation developer (explicit n8n/AI automation duties), no-code/low-code automation engineer (with n8n/AI explicitly mentioned).\nExclude: generic software roles without automation focus; RPA-only if n8n/AI automation isn\u2019t explicit; \u201cconsultant available\u201d language (see self-promo).\n\nExclude self-promotion / service ads / bait.\nReject if the author markets themselves/services (e.g., \u201chire me,\u201d \u201cavailable for projects,\u201d \u201cmy rates,\u201d \u201cportfolio/reel,\u201d \u201cDMs open to hire me,\u201d \u201cbook me,\u201d \u201cclient work,\u201d \u201ccommissions,\u201d \u201cservices\u201d).\nIf the bio indicates the author is a freelancer for hire and the post is ambiguous \u2192 treat as self-promo \u2192 exclude.\n\nDeduplication (Google Sheets).\nAfter passing 1\u20133, query the sheet for the url. If found \u2192 no output. If not found \u2192 output JSON.\n</decision_rules>\n\n<tools_and_usage>\n<google_sheets access=\"read-only\">\n\nmethod: find(url) \u2192 returns a match if the post url already exists\n</google_sheets>\n</tools_and_usage>\n\n<planning_guidance>\n\nConfirm author hiring signal for an n8n/AI automation engineer (not self-promo; not a reply/retweet unless restated).\n\nApply geo rules using post text, bio location, and link-preview text.\n\nIf pass, dedupe via Google Sheets on url.\n\nIf unique, emit strict JSON with minimal pass-through fields.\n</planning_guidance>\n\n<output> For passing, non-duplicate posts, return **only**: ```json { \"url\": \"{{ $json.url }}\", \"text\": \"{{ $json.text }}\", \"username\": \"{{ $json.author.userName }}\", \"profile_url\": \"{{ $json.author.url }}\", \"location\": \"{{ $json.author.location }}\" } ``` Otherwise, **return nothing**. </output>\n\n"
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 2.2
},
{
"id": "beae3b6b-780b-4fa8-836b-c17e9d1bfa73",
"name": "OpenAI Chat Model1",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
-1664,
1904
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4.1-mini"
},
"options": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "ff6f42d3-893c-453f-bf85-db69c094ad46",
"name": "Get row(s) in sheet in Google Sheets1",
"type": "n8n-nodes-base.googleSheetsTool",
"position": [
-1536,
1904
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1b87NBYctXlv5e-cfjF8XrGgtfLElgnELyDBcumoM2bE/edit#gid=0",
"cachedResultName": "X"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1b87NBYctXlv5e-cfjF8XrGgtfLElgnELyDBcumoM2bE",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1b87NBYctXlv5e-cfjF8XrGgtfLElgnELyDBcumoM2bE/edit?usp=drivesdk",
"cachedResultName": "X and threads"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "e4a986d2-4146-46bc-9ca8-d4acc07c9e52",
"name": "Code1",
"type": "n8n-nodes-base.code",
"position": [
-1088,
1680
],
"parameters": {
"jsCode": "const results = [];\n\nfor (const item of $input.all()) {\n try {\n const rawData = item.json.output; // The raw string from the LLM\n\n // --- FIX IS HERE ---\n // Find the first opening curly brace '{'\n const firstBrace = rawData.indexOf('{');\n // Find the last closing curly brace '}'\n const lastBrace = rawData.lastIndexOf('}');\n\n // If both braces are found, extract the content between them\n if (firstBrace !== -1 && lastBrace !== -1) {\n const jsonString = rawData.substring(firstBrace, lastBrace + 1);\n\n // Now, parse the cleaned string\n const obj = JSON.parse(jsonString);\n\n results.push({ json: obj });\n }\n // --- END OF FIX ---\n\n } catch (error) {\n // This will catch any items that still fail to parse,\n // so the whole workflow doesn't stop for one bad item.\n console.error(\"Failed to parse an item:\", error);\n }\n}\n\nreturn results;\n"
},
"typeVersion": 2
},
{
"id": "4f0c0edc-ac12-41ff-9733-71df7f1ed66f",
"name": "If",
"type": "n8n-nodes-base.if",
"position": [
-1312,
1680
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "d6b35f7a-4b86-4aa0-a826-c6992ad15da2",
"operator": {
"type": "string",
"operation": "notEmpty",
"singleValue": true
},
"leftValue": "={{ $json.output }}",
"rightValue": "={}"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "63532971-8154-4fd7-8805-c9a86d685588",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3088,
1264
],
"parameters": {
"color": 5,
"width": 672,
"height": 1184,
"content": "Automatically scrape X (Twitter) for posts hiring specific roles (e.g., automation engineers, video editors, graphic designers), filter true hiring intent with AI, deduplicate in Google Sheets, and alert via Telegram.\n\n## What it does\n\n- Pulls recent X/Twitter posts for multiple role keywords via Apify.\n\n- Normalizes each post (text, author, links, location).\n\n- Uses an AI Agent to keep only posts where the author is hiring (not self-promo).\n\n- Checks Google Sheets for duplicates by URL before saving.\n\n- Writes qualified posts to a sheet and sends a Telegram notification.\n\nWe are using n8n automation roles as the example here\n\n\n## How it works (Step by Step)\n\n1. **Schedule Trigger** \u2013 Runs on an interval (currently every 12 hours).\n\n2. **Scrape X/Twitter** \u2013 Apify tweet-scraper fetches up to 50 latest posts for keywords like:\nn8n developer, looking for n8n, n8n expert, hire AI automation, looking for AI automation.\n\n3. **Normalize Fields** \u2013 Set node maps to: url, text, author.userName, author.url, author.location.\n\n4. **AI Filter & Dedupe Check**\n\n- Accept only clear hiring posts for n8n/AI automation roles (reject self-promotion).\n- Queries Google Sheets to see if url already exists; duplicates are dropped.\n\n5. **Gate** \u2013 IF node passes only non-empty AI outputs.\n\n6. **Parse JSON Safely** \u2013 Code node extracts/validates JSON from the AI output.\n\n7. **Save to Google Sheets** \u2013 Appends/updates a row (matching on url).\n\n8. **Telegram Alert** \u2013 Sends a message with the tweet URL, author, location, and text.\n\n## Who it\u2019s for\n\nFreelancers, agencies, and job seekers who want a steady radar of real hiring posts for their target roles.\n\n## Customization Ideas\n\nSwap keywords to track other roles (video editors, designers, copywriters, etc.).\n\nAdd Slack/Discord notifications.\n\nExtend the AI rules (e.g., different geographies or role scopes).\n\nTreat the sheet as a mini-CRM (status, outreach date, notes)."
},
"typeVersion": 1
},
{
"id": "c143fed2-4d73-4532-8492-5fb66fd1ed2e",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3088,
2496
],
"parameters": {
"width": 672,
"height": 256,
"content": "# Looking for tailored workflows? Book through my Reddit or website\u2014and follow for future templates.\n## Reddit: https://www.reddit.com/user/designbyaze/\n## Website: https://hushtech.io/"
},
"typeVersion": 1
},
{
"id": "76c04377-96f0-45ec-84be-6d55e9206f29",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2224,
1264
],
"parameters": {
"color": 5,
"width": 336,
"height": 256,
"content": "## 1. Replace the API keys in each Https node\n## 2. Add the specified role in the json part.\n## 3, The apify actor used: https://apify.com/apidojo/tweet-scraper\n"
},
"typeVersion": 1
}
],
"connections": {
"If": {
"main": [
[
{
"node": "Code1",
"type": "main",
"index": 0
}
]
]
},
"Code1": {
"main": [
[
{
"node": "Send a text message1",
"type": "main",
"index": 0
},
{
"node": "Append or update row in sheet1",
"type": "main",
"index": 0
}
]
]
},
"6 hours": {
"main": [
[
{
"node": "HTTP Request",
"type": "main",
"index": 0
}
]
]
},
"AI Agent1": {
"main": [
[
{
"node": "If",
"type": "main",
"index": 0
}
]
]
},
"Edit Fields": {
"main": [
[
{
"node": "AI Agent1",
"type": "main",
"index": 0
}
]
]
},
"HTTP Request": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model1": {
"ai_languageModel": [
[
{
"node": "AI Agent1",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Get row(s) in sheet in Google Sheets1": {
"ai_tool": [
[
{
"node": "AI Agent1",
"type": "ai_tool",
"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.
googleSheetsOAuth2ApiopenAiApitelegramApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Automatically scrape X (Twitter) for posts hiring specific roles (e.g., automation engineers, video editors, graphic designers), filter true hiring intent with AI, deduplicate in Google Sheets, and alert via Telegram. Pulls recent X/Twitter posts for multiple role keywords via…
Source: https://n8n.io/workflows/9005/ — 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.
Template Name: AI Personal Assistant - Task & Email Management Price: $27 Category: Productivity & Automation Difficulty: Intermediate Use Case: Personal productivity automation for busy professionals
Automatically scrape Meta Threads for posts hiring specific roles (e.g. automation engineers, video editors, graphic designers), filter true hiring intent, deduplicate, and send alerts.
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.
🧠 Gwen – The AI Voice Marketing Agent Gwen is your intelligent voice-powered marketing assistant built in n8n. She combines the power of OpenAI, ElevenLabs, and automation workflows to handle content
This workflow automates the process of generating, reviewing, and publishing blog posts across multiple platforms, now enhanced with support for RSS Feeds as a content source. It streamlines the manag