{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "fead4f03-9842-47f8-838f-c5137b2f0d5a",
      "name": "Template Guide",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -368,
        -32
      ],
      "parameters": {
        "width": 486,
        "height": 608,
        "content": "## Analyze Meta ads with Gemini and Google Sheets\n\n**How it works:**\n1.  **Extract:** Fetches Ad and Campaign data from Meta API (Yesterday's data).\n2.  **Process:** Aggregates data by Campaign and Ad Set using Code node.\n3.  **Analyze:** Sends data to Gemini to generate qualitative insights for both Client and Agency.\n4.  **Save:** Exports raw data and AI insights to Google Sheets.\n\n**Setup steps:**\n1.  **Configuration:** Update the `Set Configuration` node with your `Ad Account ID` and `Email`.\n2.  **Credentials:** Authenticate your `Facebook Graph API`, `Google Sheets`, `Gmail`, and `Google Gemini` credentials.\n3.  **Spreadsheet:** Create a Google Sheet and update the `Save...` nodes with your Spreadsheet ID.\n4. **Facebook Graph API** [Guide](https://docs.google.com/document/d/1ydWNom0TUVh5SkU9IymlpnM_NXbTqHeL_YetDLn-9m0/edit?usp=sharing)\n9. **Google sheets** [template](https://docs.google.com/spreadsheets/d/11M6Co13t9t2P7NtFaTm9VXHnzUHXO_RGYf-FRnHkS28/edit?usp=sharing)\n10. Use this format to pull the specific date range: `time_range[since]=YYYY-MM-DD&time_range[until]=YYYY-MM-DD`\n\n\nHappy setup,\nBakdaulet Abdikhan\n\nPS. Feel free to add slack/email nodes to notify alerts/updates ;)"
      },
      "typeVersion": 1
    },
    {
      "id": "8936023f-8462-4525-aca0-1f76203fcbd6",
      "name": "Get Config",
      "type": "n8n-nodes-base.set",
      "position": [
        1552,
        -240
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "678b725a-e235-48b1-904d-1fb7ea9ad061",
              "name": "Ad Account ID",
              "type": "string",
              "value": "YOUR_ACT_ID_HERE"
            },
            {
              "id": "b0b6e2b9-6f30-4b53-a61d-485edac8d27b",
              "name": "Email",
              "type": "string",
              "value": "user@example.com"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "193a9ee7-1c12-46cb-b318-f767137a316d",
      "name": "Send Error Email",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1776,
        -240
      ],
      "parameters": {
        "sendTo": "={{ $('Get Config').first().json.Email }}",
        "message": "=<b>Error:</b> {{ $('Error Trigger').first().json.execution.error.message }}<br/>\n<b>Stack:</b> {{ $('Error Trigger').first().json.execution.error.stack }}<br/>\n<b>Last Node Executed:</b> {{ $('Error Trigger').first().json.execution.lastNodeExecuted }}",
        "options": {
          "appendAttribution": false
        },
        "subject": "=N8N ERROR: Daily Ad Pulse for Ad Account {{ $('Get Config').first().json['Ad Account ID'] }} Failed"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "a9d35f35-e8c1-42f9-bb5b-8ca26eefc6be",
      "name": "Structure Data Hierarchy",
      "type": "n8n-nodes-base.code",
      "position": [
        784,
        128
      ],
      "parameters": {
        "jsCode": "// Get all items from previous node\nconst allItems = $input.all();\n\n// Flatten everything into one array (each item.json is an ad)\nconst ads = allItems.map(item => item.json);\n\n// Prepare campaign grouping\nconst campaigns = {};\n\nfor (const ad of ads) {\n  const {\n    campaign_id,\n    campaign_name,\n    adset_id,\n    adset_name,\n    ad_id,\n    ad_name,\n    spend,\n    reach,\n    impressions,\n    clicks,\n    ctr,\n    cpc,\n    cpm,\n    date_start,\n    date_stop,\n    results\n  } = ad;\n\n  // --- Group by Campaign ---\n  if (!campaigns[campaign_id]) {\n    campaigns[campaign_id] = {\n      campaign_id,\n      campaign_name,\n      adsets: {}\n    };\n  }\n\n  // --- Group by Adset ---\n  if (!campaigns[campaign_id].adsets[adset_id]) {\n    campaigns[campaign_id].adsets[adset_id] = {\n      adset_id,\n      adset_name,\n      ads: []\n    };\n  }\n\n  // --- Add Ad ---\n  campaigns[campaign_id].adsets[adset_id].ads.push({\n    ad_id,\n    ad_name,\n    metrics: {\n      spend,\n      reach,\n      impressions,\n      clicks,\n      ctr,\n      cpc,\n      cpm\n    },\n    results,\n    date: {\n      start: date_start,\n      stop: date_stop\n    }\n  });\n}\n\n// Convert nested objects to arrays\nconst output = Object.values(campaigns).map(campaign => ({\n  ...campaign,\n  adsets: Object.values(campaign.adsets)\n}));\n\n// Return final grouped data\nreturn [{ json: { campaigns: output } }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "29c78e97-ea13-4ff3-9a9e-329a9ac3eb7d",
      "name": "Write Insights",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        1216,
        128
      ],
      "parameters": {
        "text": "=Analyze the following Meta Ads data and return structured insights.\n\nData:\n{{ JSON.stringify($json.campaigns, null, 2) }}\n\nRules:\n- Always include both campaign-level and adset-level insights.\n- Write in a professional, concise tone suitable for client reports.\n- For each adset, identify:\n  - best_performing_ad\n  - worst_performing_ad\n  - adset_suggestion (1\u20132 short sentences)\n- For each campaign, summarize overall campaign performance with campaign_suggestion (1\u20132 sentences).\n\nReturn only valid JSON following this schema:\n\n[\n  {\n    \"campaign_name\": \"\",\n    \"campaign_id\": \"\",\n    \"adsets\": [\n      {\n        \"adset_name\": \"\",\n        \"adset_id\": \"\",\n        \"best_performing_ad\": \"\",\n        \"worst_performing_ad\": \"\",\n        \"adset_suggestion\": \"\"\n      }\n    ],\n    \"campaign_suggestion\": \"\"\n  }\n]\n",
        "batching": {},
        "messages": {
          "messageValues": [
            {
              "message": "=You are MetaInsightsGPT \u2014 an expert Meta Ads performance analyst AI working inside a marketing agency automation system.\n\nYour responsibilities:\n- Read structured JSON ad performance data (campaigns \u2192 adsets \u2192 ads).\n- Evaluate ads objectively using spend, CTR, CPC, CPM, and conversions (if available).\n- Identify the best- and worst-performing ads per adset.\n- Generate useful, data-driven insights:\n  - For the agency \u2192 what to optimize or scale.\n  - For the client \u2192 what\u2019s working and why.\n- Write in English.\n\nPerformance logic:\n- Prioritize CTR and conversions as success indicators.\n- If conversions missing, use CTR/CPC ratio.\n- Consider spend and impressions for significance.\n- Ignore zero-impression ads.\n- Never use vague words like \u201cgood\u201d, \u201cbad\u201d, \u201ctry more\u201d.\n- Always quantify insights (e.g., \u201cCTR 2.3% vs. 0.7%\u201d).\n- Output must be strictly valid JSON (no markdown, no commentary).\n\nYou output insights in a consistent JSON structure so they can be parsed into Google Sheets.\n"
            },
            {
              "type": "AIMessagePromptTemplate",
              "message": "=[\n  {\n    \"campaign_name\": \"Engagement Campaign\",\n    \"campaign_id\": \"1234567890\",\n    \"adsets\": [\n      {\n        \"adset_name\": \"Broad Targeting\",\n        \"adset_id\": \"0987654321\",\n        \"best_performing_ad\": \"Video_Variant_A\",\n        \"worst_performing_ad\": \"Image_Variant_B\",\n        \"adset_suggestion\": \"Video_Variant_A achieved 0.9% CTR with 32 clicks. Image_Variant_B underperformed with 0 clicks; consider pausing.\"\n      }\n    ],\n    \"campaign_suggestion\": \"This campaign performs efficiently (CTR ~0.9%) but has uneven engagement across adsets. Reallocate budget toward higher-performing ads.\"\n  }\n]\n"
            }
          ]
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.7
    },
    {
      "id": "8ccc0b9f-d870-4e5f-a0d0-469bb2bfecc0",
      "name": "Save AI Insights",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2032,
        128
      ],
      "parameters": {
        "columns": {
          "value": {
            "Date": "={{ $now.minus({ days: 1 }).toFormat('yyyy-MM-dd') }}",
            "Ad Set": "={{ $json.adsets[0].adset_name }}",
            "Best Ad": "={{ $json.adsets[0].best_performing_ad }}",
            "Campaign": "={{ $json.campaign_name }}",
            "Worst Ad": "={{ $json.adsets[0].worst_performing_ad }}",
            "Agency Suggestion": "={{ $json.adsets[0].suggestion_for_agency }}",
            "Client Suggestion": "={{ $json.adsets[0].suggestion_for_client }}"
          },
          "schema": [
            {
              "id": "Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Campaign",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Campaign",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Ad Set",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Ad Set",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Best Ad",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Best Ad",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Worst Ad",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Worst Ad",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Agency Suggestion",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Agency Suggestion",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Client Suggestion",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Client Suggestion",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "AI_Insights"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_SPREADSHEET_ID_HERE"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "1980b51b-fb7a-4b18-95aa-9cb02ec16158",
      "name": "Save Ad Data",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        784,
        304
      ],
      "parameters": {
        "columns": {
          "value": {
            "cpc": "={{ $json.cpc }}",
            "cpm": "={{ $json.cpm }}",
            "ctr": "={{ $json.ctr }}",
            "date": "={{ $json.date_stop }}",
            "ad_id": "={{ $json.ad_id }}",
            "reach": "={{ $json.reach }}",
            "spend": "={{ $json.spend }}",
            "clicks": "={{ $json.clicks }}",
            "ad_name": "={{ $json.ad_name }}",
            "results": "={{ $json.results[0].values[0].value }}",
            "adset_id": "={{ $json.adset_id }}",
            "adset_name": "={{ $json.adset_name }}",
            "campaign_id": "={{ $json.campaign_id }}",
            "impressions": "={{ $json.impressions }}",
            "campaign_name": "={{ $json.campaign_name }}"
          },
          "schema": [
            {
              "id": "date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "campaign_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "campaign_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "campaign_name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "campaign_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "adset_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "adset_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "adset_name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "adset_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "ad_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "ad_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "ad_name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "ad_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "spend",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "spend",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "results",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "results",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "reach",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "reach",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "impressions",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "impressions",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "clicks",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "clicks",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "ctr",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "ctr",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "cpc",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "cpc",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "cpm",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "cpm",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Ads"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_SPREADSHEET_ID_HERE"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "dd95a46b-39ff-49b4-8d34-516a19a8ea73",
      "name": "Save Campaign Data",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1008,
        -240
      ],
      "parameters": {
        "columns": {
          "value": {
            "CPL": "={{ $json.cost_per_result[0].values[0].value }}",
            "CTR": "={{ $json.ctr }}",
            "Date": "={{ $json.date_start }}",
            "Reach": "={{ $json.reach }}",
            "Spend": "={{ $json.spend }}",
            "Clicks": "={{ $json.clicks }}",
            "Campaign ID": "={{ $json.campaign_id }}",
            "Impressions": "={{ $json.impressions }}",
            "Campaign Name": "={{ $json.campaign_name }}",
            "Conversations Started": "={{ $json.results[0].values[0].value }}"
          },
          "schema": [
            {
              "id": "Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Campaign ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Campaign ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Campaign Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Campaign Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Reach",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Reach",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Impressions",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Impressions",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Conversations Started",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Conversations Started",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "CPL",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "CPL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Clicks",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Clicks",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "CTR",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "CTR",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Spend",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Spend",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Campaigns"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_SPREADSHEET_ID_HERE"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "574a9644-05f3-4df0-a9d8-4fea57a8f562",
      "name": "Set Configuration",
      "type": "n8n-nodes-base.set",
      "position": [
        -16,
        -240
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "678b725a-e235-48b1-904d-1fb7ea9ad061",
              "name": "Ad Account ID",
              "type": "string",
              "value": "YOUR_ACT_ID_HERE"
            },
            {
              "id": "b0b6e2b9-6f30-4b53-a61d-485edac8d27b",
              "name": "Email",
              "type": "string",
              "value": "user@example.com"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "e86432fc-a55d-41f6-ad7f-270129ae2f7e",
      "name": "Split AI Insights",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        1840,
        128
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "output"
      },
      "typeVersion": 1
    },
    {
      "id": "20e6389f-3feb-4b96-bb12-eaedb5c6cc6a",
      "name": "Structured Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1392,
        352
      ],
      "parameters": {
        "jsonSchemaExample": "[\n  {\n    \"campaign_name\": \"string\",\n    \"adsets\": [\n      {\n        \"adset_name\": \"string\",\n        \"best_performing_ad\": \"string\",\n        \"worst_performing_ad\": \"string\",\n        \"suggestion_for_agency\": \"string\",\n        \"suggestion_for_client\": \"string\"\n      }\n    ]\n  }\n]\n"
      },
      "typeVersion": 1.3
    },
    {
      "id": "482dd147-d952-4915-adf9-1b7766e47741",
      "name": "Google Gemini Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        1216,
        352
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "3650d021-a1db-494c-9869-027994b0131a",
      "name": "Get Ad Insights - Ad Level",
      "type": "n8n-nodes-base.facebookGraphApi",
      "position": [
        368,
        128
      ],
      "parameters": {
        "edge": "insights?fields=ad_id,ad_name,adset_id,adset_name,campaign_id,campaign_name,spend,reach,impressions,clicks,results,ctr,cpc,cpm&level=ad&date_preset=yesterday",
        "node": "=act_{{ $('Set Configuration').first().json['Ad Account ID'] }}",
        "options": {},
        "graphApiVersion": "v24.0"
      },
      "credentials": {
        "facebookGraphApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "131c45ee-14b8-457f-b6ea-aabe65961104",
      "name": "Get Ad Insights - Campaign Level",
      "type": "n8n-nodes-base.facebookGraphApi",
      "position": [
        352,
        -240
      ],
      "parameters": {
        "edge": "=insights?fields=campaign_id,campaign_name,spend,impressions,clicks,results,marketing_messages_delivered,actions,reach,ctr,cost_per_result&level=campaign&date_preset=yesterday",
        "node": "=act_{{ $('Set Configuration').first().json['Ad Account ID'] }}",
        "options": {},
        "graphApiVersion": "v24.0"
      },
      "credentials": {
        "facebookGraphApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "90e8a0dc-3788-4925-94b1-9fbac67d91f4",
      "name": "Split Ad Data",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        592,
        128
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "data"
      },
      "typeVersion": 1
    },
    {
      "id": "132888b7-a5ee-4985-bb70-184345e2eb9a",
      "name": "Filter Zero Spend",
      "type": "n8n-nodes-base.filter",
      "position": [
        800,
        -240
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "066d6215-ac80-4510-9061-bd121fcae8ff",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.spend }}",
              "rightValue": "0"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "b6db113e-a4e3-48b6-baaf-48a6050b3490",
      "name": "Split Campaign Data",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        592,
        -240
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "data"
      },
      "typeVersion": 1
    },
    {
      "id": "91b6916f-c095-4961-8c12-f4c51dc33453",
      "name": "Error Trigger",
      "type": "n8n-nodes-base.errorTrigger",
      "position": [
        1328,
        -240
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "39328528-4432-41cb-9928-db5520f8ea1d",
      "name": "Schedule - Once per day",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -320,
        -240
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 6
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "1c62cf57-7a30-4c82-be4e-f5ee409419e8",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -368,
        -368
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 288,
        "content": "## Configuration & schedule\n\u2022 Define run frequency\n\u2022 Set account and reporting parameters\n"
      },
      "typeVersion": 1
    },
    {
      "id": "5990642f-977b-4e46-9ad6-04557dfb58c7",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        320,
        -368
      ],
      "parameters": {
        "color": 7,
        "width": 880,
        "height": 288,
        "content": "## Campaign-level data collection\n\u2022 Fetch campaign performance data\n\u2022 Remove zero-spend campaigns\n\u2022 Store clean campaign metrics\n"
      },
      "typeVersion": 1
    },
    {
      "id": "23cf66be-16d5-45fb-bd5e-061ac14560ca",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        320,
        -16
      ],
      "parameters": {
        "color": 7,
        "width": 720,
        "height": 496,
        "content": "## Ad-level data collection\n\u2022 Fetch ad-level performance data\n\u2022 Normalize and structure records\n\u2022 Persist raw ad metrics\n"
      },
      "typeVersion": 1
    },
    {
      "id": "e9927923-b091-4dfc-8b71-026663ca5f86",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1136,
        -16
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 512,
        "content": "## AI analysis & insights\n\u2022 Analyze performance with Gemini\n\u2022 Detect winners and underperformers\n\u2022 Generate actionable recommendations\n"
      },
      "typeVersion": 1
    },
    {
      "id": "cb8b95e6-7967-4c67-9f7b-cfe41f2362c1",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1728,
        -16
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 512,
        "content": "## Insights storage\n\u2022 Split structured AI output\n\u2022 Save insights for reporting\n"
      },
      "typeVersion": 1
    },
    {
      "id": "e5dcc793-68a0-4f4f-8f1d-2d8a86f710cf",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1280,
        -368
      ],
      "parameters": {
        "color": 7,
        "width": 720,
        "height": 288,
        "content": "## Error handling\n\u2022 Catch workflow failures\n\u2022 Send notification email\n"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Get Config": {
      "main": [
        [
          {
            "node": "Send Error Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Error Trigger": {
      "main": [
        [
          {
            "node": "Get Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Ad Data": {
      "main": [
        [
          {
            "node": "Save Ad Data",
            "type": "main",
            "index": 0
          },
          {
            "node": "Structure Data Hierarchy",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Write Insights": {
      "main": [
        [
          {
            "node": "Split AI Insights",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Zero Spend": {
      "main": [
        [
          {
            "node": "Save Campaign Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Configuration": {
      "main": [
        [
          {
            "node": "Get Ad Insights - Campaign Level",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split AI Insights": {
      "main": [
        [
          {
            "node": "Save AI Insights",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Campaign Data": {
      "main": [
        [
          {
            "node": "Filter Zero Spend",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule - Once per day": {
      "main": [
        [
          {
            "node": "Set Configuration",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get Ad Insights - Ad Level",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Write Insights",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Structure Data Hierarchy": {
      "main": [
        [
          {
            "node": "Write Insights",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Write Insights",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Get Ad Insights - Ad Level": {
      "main": [
        [
          {
            "node": "Split Ad Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Ad Insights - Campaign Level": {
      "main": [
        [
          {
            "node": "Split Campaign Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}