AutomationFlowsAI & RAG › Analyze Files and Compute KPIs with Google Sheets

Analyze Files and Compute KPIs with Google Sheets

Original n8n title: Analyze Agent Sub-workflow

ANALYZE Agent Sub-Workflow. Uses executeWorkflowTrigger, googleDrive, googleSheets. Event-driven trigger; 13 nodes.

Event trigger★★★★☆ complexity13 nodesExecute Workflow TriggerGoogle DriveGoogle Sheets
AI & RAG Trigger: Event Nodes: 13 Complexity: ★★★★☆ Added:

This workflow follows the Execute Workflow Trigger → Google Drive 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
{
  "name": "ANALYZE Agent Sub-Workflow",
  "nodes": [
    {
      "parameters": {
        "inputSource": "passthrough"
      },
      "id": "YOUR_ID",
      "typeVersion": 1.1,
      "name": "When Executed by Another Workflow",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "position": [
        1008,
        1056
      ]
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.splitInBatches",
      "typeVersion": 3,
      "position": [
        1632,
        1056
      ],
      "id": "YOUR_ID",
      "name": "Split In Batches \u2014 FOR EACH CLEAN FILE"
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "leftValue": "={{ $binary.data.mimeType }}",
                    "rightValue": "text/csv",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "id": "YOUR_ID"
                  }
                ],
                "combinator": "and"
              }
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "YOUR_ID",
                    "leftValue": "={{ $binary.data.mimeType }}",
                    "rightValue": "application/json",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              }
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict",
                  "version": 2
                },
                "conditions": [
                  {
                    "id": "YOUR_ID",
                    "leftValue": "={{ $binary.data.mimeType }}",
                    "rightValue": "text/plain",
                    "operator": {
                      "type": "string",
                      "operation": "equals",
                      "name": "filter.operator.equals"
                    }
                  }
                ],
                "combinator": "and"
              }
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.3,
      "position": [
        2192,
        1200
      ],
      "id": "YOUR_ID",
      "name": "Switch \u2014 File Type (by mimeType)"
    },
    {
      "parameters": {
        "jsCode": "// YOUR_ID\n// PERSONAL AI FACTORY v1 \u2014 KPI ENGINE\n// Input: An array of JSON rows from CLEAN (CSV + JSON only)\n// TXT files are ignored because they never reach this node\n// YOUR_ID\n\nconst rows = items.map(i => i.json);\n\n// If no rows (e.g., only TXT in CLEAN), produce empty KPIs\nif (rows.length === 0) {\n  const kpis = {\n    win_rate: 0,\n    avg_margin: 0,\n    aging_days: 0,\n    count_rows: 0\n  };\n\n  const csvRows = [\n    { metric: 'win_rate', value: 0 },\n    { metric: 'avg_margin', value: 0 },\n    { metric: 'aging_days', value: 0 },\n    { metric: 'count_rows', value: 0 }\n  ];\n\n  return [{ json: { kpis, csvRows, summary: \"No structured rows available for KPI computation.\" }}];\n}\n\n// YOUR_ID\n// Helpers\n// YOUR_ID\nconst parseNumber = (value) => {\n  if (value === undefined || value === null || value === \"\") return null;\n  const cleaned = String(value).replace(/[,\u20b9$]/g, '').trim();\n  const num = Number(cleaned);\n  return Number.isFinite(num) ? num : null;\n};\n\nconst parseDate = (value) => {\n  if (!value) return null;\n  const d = new Date(value);\n  return isNaN(d) ? null : d;\n};\n\n// Flexible mapping to handle different column names\nconst mapCol = (row, names) => {\n  for (const n of names) {\n    if (row[n] !== undefined && row[n] !== null && row[n] !== \"\") {\n      return row[n];\n    }\n  }\n  return null;\n};\n\n// YOUR_ID\n// Normalize rows\n// YOUR_ID\nconst normalized = rows.map(r => {\n  return {\n    status: (mapCol(r, ['status', 'state', 'result']) || \"\").toString().toLowerCase(),\n    revenue: parseNumber(mapCol(r, ['revenue', 'amount', 'sale_value', 'price'])),\n    cost: parseNumber(mapCol(r, ['cost', 'expense', 'cogs'])),\n    created_at: parseDate(mapCol(r, ['created_at', 'created', 'date', 'timestamp']))\n  };\n});\n\n// YOUR_ID\n// Compute KPIs\n// YOUR_ID\n\n// Win Rate\nconst total = normalized.length;\nconst wins = normalized.filter(r =>\n  r.status === 'won' ||\n  r.status === 'closed-won' ||\n  r.status === 'success'\n).length;\nconst win_rate = total > 0 ? wins / total : 0;\n\n// Average Margin\nconst margins = normalized\n  .map(r => (r.revenue && r.cost !== null && r.revenue !== 0)\n    ? (r.revenue - r.cost) / r.revenue\n    : null)\n  .filter(v => v !== null);\n\nconst avg_margin = margins.length > 0\n  ? margins.reduce((a, b) => a + b, 0) / margins.length\n  : 0;\n\n// Aging Days\nconst now = new Date();\nconst daysBetween = (a, b) => Math.round((b - a) / (1000 * 60 * 60 * 24));\n\nconst ages = normalized\n  .map(r => r.created_at ? daysBetween(r.created_at, now) : null)\n  .filter(v => v !== null);\n\nconst aging_days = ages.length > 0\n  ? Math.round(ages.reduce((a, b) => a + b, 0) / ages.length)\n  : 0;\n\n// YOUR_ID\n// Output dataset for CSV\n// YOUR_ID\nconst csvRows = [\n  { metric: \"win_rate\", value: win_rate },\n  { metric: \"avg_margin\", value: avg_margin },\n  { metric: \"aging_days\", value: aging_days },\n  { metric: \"count_rows\", value: total }\n];\n\n// YOUR_ID\n// Final Output\n// YOUR_ID\nconst summary = `Computed ${total} structured rows \u2192 win_rate=${(win_rate * 100).toFixed(1)}%, avg_margin=${(avg_margin * 100).toFixed(1)}%, aging_days=${aging_days}`;\n\nreturn [{\n  json: {\n    kpis: {\n      win_rate,\n      avg_margin,\n      aging_days,\n      count_rows: total\n    },\n    csvRows,\n    summary\n  }\n}];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2928,
        1040
      ],
      "id": "YOUR_ID",
      "name": "Function Node \u2014 Compute KPIs"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1,
      "position": [
        2464,
        1136
      ],
      "id": "YOUR_ID",
      "name": "Extract from CSV File"
    },
    {
      "parameters": {
        "operation": "fromJson",
        "options": {}
      },
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1,
      "position": [
        2464,
        1344
      ],
      "id": "YOUR_ID",
      "name": "Extract from JSON File"
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3.2,
      "position": [
        2768,
        1376
      ],
      "id": "YOUR_ID",
      "name": "Merge \u2014 Structured Data (CSV + JSON Rows)"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "n8n-nodes-base.convertToFile",
      "typeVersion": 1.1,
      "position": [
        3216,
        1120
      ],
      "id": "YOUR_ID",
      "name": "Convert to CSV File"
    },
    {
      "parameters": {
        "content": "ANALYZE Agent\n",
        "height": 768,
        "width": 3248
      },
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        752,
        896
      ],
      "typeVersion": 1,
      "id": "YOUR_ID",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "resource": "fileFolder",
        "searchMethod": "query",
        "queryString": "'YOUR_CLEAN_FOLDER_ID' in parents",
        "returnAll": true,
        "filter": {},
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        1328,
        1056
      ],
      "id": "YOUR_ID",
      "name": "Google Drive \u2014 List Files (CLEAN folder)",
      "executeOnce": true,
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "download",
        "fileId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_ID",
          "mode": "id"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        1936,
        1216
      ],
      "id": "YOUR_ID",
      "name": "Google Drive \u2014 Download CLEAN file 2",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "name": "kpi.csv",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "folderId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_ID",
          "mode": "id"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        3504,
        1216
      ],
      "id": "YOUR_ID",
      "name": "Google Drive \u2014 Upload File (to GOLD folder)",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "YOUR_GOOGLE_ID",
          "mode": "list",
          "cachedResultName": "AI_Factory_Control",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1G4x50V3uHSy-jCFt_pf-ZDpvlJN9HPX018-ju8PHdNY/edit?usp=drivesdk"
        },
        "sheetName": {
          "__rl": true,
          "value": "YOUR_SHEET_ID",
          "mode": "list",
          "cachedResultName": "EVENT_LOG",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1G4x50V3uHSy-jCFt_pf-ZDpvlJN9HPX018-ju8PHdNY/edit#gid=2072862873"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "ts": "={{ $now }}",
            "agent": "analyze",
            "input": "={{ $node[\"Google Drive \u2014 Upload File (to GOLD folder)\"].json[\"name\"] }}",
            "output": "={{$node[\"Google Drive \u2014 Upload File (to GOLD folder)\"].json[\"webViewLink\"]}}",
            "status": "success",
            "action": "compute_kpis",
            "notes": "Unified KPI CSV file generated and uploaded to GOLD folder"
          },
          "matchingColumns": [],
          "schema": [
            {
              "id": "ts",
              "displayName": "ts",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "agent",
              "displayName": "agent",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "action",
              "displayName": "action",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "input",
              "displayName": "input",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "output",
              "displayName": "output",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "displayName": "status",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "notes",
              "displayName": "notes",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        3776,
        1344
      ],
      "id": "YOUR_ID",
      "name": "Google Sheets \u2014 Append EVENT_LOG (analzye_success)",
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "When Executed by Another Workflow": {
      "main": [
        [
          {
            "node": "Google Drive \u2014 List Files (CLEAN folder)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split In Batches \u2014 FOR EACH CLEAN FILE": {
      "main": [
        [
          {
            "node": "Function Node \u2014 Compute KPIs",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Google Drive \u2014 Download CLEAN file 2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Switch \u2014 File Type (by mimeType)": {
      "main": [
        [
          {
            "node": "Extract from CSV File",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Extract from JSON File",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Split In Batches \u2014 FOR EACH CLEAN FILE",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Function Node \u2014 Compute KPIs": {
      "main": [
        [
          {
            "node": "Convert to CSV File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract from CSV File": {
      "main": [
        [
          {
            "node": "Merge \u2014 Structured Data (CSV + JSON Rows)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract from JSON File": {
      "main": [
        [
          {
            "node": "Merge \u2014 Structured Data (CSV + JSON Rows)",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge \u2014 Structured Data (CSV + JSON Rows)": {
      "main": [
        [
          {
            "node": "Split In Batches \u2014 FOR EACH CLEAN FILE",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert to CSV File": {
      "main": [
        [
          {
            "node": "Google Drive \u2014 Upload File (to GOLD folder)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Drive \u2014 List Files (CLEAN folder)": {
      "main": [
        [
          {
            "node": "Split In Batches \u2014 FOR EACH CLEAN FILE",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Drive \u2014 Download CLEAN file 2": {
      "main": [
        [
          {
            "node": "Switch \u2014 File Type (by mimeType)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Drive \u2014 Upload File (to GOLD folder)": {
      "main": [
        [
          {
            "node": "Google Sheets \u2014 Append EVENT_LOG (analzye_success)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "YOUR_ID",
  "id": "31KoZPAfZNIKGOtE",
  "tags": []
}

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

ANALYZE Agent Sub-Workflow. Uses executeWorkflowTrigger, googleDrive, googleSheets. Event-driven trigger; 13 nodes.

Source: https://github.com/anshwysmcbel2710/anis-personal-ai-factory-controller/blob/main/workflows/scheduled/analyze_agent_sub_workflow.json — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

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

AI & RAG

This workflow is designed for marketers, content creators, agencies, and solo founders who want to publish long‑form posts with visuals on autopilot using n8n and AI agents. ​

Tool Http Request, Agent, HTTP Request +27
AI & RAG

This workflow contains community nodes that are only compatible with the self-hosted version of n8n.

Output Parser Structured, Telegram, N8N Nodes Tesseractjs +14
AI & RAG

This workflow is a fully automated YouTube Shorts production pipeline. It takes the structured output from a video digestion workflow (transcript, key moments, metadata) and produces finished, rendere

HTTP Request, Google Drive, Execute Workflow Trigger +5
AI & RAG

Based on the Google Sheet data, the AI will retrieve the userstories ID's, retrieves the userstory data and the corresponding attachments and creates sprint goals according to the defined system promp

Google Gemini Chat, Google Sheets, HTTP Request Tool +6
AI & RAG

Faceless Video. Uses httpRequest, agent, googleDrive, stickyNote. Event-driven trigger; 29 nodes.

HTTP Request, Agent, Google Drive +6