{
  "id": "i8ATrlawNnV9FGIV",
  "name": "Automate Social Media Posting on Twitter (x.com) using AI Agent & Google Sheets",
  "tags": [],
  "nodes": [
    {
      "id": "185ffe75-df92-4137-a4a2-985e9d4c4359",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        640,
        832
      ],
      "parameters": {
        "text": "=You are an expert social media manager for Intuz's Twitter account. Generate engaging tweets for C-suite executives, CTOs, and engineering leaders.\n\n\ud83d\udea8 ABSOLUTE CHARACTER LIMIT: 250 CHARACTERS MAXIMUM (including ALL text, spaces, hashtags, URLs)\n\nMANDATORY PROCESS:\n1. Draft tweet\n2. Count EVERY character (letters, spaces, punctuation, hashtags, URLs)\n3. If >250 characters: Shorten immediately\n4. Recount until \u2264250 characters\n5. Never exceed 250 under any circumstances\n6. Check for existing same tweets from the Google Sheet, so as to avoid duplicate tweets\n\nOUTPUT FORMAT:\n{\n\"tweet_content\": \"[Your tweet here - max 280 chars]\",\n\"character_count\": \"[X/280]\",\n\"status\": \"Published\"\n}\n\nCONTENT FOCUS: AI trends, automation, cloud tech, RAG, ML innovations, MCP, n8n, Software Development\n\nREQUIREMENTS:\n- Always include #Intuz\n- Add 4-7 relevant hashtags\n- Include URL for https://www.mlopscrew.com/ if the tweet is cloud related otherwise add https://www.intuz.com/\n- Ask questions or add CTAs\n- Make each tweet unique\n- Keep tone: innovative, authoritative, educational\n\nCHARACTER BUDGET:\n- Core message: ~150-180 chars\n- Hashtags: ~40-60 chars\n- URL: ~20-30 chars\n- TOTAL: \u2264250 chars\n\nTARGET: Drive leads, engagement, \"Contact Us\" inquiries\n\nFINAL CHECK: Confirm character count \u2264280 before submitting!",
        "options": {},
        "promptType": "define"
      },
      "typeVersion": 2.2
    },
    {
      "id": "fc8d5d4f-bb1b-4645-8301-d9f08f2d00a6",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        400,
        1248
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini",
          "cachedResultName": "gpt-4.1-mini"
        },
        "options": {}
      },
      "typeVersion": 1.2
    },
    {
      "id": "a768abfb-aa5a-4363-b942-eee38f5deeff",
      "name": "Simple Memory",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        736,
        1728
      ],
      "parameters": {
        "sessionKey": "TWEETS",
        "sessionIdType": "customKey",
        "contextWindowLength": 15
      },
      "typeVersion": 1.3
    },
    {
      "id": "68527ad0-d27f-42aa-bf28-36a8e4f86b84",
      "name": "Create Tweet",
      "type": "n8n-nodes-base.twitter",
      "position": [
        2256,
        992
      ],
      "parameters": {
        "text": "={{ $json.tweet_content }}",
        "additionalFields": {}
      },
      "typeVersion": 2
    },
    {
      "id": "0efc1811-933f-4765-838d-48d48c4e231d",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -272,
        1168
      ],
      "parameters": {
        "width": 464,
        "height": 272,
        "content": "### Step 1: Scheduler Trigger  \nThis node acts as the workflow\u2019s timer \u23f1\ufe0f.  \nIt is configured to automatically trigger the workflow every **6 hours**, ensuring that new tweet content is generated and posted consistently without requiring manual input.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "1f98869b-5a49-4e0b-97c2-beac42127f00",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        464,
        672
      ],
      "parameters": {
        "color": 5,
        "width": 560,
        "height": 352,
        "content": "### Step 2: AI Agent Node  \nThis node acts as the **content brain \ud83e\udde0** of the workflow.  \nIt uses a carefully designed prompt to control the tweet generation process, ensuring that each post is relevant, professional, and aligned with the intended tone. The AI agent dynamically adapts content based on the given context, making every tweet unique and impactful.  \n"
      },
      "typeVersion": 1
    },
    {
      "id": "c855336e-907a-4d16-bcb1-d3f40d355ba9",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        256,
        1216
      ],
      "parameters": {
        "color": 3,
        "width": 384,
        "height": 368,
        "content": "\n\n\n\n\n\n\n\n\n\n\n\n\n### Step 2.1: AI Agent Node  \nThis node acts as the **content brain \ud83e\udde0** of the workflow.  \nIt uses a carefully designed prompt to control the tweet generation process, ensuring that each post is relevant, professional, and aligned with the intended tone. The AI agent dynamically adapts content based on the given context, making every tweet unique and impactful.  \n"
      },
      "typeVersion": 1
    },
    {
      "id": "44a5383e-df8d-4e20-8c5e-413d31a74bce",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        576,
        1712
      ],
      "parameters": {
        "color": 4,
        "width": 464,
        "height": 304,
        "content": "\n\n\n\n\n\n\n\n\n\n### Step 2.2: Simple Memory Node  \nThis node acts as a **context store \ud83e\udde0**, holding the conversation history and relevant details passed from the AI Agent and Chat Model.  \nIt ensures continuity so that future tweet generations stay consistent in tone, style, and context.  \n"
      },
      "typeVersion": 1
    },
    {
      "id": "43269c90-3691-48dc-8c3a-aea53349206b",
      "name": "Get Data from Google Sheet",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        1120,
        1248
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/{YOUR_GOOGLE_SHEETS_DOCUMENT_ID}/edit#gid=0",
          "cachedResultName": "Tweets"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "{YOUR_GOOGLE_SHEETS_DOCUMENT_ID}",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/{YOUR_GOOGLE_SHEETS_DOCUMENT_ID}/edit?usp=drivesdk",
          "cachedResultName": "Twitter"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "dcf857b1-9cf0-42aa-8b5c-651d6cc97118",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        912,
        1232
      ],
      "parameters": {
        "color": 6,
        "width": 496,
        "height": 304,
        "content": "\n\n\n\n\n\n\n\n\n\n\n\n\n### Step 2.3: Get Rows from Google Sheet Node  \nThis node retrieves the list of **already published tweets \ud83d\udcd1** from a connected Google Sheet.  \nBy keeping track of past posts, it ensures the workflow avoids publishing duplicate tweets and maintains fresh, engaging content each time.  \n"
      },
      "typeVersion": 1
    },
    {
      "id": "410b5cb5-b4fb-4c00-9d06-464860334a43",
      "name": "Parse AI Response",
      "type": "n8n-nodes-base.code",
      "position": [
        1616,
        1232
      ],
      "parameters": {
        "jsCode": "// Input: string with escaped or messy JSON\nconst inputString = $input.first().json.output;\n\nfunction safeParse(str) {\n  try {\n    // Try direct parse first\n    return JSON.parse(str);\n  } catch (e) {\n    // Try to extract JSON substring with regex\n    const match = str.match(/\\{[\\s\\S]*\\}/);\n    if (match) {\n      try {\n        return JSON.parse(match[0]);\n      } catch (err) {\n        return { error: \"Failed to parse extracted JSON\", raw: str };\n      }\n    }\n    return { error: \"Invalid JSON format\", raw: str };\n  }\n}\n\nconst parsed = safeParse(inputString);\n\n// Return cleaned output\nreturn [\n  {\n    json: parsed\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "ea5b0b4f-a8f2-41fb-9fa7-d11d89f8b9c1",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1456,
        1040
      ],
      "parameters": {
        "width": 400,
        "height": 352,
        "content": "### Step 3: Code Node  \nThis node parses the **raw string response \ud83d\udcdd** generated by the AI model into a clean, structured **JSON format**.  \nBy converting the response into executable JSON, it ensures that the tweet content is easy to process and ready for further automation steps.  \n"
      },
      "typeVersion": 1
    },
    {
      "id": "190e5bfe-99e6-4dbf-abc2-a56e633ef4a3",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2080,
        816
      ],
      "parameters": {
        "color": 3,
        "width": 432,
        "height": 352,
        "content": "### Step 4: X Create Tweet Node  \nThis node publishes the final tweet \ud83d\udc26 generated by the AI directly to **X (Twitter)**.  \nIt ensures that the content parsed and validated in earlier steps is posted automatically on schedule, keeping your feed consistent and engaging.  \n"
      },
      "typeVersion": 1
    },
    {
      "id": "44d53ba9-ffdc-44dd-9414-65149f2b2449",
      "name": "Add new Tweet to Google sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3024,
        1200
      ],
      "parameters": {
        "columns": {
          "value": {
            "Status": "={{ $('Parse AI Response').item.json.status }}",
            "Tweet Content": "={{ $('Parse AI Response').item.json.tweet_content }}"
          },
          "schema": [
            {
              "id": "Tweet Content",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Tweet Content",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Tweet Content"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/{YOUR_GOOGLE_SHEETS_DOCUMENT_ID}/edit#gid=0",
          "cachedResultName": "Tweets"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "{YOUR_GOOGLE_SHEETS_DOCUMENT_ID}",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/{YOUR_GOOGLE_SHEETS_DOCUMENT_ID}/edit?usp=drivesdk",
          "cachedResultName": "Twitter"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "95ba4418-c676-425d-bdee-a756f1422bea",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2816,
        960
      ],
      "parameters": {
        "color": 4,
        "width": 496,
        "height": 432,
        "content": "### Step 5: Add New Tweet to Google Sheet Node  \nThis node logs each newly published tweet into the connected **Google Sheet**.  \nIt records both the **tweet content** and its **status** (marked as *Published*) to maintain a structured history of all posts.  \n\nThis log is later referenced in **Step 2.3** (Get Rows from Google Sheet) to check for duplicates, ensuring that the AI never regenerates or reposts the same tweet \u2014 completing the cycle of tweet creation, publication, and validation.  \n"
      },
      "typeVersion": 1
    },
    {
      "id": "e9779654-a51b-4c71-b356-9fd7e7d08ea4",
      "name": "Start Workflow",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -96,
        1312
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 6
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "28fca0ca-9c2d-4b14-9c50-4b533bc7fac9",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -368,
        592
      ],
      "parameters": {
        "color": 3,
        "width": 528,
        "height": 432,
        "content": "### Prerequisites  \n\n#### Google Sheets  \n- Connect your Google credentials with **Google Sheets** and **Google Drive** services enabled.  \n- Create a Google Sheet with the following column headers:  \n  - **Tweet Content**  \n  - **Status**  \n- Use this sheet in all Google Sheet nodes within the workflow.  \n\n#### OpenAI  \n- Add and connect your **OpenAI API Key** in the **OpenAI Chat Model node** to enable tweet generation.  \n\n#### X (Twitter)  \n- Connect your **Twitter (X) account credentials** in the **Create Tweet node** to allow automated posting.  \n"
      },
      "typeVersion": 1
    },
    {
      "id": "7d1f8ed7-e600-482f-b4b2-bae71fd337c2",
      "name": "Sticky Note23",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1552,
        1584
      ],
      "parameters": {
        "color": 2,
        "width": 440,
        "height": 240,
        "content": "## Need Help? \n\nWe develop tailored workflow to save youe valuable time. Should you have any questions or wish to explore more custom automation solutions, we would be happy to connect\n\n\n### Email: getstarted@intuz.com\n### Website: https://www.intuz.com/\n\n"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "0d4ea7d6-69a6-40bc-a8f3-4fb1ce2c6315",
  "connections": {
    "AI Agent": {
      "main": [
        [
          {
            "node": "Parse AI Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Tweet": {
      "main": [
        [
          {
            "node": "Add new Tweet to Google sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Simple Memory": {
      "ai_memory": [
        [
          {
            "node": "AI Agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Start Workflow": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Parse AI Response": {
      "main": [
        [
          {
            "node": "Create Tweet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Data from Google Sheet": {
      "ai_tool": [
        [
          {
            "node": "AI Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    }
  }
}