{
  "name": "Weekly AI search visibility report (ChatGPT, Perplexity, Gemini, Google AI Mode) to Sheets + Slack",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "weeksInterval": 1,
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 8
            }
          ]
        }
      },
      "id": "3d5adb24-b6f0-50ff-befd-4862a78a9557",
      "name": "Every Monday 08:00",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        300
      ]
    },
    {
      "parameters": {
        "resource": "Actors",
        "operation": "Run actor and get dataset",
        "actorId": "wrenfield-data~ai-search-visibility-tracker",
        "customBody": "{\n  \"brands\": [\n    \"YourBrand\"\n  ],\n  \"domains\": [\n    \"yourbrand.com\"\n  ],\n  \"competitors\": [\n    \"Competitor One | competitor1.com\",\n    \"Competitor Two | competitor2.com\"\n  ],\n  \"prompts\": [\n    \"What is the best <your category> tool?\",\n    \"Best <your category> software for small businesses\",\n    \"<Competitor One> alternatives\"\n  ],\n  \"engines\": [\n    \"chatgpt\",\n    \"perplexity\",\n    \"gemini\",\n    \"google_ai_mode\"\n  ],\n  \"country\": \"United States\",\n  \"language\": \"English\",\n  \"monitoringMode\": true,\n  \"trackingId\": \"yourbrand-weekly\",\n  \"includeAnswerText\": false,\n  \"maxChecks\": 40\n}",
        "timeout": 1800,
        "memory": 1024,
        "maxTotalChargeUsd": 3,
        "authentication": "apifyApi"
      },
      "id": "ed1d0c9e-5a00-5a5f-a50d-e43229a14354",
      "name": "Check AI answers",
      "type": "@apify/n8n-nodes-apify.apify",
      "typeVersion": 2,
      "position": [
        240,
        300
      ],
      "credentials": {
        "apifyApi": {
          "id": "",
          "name": "Apify account"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// One row per prompt x engine check; drop summary rows. Keeps the sheet flat.\nreturn $input.all()\n  .filter(i => i.json.type === 'check' || i.json.type === undefined)\n  .map(i => ({ json: {\n    week_of: new Date().toISOString().slice(0, 10),\n    prompt: i.json.prompt,\n    engine: i.json.engine_name || i.json.engine,\n    status: i.json.status,\n    brand_mentioned: i.json.brand_mentioned,\n    brand_position: i.json.brand_position,\n    brand_sentiment: i.json.brand_sentiment,\n    your_domain_cited: i.json.your_domain_cited,\n    first_mentioned_brand: i.json.first_mentioned_brand,\n    competitors_mentioned: (i.json.competitors_mentioned || []).join(', '),\n    citations_count: i.json.citations_count,\n    change_vs_last_run: i.json.change_status || '',\n  }}));"
      },
      "id": "0282954c-2822-5f0f-b167-69d64e112b46",
      "name": "Flatten rows",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        480,
        300
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "",
          "mode": "url"
        },
        "sheetName": {
          "__rl": true,
          "value": "AI visibility",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "autoMapInputData",
          "value": {},
          "matchingColumns": [],
          "schema": []
        },
        "options": {}
      },
      "id": "e90edd49-24d3-5441-937b-fd3f66eb63f3",
      "name": "Append to Google Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        720,
        300
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "",
          "name": "Google Sheets account"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Build a short Slack summary from the rows written to the sheet.\nconst rows = $input.all().map(i => i.json);\nconst ok = rows.filter(r => r.status === 'ok');\nconst pct = (n, d) => d ? Math.round(100 * n / d) + '%' : 'n/a';\nconst byEngine = {};\nfor (const r of ok) {\n  const e = byEngine[r.engine] = byEngine[r.engine] || { n: 0, m: 0, c: 0 };\n  e.n++; if (r.brand_mentioned) e.m++; if (r.your_domain_cited) e.c++;\n}\nconst lines = Object.entries(byEngine).map(([e, v]) => `\u2022 ${e}: mentioned in ${pct(v.m, v.n)}, cited in ${pct(v.c, v.n)} (${v.n} checks)`);\nconst changes = rows.filter(r => r.change_vs_last_run && !['unchanged', 'new', ''].includes(r.change_vs_last_run));\nconst firsts = {};\nfor (const r of ok) if (r.first_mentioned_brand) firsts[r.first_mentioned_brand] = (firsts[r.first_mentioned_brand] || 0) + 1;\nconst leader = Object.entries(firsts).sort((a, b) => b[1] - a[1])[0];\nconst text = [\n  `*AI search visibility, week of ${rows[0]?.week_of || ''}*`,\n  `Mentioned in ${pct(ok.filter(r => r.brand_mentioned).length, ok.length)} of ${ok.length} AI answers.`,\n  ...lines,\n  leader ? `Most often named first: ${leader[0]} (${leader[1]}x)` : '',\n  changes.length ? `${changes.length} answers changed since last week, see the sheet.` : 'No changes since last week.',\n].filter(Boolean).join('\\n');\nreturn [{ json: { text } }];"
      },
      "id": "a6d7153a-bf10-5cf6-b13f-95ad2e2de41b",
      "name": "Build summary",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        960,
        300
      ]
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "#marketing",
          "mode": "name"
        },
        "text": "={{ $json.text }}",
        "otherOptions": {}
      },
      "id": "7715e715-db57-5073-af00-92112b96dcb1",
      "name": "Post to Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.2,
      "position": [
        1200,
        300
      ],
      "credentials": {
        "slackApi": {
          "id": "",
          "name": "Slack account"
        }
      }
    },
    {
      "parameters": {
        "content": "## Weekly AI search visibility report\nAsks ChatGPT, Perplexity, Gemini and Google AI Mode your buyer questions every Monday, logs whether your brand is mentioned and cited, and posts a summary to Slack.\n\n**Setup (5 min)**\n1. Add your Apify API token as the *Apify account* credential.\n2. In **Check AI answers**, edit `brands`, `domains`, `competitors` and `prompts`. Keep `trackingId` fixed so week-over-week changes are detected.\n3. Pick a Google Sheet (tab `AI visibility`) and a Slack channel.\n\n**Cost:** 10 prompts x 4 engines = 40 checks per week. Pay per check, no subscription; `maxTotalChargeUsd` caps each run at $3.",
        "height": 330,
        "width": 560,
        "color": 5
      },
      "id": "68edeff0-e26e-5255-b95b-43460a0f9378",
      "name": "Setup",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -40,
        -60
      ]
    }
  ],
  "connections": {
    "Every Monday 08:00": {
      "main": [
        [
          {
            "node": "Check AI answers",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check AI answers": {
      "main": [
        [
          {
            "node": "Flatten rows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Flatten rows": {
      "main": [
        [
          {
            "node": "Append to Google Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append to Google Sheet": {
      "main": [
        [
          {
            "node": "Build summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build summary": {
      "main": [
        [
          {
            "node": "Post to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "tags": []
}