AutomationFlowsAI & RAG › AI CRM Automation

AI CRM Automation

AI CRM Automation. Uses googleSheetsTrigger, lmChatOpenAi, chainLlm, googleSheets. Event-driven trigger; 6 nodes.

Event trigger★★★★☆ complexityAI-powered6 nodesGoogle Sheets TriggerOpenAI ChatChain LlmGoogle Sheets
AI & RAG Trigger: Event Nodes: 6 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow follows the Chainllm → Google Sheets 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": "AI CRM Automation",
  "nodes": [
    {
      "parameters": {
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "documentId": {
          "__rl": true,
          "value": "1T3CzZOvM8vHFwUQnxG9ACV0aTKochbskQ-dvtCTzaoo",
          "mode": "list",
          "cachedResultName": "AI CRM Automation",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1T3CzZOvM8vHFwUQnxG9ACV0aTKochbskQ-dvtCTzaoo/edit?usp=drivesdk"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "Sheet1",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1T3CzZOvM8vHFwUQnxG9ACV0aTKochbskQ-dvtCTzaoo/edit#gid=0"
        },
        "event": "rowAdded",
        "options": {}
      },
      "id": "803b0419-4a4b-4b83-a6ae-999cffa8d992",
      "name": "Google Sheets Trigger",
      "type": "n8n-nodes-base.googleSheetsTrigger",
      "typeVersion": 1,
      "position": [
        400,
        48
      ],
      "credentials": {
        "googleSheetsTriggerOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "notes": "Polls the 'Leads Intake' sheet every minute for newly added rows. Any new lead row triggers automatic enrichment."
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "crma-field-001",
              "name": "row_number",
              "value": "={{ $json.row_number }}",
              "type": "number"
            },
            {
              "id": "crma-field-002",
              "name": "fullName",
              "value": "={{ $json.Name || 'Unknown' }}",
              "type": "string"
            },
            {
              "id": "crma-field-003",
              "name": "email",
              "value": "={{ $json.Email || '' }}",
              "type": "string"
            },
            {
              "id": "crma-field-004",
              "name": "company",
              "value": "={{ $json.Company || 'Unknown' }}",
              "type": "string"
            },
            {
              "id": "crma-field-005",
              "name": "industry",
              "value": "={{ $json.Industry || '' }}",
              "type": "string"
            },
            {
              "id": "crma-field-006",
              "name": "notes",
              "value": "={{ $json.Notes || '' }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "8c21a76a-01d6-4b4f-a677-281ba5b6979f",
      "name": "Normalize Row Data",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        624,
        48
      ],
      "notes": "Maps raw spreadsheet columns into clean, named variables. row_number is kept so the result can be written back to the same row."
    },
    {
      "parameters": {
        "options": {
          "maxTokens": 1500,
          "temperature": 1
        }
      },
      "id": "88605b53-9cdb-4015-9716-0fbaf2ae17a3",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1,
      "position": [
        848,
        240
      ],
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=Analyze this CRM lead and return ONLY a valid JSON object \u2014 no markdown, no explanation, no template placeholders of any kind (never output brackets like [Your Name] or [Company]; use only the real values provided below or write \"Not provided\" if a field is genuinely missing).\n\nLead data:\nName: {{ $json.fullName }}\nEmail: {{ $json.email }}\nCompany: {{ $json.company }}\nIndustry: {{ $json.industry }}\nNotes: {{ $json.notes }}\n\nReturn exactly this JSON structure:\n{\n  \"leadScore\": integer 0-100,\n  \"qualification\": \"one of: Qualified | Needs Nurturing | Not Qualified\",\n  \"enrichmentSummary\": \"2-3 sentences describing the company and opportunity, using only the real data provided\",\n  \"recommendedNextStep\": \"one concrete next action for the sales rep\"\n}"
      },
      "id": "0d866e3c-191a-456a-a926-7f3b873ebcca",
      "name": "Analyze & Enrich Lead",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "typeVersion": 1.5,
      "position": [
        848,
        48
      ],
      "notes": "Sends the normalized lead to gpt-4.1-mini. System prompt explicitly forbids placeholder/template output \u2014 this is the fix for the earlier bug where unfilled brackets like [Your Name] were written to the sheet."
    },
    {
      "parameters": {
        "jsCode": "const item = $input.first();\n\n// Step 1: Get raw text from the LLM Chain output\nlet rawText = '';\ntry {\n  rawText = item.json.text || item.json.output || '';\n} catch (e) {\n  rawText = '';\n}\n\n// Step 2: Strip markdown fences and parse JSON\nlet parsed;\ntry {\n  const cleaned = rawText\n    .replace(/```json/gi, '')\n    .replace(/```/g, '')\n    .trim();\n  parsed = JSON.parse(cleaned);\n} catch (e) {\n  parsed = {};\n}\n\n// Step 3: Detect leftover template placeholders (the original bug) and treat as invalid\nfunction hasPlaceholder(value) {\n  return typeof value === 'string' && /\\[(your|company|email|phone|name|title)[^\\]]*\\]/i.test(value);\n}\n\n// Step 4: Allowed values and safe defaults\nconst validQualification = ['Qualified', 'Needs Nurturing', 'Not Qualified'];\n\nconst rawScore = parseInt(parsed.leadScore, 10);\nconst leadScore = isNaN(rawScore) ? 0 : Math.min(100, Math.max(0, rawScore));\n\nconst result = {\n  row_number: $('Normalize Row Data').item.json.row_number,\n  leadScore,\n  qualification: validQualification.includes(parsed.qualification)\n    ? parsed.qualification\n    : 'Needs Nurturing',\n  enrichmentSummary: (typeof parsed.enrichmentSummary === 'string' && parsed.enrichmentSummary.length > 5 && !hasPlaceholder(parsed.enrichmentSummary))\n    ? parsed.enrichmentSummary\n    : 'Insufficient data for a summary. Manual review recommended.',\n  recommendedNextStep: (typeof parsed.recommendedNextStep === 'string' && parsed.recommendedNextStep.length > 3 && !hasPlaceholder(parsed.recommendedNextStep))\n    ? parsed.recommendedNextStep\n    : 'Manually review this lead \u2014 automated enrichment was incomplete.'\n};\n\nreturn [{ json: result }];"
      },
      "id": "a2827ff6-2f82-4566-b89a-481be012d9e0",
      "name": "Parse & Validate Enrichment",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1120,
        48
      ],
      "notes": "Parses the AI's JSON output. Rejects any field still containing unfilled template brackets (e.g. [Your Name]) and replaces it with a safe fallback instead of writing broken data to the sheet."
    },
    {
      "parameters": {
        "operation": "appendOrUpdate",
        "documentId": {
          "__rl": true,
          "value": "1T3CzZOvM8vHFwUQnxG9ACV0aTKochbskQ-dvtCTzaoo",
          "mode": "list",
          "cachedResultName": "AI CRM Automation",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1T3CzZOvM8vHFwUQnxG9ACV0aTKochbskQ-dvtCTzaoo/edit?usp=drivesdk"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "Sheet1",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1T3CzZOvM8vHFwUQnxG9ACV0aTKochbskQ-dvtCTzaoo/edit#gid=0"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "leadScore": "={{ $json.leadScore }}",
            "qualification": "={{ $json.qualification }}",
            "enrichmentSummary": "={{ $json.enrichmentSummary }}",
            "recommendedNextStep": "={{ $json.recommendedNextStep }}",
            "Email": "={{ $('Normalize Row Data').item.json.email }}"
          },
          "matchingColumns": [
            "Email"
          ],
          "schema": [
            {
              "id": "Name",
              "displayName": "Name",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "Email",
              "displayName": "Email",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "Company",
              "displayName": "Company",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "Industry",
              "displayName": "Industry",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "Notes",
              "displayName": "Notes",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "row_number",
              "displayName": "row_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "leadScore",
              "displayName": "leadScore",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "qualification",
              "displayName": "qualification",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "enrichmentSummary",
              "displayName": "enrichmentSummary",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "recommendedNextStep",
              "displayName": "recommendedNextStep",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "id": "2540c6b7-faf7-49ae-a21d-aa624f1de515",
      "name": "Append or Update Row",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        1280,
        48
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "notes": "Writes the validated enrichment fields back into the same row, matched by row_number."
    }
  ],
  "connections": {
    "Google Sheets Trigger": {
      "main": [
        [
          {
            "node": "Normalize Row Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Row Data": {
      "main": [
        [
          {
            "node": "Analyze & Enrich Lead",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Analyze & Enrich Lead",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Analyze & Enrich Lead": {
      "main": [
        [
          {
            "node": "Parse & Validate Enrichment",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse & Validate Enrichment": {
      "main": [
        [
          {
            "node": "Append or Update Row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate"
  },
  "versionId": "760103f5-0df4-4eb7-9687-b30fbc9d6f09",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodeGroups": [],
  "id": "O092aeRDxo0uJKOj",
  "tags": [
    {
      "updatedAt": "2026-07-25T18:18:08.685Z",
      "createdAt": "2026-07-25T18:18:08.685Z",
      "id": "G8elLSnd3ySOhhG3",
      "name": "crm-automation"
    },
    {
      "updatedAt": "2026-07-25T18:18:08.707Z",
      "createdAt": "2026-07-25T18:18:08.707Z",
      "id": "9oczA1WlNB9PVRVX",
      "name": "google-sheets"
    },
    {
      "updatedAt": "2026-07-12T08:55:20.350Z",
      "createdAt": "2026-07-12T08:55:20.350Z",
      "id": "zLEptWcWohWystrd",
      "name": "openai"
    },
    {
      "updatedAt": "2026-07-19T15:39:41.698Z",
      "createdAt": "2026-07-19T15:39:41.698Z",
      "id": "RZhcdgrGYx5XyAIk",
      "name": "ai-automation"
    }
  ]
}

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

AI CRM Automation. Uses googleSheetsTrigger, lmChatOpenAi, chainLlm, googleSheets. Event-driven trigger; 6 nodes.

Source: https://github.com/nextwave-ai/ai-automation-portfolio/blob/main/Projects/AI-CRM-Automation/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 end-to-end AI-powered recruitment automation workflow helps HR and talent acquisition teams automate the complete hiring pipeline—from resume intake and parsing to GPT-4-based evaluation, TA appr

Form Trigger, Output Parser Structured, Google Drive +10
AI & RAG

&gt; by Thomas Vie Thomas@pollup.net

HTTP Request, OpenAI Chat, Output Parser Structured +4
AI & RAG

Workflow 2823. Uses httpRequest, lmChatOpenAi, outputParserStructured, chainLlm. Event-driven trigger; 19 nodes.

HTTP Request, OpenAI Chat, Output Parser Structured +4
AI & RAG

2823. Uses httpRequest, lmChatOpenAi, outputParserStructured, chainLlm. Event-driven trigger; 19 nodes.

HTTP Request, OpenAI Chat, Output Parser Structured +4
AI & RAG

This workflow watches for new rows in Google Sheets, uses an OpenAI chat model to score and categorize lead intent with structured output, writes the results back to the same sheet, and posts only hig

Google Sheets Trigger, Chain Llm, OpenAI Chat +3