AutomationFlowsData & Sheets › Pick a Daily Facebook Comment Contest Winner with Openai, Airtable and Telegram

Pick a Daily Facebook Comment Contest Winner with Openai, Airtable and Telegram

ByWeblineIndia @weblineindia on n8n.io

This workflow automatically monitors a Facebook post, extracts comments, enforces a "past winner" blocklist, analyzes sentiment using AI to find positive entries, randomly selects a winner, stores them in Airtable and announces the result via Telegram.

Cron / scheduled trigger★★★★☆ complexityAI-powered18 nodesAirtableOpenAI ChatTelegramSupabaseSentiment AnalysisHTTP Request
Data & Sheets Trigger: Cron / scheduled Nodes: 18 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #12375 — we link there as the canonical source.

This workflow follows the Airtable → 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 →

Download .json
{
  "id": "zMqmuc3C2G5jZ6AX",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Community Contest Tracker (FB Comments) \u2192Sentiment Analysis-> Telegram Winner Alerts + Airtable Proof",
  "tags": [],
  "nodes": [
    {
      "id": "f90317ed-250a-40cd-89eb-9debba6de03d",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -624,
        -896
      ],
      "parameters": {
        "width": 532,
        "height": 662,
        "content": "# Facebook Community Contest Automator\n\n## How it works\n### This workflow automates the selection of a daily contest winner from your Facebook posts. It triggers every night at 9 PM, fetches the latest comments and cross-references them against a list of past winners from Airtable to ensure fairness. It filters out spam, uses OpenAI to identify genuinely positive comments and randomly selects a winner. Finally, it logs the winner to Airtable and announces them via Telegram (or logs errors to Supabase if something fails).\n\n**Setup Steps**\n1. **Credentials:** Configure your Facebook Graph API, Airtable, OpenAI, Telegram and Supabase credentials.\n2. **Post ID:** Update the **Get FB Comments** node with the specific `Post ID` you want to monitor.\n3. **Blocklist:** Ensure the **Get Past Winners** node points to your existing Airtable winner database.\n4. **Activate:** Switch the workflow to Active."
      },
      "typeVersion": 1
    },
    {
      "id": "63f723ea-7a08-41f2-83da-5873246b8274",
      "name": "Sticky Note - Ingestion",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -96,
        -192
      ],
      "parameters": {
        "color": 7,
        "width": 780,
        "height": 450,
        "content": "## 1. Data Ingestion\n\n**Scheduled Fetch**\nTriggers automatically every day at 21:00 (9 PM). \n\n**Context Retrieval**\nSimultaneously fetches fresh comments from the Facebook API and the list of previous winners from Airtable. This ensures the workflow has all necessary data before processing begins."
      },
      "typeVersion": 1
    },
    {
      "id": "67394214-d304-4712-811f-d29b57789595",
      "name": "Sticky Note - Filter",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        -192
      ],
      "parameters": {
        "color": 7,
        "width": 560,
        "height": 450,
        "content": "## 2. Pre-Processing & Filter\n\n**Fairness Logic**\nExecutes custom code to create a \"Blocklist\" of users who have won in the last 30 days, ensuring prize distribution is fair.\n\n**Spam Protection**\nFilters out comments that are too short (e.g., single emojis) or match known spam patterns. If no valid users remain, the workflow halts here."
      },
      "typeVersion": 1
    },
    {
      "id": "244c77de-e58d-45dc-b4ef-5f049ef95096",
      "name": "Sticky Note - AI",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1312,
        -256
      ],
      "parameters": {
        "color": 7,
        "width": 720,
        "height": 642,
        "content": "## 3. AI Analysis & Selection\n\n**Sentiment Engine**\nUses GPT-4o-mini to analyze the context of every eligible comment. It filters strictly for \"Positive\" sentiment to reward constructive community engagement.\n\n**Random Draw**\nFrom the pool of positive, eligible comments, the system mathematically selects one random winner."
      },
      "typeVersion": 1
    },
    {
      "id": "ffcf2f46-2ce9-490c-a3aa-c2156ea6f155",
      "name": "Sticky Note - Storage",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2096,
        -256
      ],
      "parameters": {
        "color": 7,
        "width": 850,
        "height": 620,
        "content": "## 4. Storage & Notifications\n\n**Database Sync**\nWrites the winner's details (Name, ID, Comment) into Airtable for long-term record keeping.\n\n**Multi-Channel Alerting**\nIf successful, sends a celebratory message to the Telegram channel. If the database save fails, it logs the error to Supabase and alerts the Admin immediately."
      },
      "typeVersion": 1
    },
    {
      "id": "5c7e05fc-b073-4c56-a731-2375086d9771",
      "name": "Daily Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -32,
        64
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 21 * * *"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "956ba77c-273b-4d47-b6bf-d59bc95b40f3",
      "name": "Pre-Filter (Blocklist)",
      "type": "n8n-nodes-base.code",
      "position": [
        832,
        64
      ],
      "parameters": {
        "jsCode": "// 1. Get Data from the Mock/API\nconst comments = $(\"Get FB Comments\").first().json.data || [];\nlet pastWinners = [];\ntry {\n  pastWinners = $(\"Get Past Winners\").all().map(i => i.json);\n} catch (e) {\n  pastWinners = [];\n}\n\n// 2. Create Blocklist (Users who won in last 30 days)\n// FIX: We access \"Facebook ID\" directly using brackets (because of the space)\n// We also use .filter(id => id) to skip incomplete records (like the second item in your data)\nconst winnerBlocklist = new Set(\n    pastWinners\n    .map(w => w[\"Facebook ID\"]) \n    .filter(id => id)\n);\n\n// 3. Filter Out Past Winners & Short Comments\nconst eligibleForAI = comments.filter(c => {\n  if (winnerBlocklist.has(c.from.id)) return false;\n  if (!c.message || c.message.length < 2) return false;\n  return true;\n});\n\n// 4. Return INDIVIDUAL ITEMS\nif (eligibleForAI.length === 0) {\n    return [{json: {abort: true, reason: \"No eligible new users found\"}}];\n}\n\nreturn eligibleForAI.map(c => ({\n    json: {\n        abort: false,\n        id: c.from.id,\n        name: c.from.name,\n        text: c.message\n    }\n}));"
      },
      "typeVersion": 1
    },
    {
      "id": "a5c7f7f0-128d-4ded-a7ec-2ca0a754ad07",
      "name": "Any Eligible?",
      "type": "n8n-nodes-base.if",
      "position": [
        1056,
        64
      ],
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{ $json.abort }}",
              "value2": true
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "c8018d6e-b8fc-41fe-8047-19132c0321d0",
      "name": "Pick Random Winner",
      "type": "n8n-nodes-base.code",
      "position": [
        1744,
        32
      ],
      "parameters": {
        "jsCode": "// 1. Get all analyzed items\nconst items = $input.all();\n\n// 2. Filter for POSITIVE sentiment\nconst positiveComments = items.filter(item => {\n    // FIX: Access the nested path 'sentimentAnalysis.category'\n    // Use optional chaining (?.) to prevent crashes if the field is missing\n    const s = item.json.sentimentAnalysis?.category;\n    \n    // Check if sentiment exists and is Positive\n    return s && s.toString().toLowerCase().includes('positive');\n});\n\n// 3. Validation\nif (positiveComments.length === 0) {\n   return [{json: {error: true, message: \"AI found no positive human comments\"}}];\n}\n\n// 4. Random Selection\nconst randomWinner = positiveComments[Math.floor(Math.random() * positiveComments.length)];\n\nreturn [{\n  json: {\n    error: false,\n    winner_id: randomWinner.json.id,\n    winner_name: randomWinner.json.name,\n    winner_comment: randomWinner.json.text,\n    // FIX: Map the output correctly using the same nested path\n    sentiment: randomWinner.json.sentimentAnalysis?.category\n  }\n}];"
      },
      "typeVersion": 1
    },
    {
      "id": "c1a4d98b-f55c-4143-90e3-4ffa500a0326",
      "name": "Get Past Winners",
      "type": "n8n-nodes-base.airtable",
      "position": [
        480,
        64
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "list",
          "value": "appMplJTSjazXzICD",
          "cachedResultUrl": "https://airtable.com/appMplJTSjazXzICD",
          "cachedResultName": "Community Contest Tracker"
        },
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "tblxGqThycjphLBG9",
          "cachedResultUrl": "https://airtable.com/appMplJTSjazXzICD/tblxGqThycjphLBG9",
          "cachedResultName": "Contest Winners"
        },
        "options": {},
        "operation": "search"
      },
      "credentials": {
        "airtableTokenApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "d370b18b-fd5e-49c3-880c-cfd310ad5033",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1344,
        272
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini",
          "cachedResultName": "gpt-4o-mini"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "50f3dc87-b4ac-4a1e-a0e5-5b0c7a39a320",
      "name": "Create a record",
      "type": "n8n-nodes-base.airtable",
      "position": [
        1904,
        32
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "list",
          "value": "appMplJTSjazXzICD",
          "cachedResultUrl": "https://airtable.com/appMplJTSjazXzICD",
          "cachedResultName": "Community Contest Tracker"
        },
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "tblxGqThycjphLBG9",
          "cachedResultUrl": "https://airtable.com/appMplJTSjazXzICD/tblxGqThycjphLBG9",
          "cachedResultName": "Contest Winners"
        },
        "columns": {
          "value": {
            "Date": "={{ $today }}",
            "Name": "={{ $json.winner_name }}",
            "Facebook ID": "={{ $json.winner_id }}"
          },
          "schema": [
            {
              "id": "Name",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Facebook ID",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Facebook ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Date",
              "type": "dateTime",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {
          "typecast": true
        },
        "operation": "create"
      },
      "credentials": {
        "airtableTokenApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "bd006cda-3183-4782-a7ec-9d54a3cd5b01",
      "name": "Notify Admin (Error)1",
      "type": "n8n-nodes-base.telegram",
      "position": [
        2592,
        160
      ],
      "parameters": {
        "text": "=\u26a0\ufe0f Contest Error\n\nDetails: {{ $json.error_message || $json.message }}",
        "chatId": "@youradminchannel",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "7e1ee7ea-cce9-4df2-94a8-d8aaa6fe6bb1",
      "name": "Log Error (Supabase) ",
      "type": "n8n-nodes-base.supabase",
      "position": [
        2416,
        176
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "9a277ea7-db35-46e9-879b-3c9973f9e521",
      "name": "Send a text message1",
      "type": "n8n-nodes-base.telegram",
      "position": [
        2448,
        -32
      ],
      "parameters": {
        "text": "= We have a winner! \nName:  {{ $('Pick Random Winner').item.json.winner_name }}\nCongrats on the positive vibes!",
        "chatId": "123456789",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "39010b0f-a1e4-4807-9842-0b7575bda075",
      "name": "Saved?",
      "type": "n8n-nodes-base.if",
      "position": [
        2160,
        64
      ],
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{ $json.id ? true : false }}",
              "value2": true
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "ae99e7fe-be6c-4d33-ad7b-cdae5333c4ee",
      "name": "Sentiment Analysis",
      "type": "@n8n/n8n-nodes-langchain.sentimentAnalysis",
      "position": [
        1344,
        48
      ],
      "parameters": {
        "options": {
          "categories": "Positive, Neutral, Negative"
        },
        "inputText": "={{ $json.text }}"
      },
      "typeVersion": 1.1
    },
    {
      "id": "d3d0e5ed-6575-443b-81aa-f549c79466c9",
      "name": "Get FB Comments",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        224,
        64
      ],
      "parameters": {
        "url": "https://graph.facebook.com/v19.0/YOUR_POST_ID/comments",
        "options": {},
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "fields",
              "value": "message,from"
            },
            {
              "name": "limit",
              "value": "100"
            }
          ]
        }
      },
      "typeVersion": 4.1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "835829cb-4bb7-4b1e-9329-309885b7bdd9",
  "connections": {
    "Saved?": {
      "main": [
        [
          {
            "node": "Send a text message1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Log Error (Supabase) ",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Any Eligible?": {
      "main": [
        [],
        [
          {
            "node": "Sentiment Analysis",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Daily Trigger": {
      "main": [
        [
          {
            "node": "Get FB Comments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create a record": {
      "main": [
        [
          {
            "node": "Saved?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get FB Comments": {
      "main": [
        [
          {
            "node": "Get Past Winners",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Past Winners": {
      "main": [
        [
          {
            "node": "Pre-Filter (Blocklist)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Sentiment Analysis",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Pick Random Winner": {
      "main": [
        [
          {
            "node": "Create a record",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sentiment Analysis": {
      "main": [
        [
          {
            "node": "Pick Random Winner",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Error (Supabase) ": {
      "main": [
        [
          {
            "node": "Notify Admin (Error)1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Pre-Filter (Blocklist)": {
      "main": [
        [
          {
            "node": "Any Eligible?",
            "type": "main",
            "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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow automatically monitors a Facebook post, extracts comments, enforces a "past winner" blocklist, analyzes sentiment using AI to find positive entries, randomly selects a winner, stores them in Airtable and announces the result via Telegram.

Source: https://n8n.io/workflows/12375/ — original creator credit. Request a take-down →

More Data & Sheets workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Data & Sheets

Automates your complete social media content pipeline: sources articles from Wallabag RSS, generates platform-specific posts with AI, creates contextual images, and publishes via GetLate API. Built wi

Chain Llm, HTTP Request, Airtable +4
Data & Sheets

🚀 Automate your social media presence! This workflow duo automatically curates content from your Wallabag RSS feeds, generates platform-specific posts using AI, and publishes them—complete with AI-gen

Groq Chat, Output Parser Structured, Chain Llm +3
Data & Sheets

Scheduled processes retrieve customer feedback from multiple channels. The system performs sentiment analysis to classify tone, then uses OpenAI models to extract themes, topics, and urgency indicator

HTTP Request, Lm Chat Azure Open Ai, Sentiment Analysis +5
Data & Sheets

Splitout Filter. Uses toolWorkflow, lmChatOpenAi, outputParserStructured, manualTrigger. Event-driven trigger; 38 nodes.

Tool Workflow, OpenAI Chat, Output Parser Structured +3
Data & Sheets

Handles GDPR Article 15 (access) and Article 17 (erasure) requests end-to-end — from inbound email to legally-compliant response — with zero manual intervention and a full audit trail. 📬 Monitors Gmai

Gmail Trigger, Agent, OpenAI Chat +5