AutomationFlowsSocial Media › Twitter/X Scraper

Twitter/X Scraper

Twitter/X Scraper. Uses manualTrigger, googleSheets, noOp, limit. Event-driven trigger; 16 nodes.

Event trigger★★★★☆ complexity16 nodesGoogle SheetsHttp Request
Social Media Trigger: Event Nodes: 16 Complexity: ★★★★☆

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 →

Download .json
{
  "name": "Twitter/X Scraper",
  "nodes": [
    {
      "parameters": {},
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        20,
        460
      ],
      "id": "979d95f8-9197-4b89-adbf-a67ce9a8a7a9",
      "name": "When clicking \u2018Test workflow\u2019"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "bc47f40e-0850-4762-9efb-999608a2c096",
              "name": "counter",
              "value": "={{ $json.count }}",
              "type": "number"
            },
            {
              "id": "92034c06-3976-4099-a7a5-28a252204472",
              "name": "cursor",
              "value": "={{ $json.cursor }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        400,
        460
      ],
      "id": "244050aa-04c4-4ad7-9d16-f8a34fff8332",
      "name": "Counter"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "b2f9c3c3-32f4-48b4-b72f-76f03c35b750",
              "name": "count",
              "value": 1,
              "type": "number"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        200,
        460
      ],
      "id": "395c383f-f6f3-4533-acf8-2eec2305e996",
      "name": "Set Count"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "928894d0-2876-4996-9b1e-3d365b903771",
              "leftValue": "={{ $('Counter').item.json.counter }}",
              "rightValue": 3,
              "operator": {
                "type": "number",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1300,
        460
      ],
      "id": "8eab7011-986e-4089-a50c-78c20b952cfe",
      "name": "If"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "a252eb06-03cd-4e3f-84b0-2a46082606ca",
              "name": "counter",
              "value": "={{ $('Counter').item.json.counter }}",
              "type": "number"
            },
            {
              "id": "43222ff8-c354-4afa-b050-7d55fe30c865",
              "name": "cursor",
              "value": "={{ $('Get Tweets').item.json.next_cursor }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        620,
        780
      ],
      "id": "9becc5d4-0b3f-4673-9bda-1f95addce714",
      "name": "Set Increase"
    },
    {
      "parameters": {
        "jsCode": "// This code should be placed in an n8n Function node\n\n// Get the input items\nconst items = $input.all();\n\n// Process each item in the array\nreturn items.map(item => {\n  // Create a new value for the count field\n  let newCount = 1;\n  \n  // If there's an existing counter value, use it as a base\n  if (item.json && item.json.counter !== undefined) {\n    newCount = item.json.counter + 1;\n  }\n  \n  // Ensure json property exists\n  if (!item.json) {\n    item.json = {};\n  }\n  \n  // Set the value to the new field name \"count\"\n  item.json.count = newCount;\n  \n  // Return the modified item\n  return item;\n});"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        800,
        780
      ],
      "id": "bc04ea46-4d94-4648-bbee-9a5cceb5ae36",
      "name": "Increase Count"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "5be1f203-28ea-4635-b42d-01f2a5bb367f",
              "name": "count",
              "value": "={{ $json.count }}",
              "type": "string"
            },
            {
              "id": "b68f8c17-c045-4b5b-8f8b-367ec72b72a3",
              "name": "cursor",
              "value": "={{ $('Set Increase').item.json.cursor }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        980,
        780
      ],
      "id": "495b42f4-4b73-4adc-b1f4-0a4b8c22cf2d",
      "name": "Set Count and Cursor"
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "1_GeFBfE6vFYFv0C-e_HmpKMB6kDnq676IeidTaWFg0Y",
          "mode": "list",
          "cachedResultName": "Twitter Data",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1_GeFBfE6vFYFv0C-e_HmpKMB6kDnq676IeidTaWFg0Y/edit?usp=drivesdk"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "Sheet1",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1_GeFBfE6vFYFv0C-e_HmpKMB6kDnq676IeidTaWFg0Y/edit#gid=0"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "Tweet ID": "={{ $json.tweetId }}",
            "URL": "={{ $json.url }}",
            "Content": "={{ $json.content }}",
            "Likes": "={{ $json.likeCount }}",
            "Retweets": "={{ $json.retweetCount }}",
            "Replies": "={{ $json.replyCount }}",
            "Quotes": "={{ $json.quoteCount }}",
            "Views": "={{ $json.viewCount }}",
            "Date": "={{ $json.createdAt }}"
          },
          "matchingColumns": [],
          "schema": [
            {
              "id": "Tweet ID",
              "displayName": "Tweet ID",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "URL",
              "displayName": "URL",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Content",
              "displayName": "Content",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Likes",
              "displayName": "Likes",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Retweets",
              "displayName": "Retweets",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Replies",
              "displayName": "Replies",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Quotes",
              "displayName": "Quotes",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Views",
              "displayName": "Views",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "Date",
              "displayName": "Date",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        940,
        460
      ],
      "id": "ce9f712b-c9bf-46e8-a833-de65500d0688",
      "name": "Add to Sheet",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// This approach handles both single tweets and collections\n// It focuses on properly formatting the output for n8n\n// First, let's log what we're working with for debugging\nconsole.log(\"Input item structure:\", JSON.stringify($input.item, null, 2));\n\n// Function to format the date in a more human-readable way\nfunction formatDate(dateString) {\n  if (!dateString) return '';\n  \n  try {\n    const date = new Date(dateString);\n    // Format: \"March 13, 2025 at 19:25\"\n    return date.toLocaleString('en-US', {\n      year: 'numeric',\n      month: 'long',\n      day: 'numeric',\n      hour: '2-digit',\n      minute: '2-digit'\n    });\n  } catch (error) {\n    console.log(\"Error formatting date:\", error);\n    return dateString; // Return original if parsing fails\n  }\n}\n\n// Check if this is a Twitter Search result with multiple tweets\nif ($input.item.json.tweets && Array.isArray($input.item.json.tweets) && $input.item.json.tweets.length > 0) {\n  // This is a collection of tweets\n  // In n8n, to output multiple items, we need to use an array of objects with a json property\n  const items = $input.item.json.tweets.map(tweet => {\n    return {\n      json: {\n        tweetId: tweet.id || '',\n        url: tweet.url || '',\n        content: tweet.text || '',\n        likeCount: tweet.likeCount || 0,\n        retweetCount: tweet.retweetCount || 0,\n        replyCount: tweet.replyCount || 0,\n        quoteCount: tweet.quoteCount || 0,\n        viewCount: tweet.viewCount || 0,\n        createdAt: formatDate(tweet.createdAt)\n      }\n    };\n  });\n  \n  console.log(`Processing ${items.length} tweets`);\n  \n  // Return all items\n  return items;\n} else {\n  // This is a single tweet, just extract and return its data\n  const tweetData = {\n    tweetId: $input.item.json.id || '',\n    url: $input.item.json.url || '',\n    content: $input.item.json.text || '',\n    likeCount: $input.item.json.likeCount || 0,\n    retweetCount: $input.item.json.retweetCount || 0,\n    replyCount: $input.item.json.replyCount || 0,\n    quoteCount: $input.item.json.quoteCount || 0,\n    viewCount: $input.item.json.viewCount || 0,\n    createdAt: formatDate($input.item.json.createdAt)\n  };\n  \n  console.log(\"Processing single tweet\");\n  \n  // Return as a single item\n  return {\n    json: tweetData\n  };\n}"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        760,
        460
      ],
      "id": "916933bb-bffd-4360-be34-ec96f785c807",
      "name": "Extract Info"
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [
        1520,
        460
      ],
      "id": "dfbe6f01-8724-4dd1-9d4e-50a2b1b4a4f7",
      "name": "No Operation, do nothing"
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.limit",
      "typeVersion": 1,
      "position": [
        460,
        780
      ],
      "id": "372b41c3-15ed-42e6-9dbc-f4f2780f38e7",
      "name": "Limit"
    },
    {
      "parameters": {
        "url": "https://api.twitterapi.io/twitter/tweet/advanced_search",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "query",
              "value": "OpenAI"
            },
            {
              "name": "queryType",
              "value": "Top"
            },
            {
              "name": "cursor",
              "value": "={{ $json.cursor }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        580,
        460
      ],
      "id": "e77121c6-b7d2-4d2b-bdee-dfcbd665c84e",
      "name": "Get Tweets",
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "content": "# Increasing Count & Cursor\n",
        "height": 260,
        "width": 1360,
        "color": 5
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -200,
        720
      ],
      "id": "e3f4a99c-3271-485e-b96f-45a0e8afec2f",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "content": "# Checking Count\n",
        "height": 260,
        "width": 500
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1220,
        380
      ],
      "id": "9871378e-88d7-4417-aec5-68c266db1bc3",
      "name": "Sticky Note2"
    },
    {
      "parameters": {
        "content": "# Scraping X",
        "height": 260,
        "width": 1360,
        "color": 4
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -200,
        380
      ],
      "id": "0a948a34-476f-4a79-996e-97033b285b0b",
      "name": "Sticky Note1"
    },
    {
      "parameters": {
        "content": "# Nate Herk | AI Automation",
        "height": 80,
        "width": 500,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        420,
        220
      ],
      "id": "58f84c2a-b87c-4183-a855-67cd6e041822",
      "name": "Sticky Note3"
    }
  ],
  "connections": {
    "When clicking \u2018Test workflow\u2019": {
      "main": [
        [
          {
            "node": "Set Count",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Counter": {
      "main": [
        [
          {
            "node": "Get Tweets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Count": {
      "main": [
        [
          {
            "node": "Counter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If": {
      "main": [
        [
          {
            "node": "No Operation, do nothing",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Limit",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Increase": {
      "main": [
        [
          {
            "node": "Increase Count",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Increase Count": {
      "main": [
        [
          {
            "node": "Set Count and Cursor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Count and Cursor": {
      "main": [
        [
          {
            "node": "Counter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add to Sheet": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Info": {
      "main": [
        [
          {
            "node": "Add to Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Limit": {
      "main": [
        [
          {
            "node": "Set Increase",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Tweets": {
      "main": [
        [
          {
            "node": "Extract Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "ae372884-4333-4aec-93d7-bba986ca3786",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "NaxibodNsCmkKho0",
  "tags": []
}

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.

About this workflow

Twitter/X Scraper. Uses manualTrigger, googleSheets, noOp, limit. Event-driven trigger; 16 nodes.

Source: https://github.com/Zie619/n8n-workflows — original creator credit. Request a take-down →

More Social Media workflows → · Browse all categories →