{
  "nodes": [
    {
      "id": "58d72e7d-b991-4504-be10-41530abb1568",
      "name": "Daily Engagement Scan",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        480,
        688
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "cee353f1-b8bc-4775-b411-2432e9da5c27",
      "name": "Read Competitor Accounts",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        752,
        688
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "id",
          "value": "competitor_accounts"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_SPREADSHEET_ID"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "3442733f-9516-44e8-9957-d426dae69428",
      "name": "Scrape Instagram Profiles",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1232,
        688
      ],
      "parameters": {
        "url": "=https://api.brightdata.com/datasets/v3/scrape?dataset_id=gd_l1vikfch901nx3by4&format=json",
        "method": "POST",
        "options": {
          "timeout": 60000
        },
        "jsonBody": "={{ JSON.stringify({ input: [{ url: $json.url }] }) }}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "typeVersion": 4.2
    },
    {
      "id": "82fe687d-c4ae-43cd-8347-6497179bf210",
      "name": "Validate BD Response",
      "type": "n8n-nodes-base.code",
      "position": [
        1488,
        688
      ],
      "parameters": {
        "jsCode": "const input = $input.first().json;\n\n// Handle array response (synchronous success)\nif (Array.isArray(input)) {\n  if (input.length === 0) {\n    return [{ json: { error: 'Bright Data returned empty results', status: 'no_data' } }];\n  }\n  return input.map(item => ({ json: { ...item, status: 'ok' } }));\n}\n\n// Handle object response\nif (input.snapshot_id) {\n  return [{ json: { error: 'Async response - snapshot not ready', snapshot_id: input.snapshot_id, status: 'async_pending' } }];\n}\n\nif (input.error || input.message) {\n  return [{ json: { error: input.error || input.message, status: 'api_error' } }];\n}\n\n// Pass through valid single-object response\nreturn [{ json: { ...input, status: 'ok' } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "be302640-982d-4f89-af14-03355442d886",
      "name": "Analyze Engagement",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "onError": "continueErrorOutput",
      "position": [
        2000,
        688
      ],
      "parameters": {
        "text": "Analyze this Instagram competitor profile.\n\nCompetitor: {{ $json.competitor_name }}\nIndustry: {{ $json.our_industry }}\n\nScraped profile data:\n{{ JSON.stringify($json, null, 2) }}",
        "options": {
          "systemMessage": "You are an Instagram competitive intelligence analyst.\nYou receive scraped Instagram profile data for a competitor account.\n\nYour task: analyze the profile metrics and score the competitor on engagement quality.\n\nScoring rubric (0-25 each, total engagement_score 0-100):\n\nfollower_growth_signal (0-25):\n  0-5: Declining or stagnant follower count, signs of bought followers\n  6-12: Slow but organic growth patterns\n  13-19: Steady growth with periodic spikes from viral content\n  20-25: Strong consistent growth indicating high audience demand\n\nengagement_rate_quality (0-25):\n  0-5: Below 0.5% engagement rate or engagement looks artificial\n  6-12: 0.5-2% rate, mostly passive likes with few comments\n  13-19: 2-5% rate with genuine comment threads\n  20-25: 5%+ rate with deep audience interaction and saves/shares\n\ncontent_consistency (0-25):\n  0-5: Sporadic posting, no visual or thematic coherence\n  6-12: Semi-regular posting, some brand consistency\n  13-19: Regular cadence with clear content pillars\n  20-25: Highly consistent brand voice, posting schedule, and visual identity\n\naudience_authenticity (0-25):\n  0-5: High bot/fake follower indicators\n  6-12: Some suspicious patterns but mostly real\n  13-19: Predominantly authentic audience\n  20-25: Highly authentic, engaged community with UGC signals\n\nCRITICAL OUTPUT RULES:\n- Return ONLY a raw JSON object. Nothing else.\n- No markdown. No code fences. No explanations before or after.\n\nOutput schema:\n{\n  \"competitor_name\": \"string\",\n  \"follower_count\": number,\n  \"follower_growth_signal\": number,\n  \"engagement_rate_quality\": number,\n  \"content_consistency\": number,\n  \"audience_authenticity\": number,\n  \"engagement_score\": number,\n  \"top_content_types\": [\"string\"],\n  \"posting_frequency\": \"string\",\n  \"key_strengths\": [\"string\"],\n  \"key_weaknesses\": [\"string\"],\n  \"strategic_takeaway\": \"string\",\n  \"eval\": {\n    \"confidence\": 0.0,\n    \"reasoning\": \"string\",\n    \"data_quality\": \"high|medium|low\",\n    \"evidence_count\": 0\n  }\n}\n\nSELF-EVALUATION (mandatory):\nInclude an \"eval\" object in your response with:\n- confidence: float 0.0-1.0, your confidence in the analysis quality\n- reasoning: 1 sentence explaining your confidence level\n- data_quality: \"high\", \"medium\", or \"low\" based on input completeness\n- evidence_count: integer, number of data points you based the analysis on"
        },
        "promptType": "define"
      },
      "typeVersion": 3
    },
    {
      "id": "509961a9-0df1-45c1-9b4e-4267424aecdc",
      "name": "GPT-5.5 Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        2000,
        928
      ],
      "parameters": {
        "model": "gpt-5.5",
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "64d17917-37d7-4b5a-affd-4591b8209696",
      "name": "Parse AI Output",
      "type": "n8n-nodes-base.code",
      "position": [
        2272,
        688
      ],
      "parameters": {
        "jsCode": "const raw = $input.first().json.output || $input.first().json.text || '';\nconst clean = raw.replace(/```json\\n?/g, '').replace(/```\\n?/g, '').trim();\n\nlet parsed;\ntry {\n  parsed = JSON.parse(clean);\n} catch (e) {\n  parsed = {\n    error: 'Failed to parse AI response',\n    parse_error: e.message,\n    raw_preview: raw.substring(0, 200)\n  };\n}\nconst original = $(\"Read Competitor Accounts\").first().json;\n\nreturn [{ json: { ...original, ...parsed, processed_at: new Date().toISOString() } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "bb4228b8-6760-427e-9655-d1ddd6eb207d",
      "name": "IF Confidence >= 0.7",
      "type": "n8n-nodes-base.if",
      "onError": "continueErrorOutput",
      "position": [
        2528,
        688
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "87d141e2-e963-4e85-93d1-ac205bdf08a0",
              "operator": {
                "type": "number",
                "operation": "gte"
              },
              "leftValue": "={{ $json.eval.confidence }}",
              "rightValue": 0.7
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "9d4e2c5e-faa9-4f72-812b-1d7b53038064",
      "name": "IF Engagement >= 75",
      "type": "n8n-nodes-base.if",
      "onError": "continueErrorOutput",
      "position": [
        2784,
        544
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "33d3c50a-635f-4643-a195-8215feb812b2",
              "operator": {
                "type": "number",
                "operation": "gte"
              },
              "leftValue": "{{ $json.engagement_score }}",
              "rightValue": 75
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "f6f6a556-df6d-4f61-be8c-3e4e68056b3f",
      "name": "Alert Top Performer",
      "type": "n8n-nodes-base.gmail",
      "position": [
        3040,
        400
      ],
      "parameters": {
        "sendTo": "={{ $('Read Competitor Accounts').first().json.team_email || 'team@company.com' }}",
        "message": "=Competitor {{ $json.competitor_name }} scored {{ $json.engagement_score }}/100 on engagement analysis.\n\nKey strengths: {{ $json.key_strengths }}\nStrategic takeaway: {{ $json.strategic_takeaway }}",
        "options": {},
        "subject": "=High-Performing Competitor: {{ $json.competitor_name }} (Score: {{ $json.engagement_score }}/100)",
        "emailType": "text"
      },
      "typeVersion": 2.1
    },
    {
      "id": "e7f72917-6374-4673-8088-d67103561400",
      "name": "Append Top Performers",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3040,
        544
      ],
      "parameters": {
        "columns": {
          "value": {},
          "schema": [],
          "mappingMode": "autoMapInputData",
          "matchingColumns": []
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "id",
          "value": "top_performers"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_SPREADSHEET_ID"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "4750a4c4-d84f-4ac1-a7a2-2e128f295bde",
      "name": "Append Engagement Analysis",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3040,
        768
      ],
      "parameters": {
        "columns": {
          "value": {},
          "schema": [],
          "mappingMode": "autoMapInputData",
          "matchingColumns": []
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "id",
          "value": "engagement_analysis"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_SPREADSHEET_ID"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "05c441ad-a699-49e9-9877-fffa614d8ac4",
      "name": "Append Low Confidence",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2784,
        768
      ],
      "parameters": {
        "columns": {
          "value": {},
          "schema": [],
          "mappingMode": "autoMapInputData",
          "matchingColumns": []
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "id",
          "value": "low_confidence_engagement"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_SPREADSHEET_ID"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "8aa665c6-af9d-4c38-8dad-21643fbb942e",
      "name": "Calculate Raw Engagement Metrics",
      "type": "n8n-nodes-base.code",
      "position": [
        1744,
        688
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\nreturn items.map(item => {\n  const d = item.json;\n  const followers = d.followers_count || d.follower_count || 1;\n  const avgLikes = d.avg_likes || d.edge_liked_by || 0;\n  const avgComments = d.avg_comments || 0;\n  const engagementRate = ((avgLikes + avgComments) / followers * 100).toFixed(2);\n  const postsPerWeek = d.media_count ? Math.min(d.media_count / 52, 20).toFixed(1) : 'unknown';\n  return { json: { ...d, calculated_engagement_rate: parseFloat(engagementRate),\n    posts_per_week: postsPerWeek, metrics_calculated: true } };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "f528564a-35c3-4e31-84df-950f9c27b293",
      "name": "Process Items One by One",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        992,
        688
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "b72803b0-5834-4313-8d00-6dccb93c4632",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -368,
        -96
      ],
      "parameters": {
        "width": 560,
        "height": 720,
        "content": "### How it works\n\nThis workflow monitors competitor Instagram accounts on a daily schedule. It reads profile URLs from a Google Sheet, scrapes each one through the Bright Data Instagram Profiles API, and calculates raw engagement metrics like engagement rate and posting frequency.\n\nGPT-5.5 then analyzes each profile across four dimensions: follower growth signals, engagement rate quality, content consistency, and audience authenticity. Each dimension is scored 0-25 for a total engagement score of 0-100.\n\nTwo quality gates filter the results. A confidence check (>= 0.7) discards unreliable AI outputs. An engagement threshold (>= 75) separates top performers from the rest. High scorers go to the 'top_performers' sheet and trigger a Gmail alert. All other results go to 'engagement_analysis'. Low-confidence outputs land in 'low_confidence_engagement' for review.\n\n### Setup\n\n1. Create a Google Sheet with a tab named 'competitor_accounts' and a 'url' column containing Instagram profile URLs\n2. Add your Bright Data API key as an HTTP Header Auth credential (Bearer token)\n3. Add your OpenAI API key\n4. Connect Google Sheets via OAuth\n5. Connect Gmail via OAuth for alerts\n6. Update the recipient in the 'Alert Top Performer' node\n\nCost: ~$0.01-0.03 per profile (Bright Data) + ~$0.005 per analysis (GPT-5.5)"
      },
      "typeVersion": 1
    },
    {
      "id": "69ff9502-6db9-4c0e-9920-d304badf2990",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        448,
        496
      ],
      "parameters": {
        "color": 7,
        "width": 460,
        "height": 296,
        "content": "## 1. Data Input\n\nTriggers daily at 8 AM. Reads competitor Instagram profile URLs from the 'competitor_accounts' sheet and processes them one at a time."
      },
      "typeVersion": 1
    },
    {
      "id": "a5062c63-4a9f-4e37-9dea-7ada7a71bd21",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1184,
        464
      ],
      "parameters": {
        "color": 7,
        "width": 672,
        "height": 328,
        "content": "## 2. Scrape & Validate\n\nSends each URL to the Bright Data Instagram API, validates the response, and calculates raw engagement metrics."
      },
      "typeVersion": 1
    },
    {
      "id": "8313d152-591c-4ab9-8e03-31e27d9615ca",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1984,
        416
      ],
      "parameters": {
        "color": 7,
        "width": 396,
        "height": 448,
        "content": "## 3. AI Analysis\n\nGPT-5.5 scores each profile on follower growth, engagement quality, content consistency, and audience authenticity (0-100)."
      },
      "typeVersion": 1
    },
    {
      "id": "ed241d1d-2609-4d1d-91e1-0cd416cec306",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2480,
        320
      ],
      "parameters": {
        "color": 7,
        "width": 832,
        "height": 728,
        "content": "## 4. Quality Gates & Output\n\nConfidence gate (>= 0.7) and engagement threshold (>= 75) route results to three sheets. Top performers trigger Gmail alerts."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "GPT-5.5 Model": {
      "ai_languageModel": [
        [
          {
            "node": "Analyze Engagement",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Parse AI Output": {
      "main": [
        [
          {
            "node": "IF Confidence >= 0.7",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Analyze Engagement": {
      "main": [
        [
          {
            "node": "Parse AI Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF Engagement >= 75": {
      "main": [
        [
          {
            "node": "Alert Top Performer",
            "type": "main",
            "index": 0
          },
          {
            "node": "Append Top Performers",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Append Engagement Analysis",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF Confidence >= 0.7": {
      "main": [
        [
          {
            "node": "IF Engagement >= 75",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Append Low Confidence",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate BD Response": {
      "main": [
        [
          {
            "node": "Calculate Raw Engagement Metrics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append Low Confidence": {
      "main": [
        [
          {
            "node": "Process Items One by One",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append Top Performers": {
      "main": [
        [
          {
            "node": "Process Items One by One",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Daily Engagement Scan": {
      "main": [
        [
          {
            "node": "Read Competitor Accounts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Items One by One": {
      "main": [
        [
          {
            "node": "Scrape Instagram Profiles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Competitor Accounts": {
      "main": [
        [
          {
            "node": "Process Items One by One",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scrape Instagram Profiles": {
      "main": [
        [
          {
            "node": "Validate BD Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append Engagement Analysis": {
      "main": [
        [
          {
            "node": "Process Items One by One",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate Raw Engagement Metrics": {
      "main": [
        [
          {
            "node": "Analyze Engagement",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}