{
  "id": "EDJZmzgjpQYoRAFh",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Monitor X",
  "tags": [],
  "nodes": [
    {
      "id": "6d32d28a-d604-431f-a8e9-051b890c63d2",
      "name": "When Executed by Another Workflow",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "position": [
        -320,
        320
      ],
      "parameters": {
        "workflowInputs": {
          "values": [
            {
              "name": "airtop_profile"
            },
            {
              "name": "x_url"
            },
            {
              "name": "relevant_categories"
            }
          ]
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "fcba7e05-3ab7-4036-9505-d840d8cb3d8e",
      "name": "Extract posts",
      "type": "n8n-nodes-base.airtop",
      "position": [
        560,
        320
      ],
      "parameters": {
        "prompt": "=This is X search results. Extract up to 10 non-sponsored posts in English. For each post extract post writer, time, post text and post URL. Return only posts that appear in the search results. A valid post URL inclides /status/\n\n\nAlso classify posts based on the following categories:\n{{ $('Inputs').item.json.categories }}\n\nIMPORTANT anything that is not directly related to categories above should return [NA]",
        "resource": "extraction",
        "additionalFields": {
          "outputSchema": "{  \"type\": \"object\",  \"properties\": {    \"posts\": {      \"type\": \"array\",      \"items\": {        \"type\": \"object\",        \"properties\": {          \"writer\": {            \"type\": \"string\",            \"description\": \"The writer of the post\"          },          \"time\": {            \"type\": \"string\",            \"description\": \"The time the post was made\"          },          \"text\": {            \"type\": \"string\",            \"description\": \"The text content of the post\"          },          \"url\": {            \"type\": \"string\",            \"description\": \"The URL of the post\"          },          \"category\": {            \"type\": \"string\",            \"description\": \"The category of the post based on predefined categories\"          }        },        \"required\": [          \"writer\",          \"time\",          \"text\",          \"url\",          \"category\"        ],        \"additionalProperties\": false      }    }  },  \"required\": [    \"posts\"  ],  \"additionalProperties\": false,  \"$schema\": \"http://json-schema.org/draft-07/schema#\"}",
          "paginationMode": "infinite-scroll",
          "interactionMode": "auto"
        }
      },
      "credentials": {
        "airtopApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "3184b362-5875-445a-8c0f-c7fabfaeca1d",
      "name": "Session",
      "type": "n8n-nodes-base.airtop",
      "position": [
        120,
        320
      ],
      "parameters": {
        "proxy": "integrated",
        "profileName": "={{ $('Inputs').item.json.profile }}"
      },
      "credentials": {
        "airtopApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "e2808fa6-be3d-42db-8fae-077bc977e7fd",
      "name": "Window",
      "type": "n8n-nodes-base.airtop",
      "position": [
        340,
        320
      ],
      "parameters": {
        "url": "={{ $('Inputs').item.json.url }}",
        "resource": "window",
        "additionalFields": {}
      },
      "credentials": {
        "airtopApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "46c08221-84c0-42d3-8a3a-f572e1906e9a",
      "name": "End session",
      "type": "n8n-nodes-base.airtop",
      "position": [
        780,
        320
      ],
      "parameters": {
        "operation": "terminate"
      },
      "credentials": {
        "airtopApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "91460277-a8d9-4425-bc76-68b8f0209ae7",
      "name": "Filter out [NA] posts",
      "type": "n8n-nodes-base.filter",
      "position": [
        1220,
        320
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "111d98cf-f141-45e2-a1d8-36442e2b130b",
              "operator": {
                "type": "string",
                "operation": "notContains"
              },
              "leftValue": "={{ $json.category }}",
              "rightValue": "NA"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "e06c0c9b-c121-4703-903c-e071b21c2498",
      "name": "Parse JSON output",
      "type": "n8n-nodes-base.code",
      "position": [
        1000,
        320
      ],
      "parameters": {
        "jsCode": "const posts =  JSON.parse($('Extract posts').last().json.data.modelResponse).posts\n\nif (!posts.length) {\n  return [{ json: {}}]\n}\n\nreturn posts.map((post) => ({\n  json: post\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "2cb39cac-306f-496c-8198-8118b78f5781",
      "name": "Inputs",
      "type": "n8n-nodes-base.set",
      "position": [
        -100,
        320
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "75931d59-a1ee-483b-97b4-fe3b380e8e11",
              "name": "url",
              "type": "string",
              "value": "={{ $json.x_url }}"
            },
            {
              "id": "9547c2d9-1676-4668-adb0-98fd69860d52",
              "name": "profile",
              "type": "string",
              "value": "={{ $json.airtop_profile }}"
            },
            {
              "id": "e54bd389-6933-49b0-9025-5d8a11b94dd0",
              "name": "categories",
              "type": "string",
              "value": "={{ $json.relevant_categories }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "2f194c76-29a7-401f-8cd4-a74794b72c79",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -40,
        -1020
      ],
      "parameters": {
        "color": 5,
        "width": 1100,
        "height": 1240,
        "content": "README\n# Monitor X for Relevant Community Posts\n## Use Case\nThis automation monitors X (formerly Twitter) search pages in real time and extracts high-signal posts that match your categories of interest. It\u2019s ideal for community engagement, lead discovery, thought leadership tracking, or competitive analysis.\n\n## What This Automation Does\nGiven a search URL and a list of categories, it:\n- Logs into X using Airtop\n- Opens the specified search URL\n- Scrolls through the results\n- Extracts up to 10 valid, English-language posts\n- Filters and classifies each post by category (or marks as `[NA]` if unrelated)\n- Returns the structured results as JSON\n\nInput parameters:\n- **airtop_profile** \u2014 An Airtop browser profile authenticated on X\n- **x_url** \u2014 X search URL (e.g., `https://x.com/search?q=ai agents&f=live`)\n- **relevant_categories** \u2014 Text-based list of categories to classify posts (e.g., \"Web automation use cases\", \"Thought leadership\")\n\nOutput:\nA JSON array of posts, each with:\n- `writer`\n- `time`\n- `text`\n- `url`\n- `category`\n\n## How It Works\n1. **Trigger**: This workflow is triggered by another workflow (e.g., a community engagement pipeline).\n2. **Input Setup**: Accepts the Airtop profile, search URL, and categories to use for classification.\n3. **Session**: Starts a browser session using the Airtop profile.\n4. **Window Navigation**: Opens the provided X search URL.\n5. **Extraction**: Scrapes up to 10 posts with `/status/` in the URL and text in English.\n6. **Classification**: Each post is labeled with a category if relevant, or `[NA]` otherwise.\n7. **Filtering**: Discards `[NA]` posts.\n8. **Output**: Returns the list of classified posts.\n\n## Setup Requirements\n1. Airtop profile with an active X login.\n2. Airtop API key connected in n8n.\n3. List of category definitions to guide post classification (used in prompt).\n4. Workflow designed to be triggered externally, not run standalone.\n\n## Next Steps\n- **Feed into Engagement Workflows**: Pass the results to workflows that reply, retweet, or track posts.\n- **Use in Slack Alerts**: Push classified posts into Slack channels for review and reaction.\n- **Customize Classifier**: Refine the categorization logic to include sentiment or company mentions.\n"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "b34d8340-64a4-41e4-a882-59e157490155",
  "connections": {
    "Inputs": {
      "main": [
        [
          {
            "node": "Session",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Window": {
      "main": [
        [
          {
            "node": "Extract posts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Session": {
      "main": [
        [
          {
            "node": "Window",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "End session": {
      "main": [
        [
          {
            "node": "Parse JSON output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract posts": {
      "main": [
        [
          {
            "node": "End session",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse JSON output": {
      "main": [
        [
          {
            "node": "Filter out [NA] posts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When Executed by Another Workflow": {
      "main": [
        [
          {
            "node": "Inputs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}