{
  "id": "8m9gPPRDbo6ajqxy",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Zoho - CRM - COMPETITIVE BATTLE CARD GENERATOR",
  "tags": [],
  "nodes": [
    {
      "id": "676e471f-860d-4ab3-8d2c-a71008a3aa69",
      "name": "Cron (every 5 min)",
      "type": "n8n-nodes-base.cron",
      "position": [
        -2720,
        -48
      ],
      "parameters": {
        "triggerTimes": {
          "item": [
            {
              "mode": "everyX",
              "unit": "minutes",
              "value": 5
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "165e0939-bddc-4f44-a7c0-18795859741c",
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "position": [
        -2048,
        -64
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2,
      "alwaysOutputData": true
    },
    {
      "id": "142afbab-800e-426b-ba6f-2fbebb8c7155",
      "name": "Filter New Deals",
      "type": "n8n-nodes-base.code",
      "position": [
        -1808,
        -64
      ],
      "parameters": {
        "jsCode": "// --- Modern n8n Code node version (no `items` implicit var) ---\nconst inputItems = $input.all(); // get all merged inputs\n\n// Find record containing lastCheck\nconst lastCheckItem = inputItems.find(i => i.json.lastCheck);\nconst lastCheckStr = lastCheckItem ? lastCheckItem.json.lastCheck : null;\nif (!lastCheckStr) {\n  return [{ json: { newDeals: [] } }];\n}\n\n// Convert to UTC (10-minute safety buffer)\nconst lastCheckUTC = Date.parse(lastCheckStr) - 10 * 60 * 1000;\n\n// Collect all deals from input\nconst deals = inputItems\n  .map(i => i.json)\n  .filter(i => i.Created_Time);\n\n// Filter only new ones\nconst newDeals = deals.filter(d => {\n  const createdUTC = Date.parse(d.Created_Time);\n  return !isNaN(createdUTC) && createdUTC > lastCheckUTC;\n});\n\n// Return result in new n8n format\nreturn [{ json: { newDeals } }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "364392d2-621a-48f4-adba-2714aa39d7fd",
      "name": "Split the deals",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        -1584,
        -64
      ],
      "parameters": {
        "include": "allOtherFields",
        "options": {},
        "fieldToSplitOut": "newDeals"
      },
      "typeVersion": 1
    },
    {
      "id": "5bc891e3-aa80-4aab-8e32-cd3ee430f8e0",
      "name": "parse competitor info",
      "type": "n8n-nodes-base.code",
      "position": [
        -1088,
        -176
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Extract competitor name and first URL from Description\nconst desc = $json.newDeals.Description || '';\n\nconst urlMatch = desc.match(/https?:\\/\\/[^\\s]+/);\nconst nameMatch = desc.match(/^([\\w\\s\\-\\&]+)/);\n\nreturn {\n  json: {\n    ...$json,\n    competitorName: nameMatch ? nameMatch[1].trim() : '',\n    competitorUrl: urlMatch ? urlMatch[0] : ''\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "c0d322a3-451c-4557-84ab-0d6de9fe63a2",
      "name": "HTTP Request",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -816,
        -176
      ],
      "parameters": {
        "url": "={{ $json.competitorUrl }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "text"
            }
          }
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "e04c5748-f8d4-4152-9f0a-4bc11d96244e",
      "name": "Google Gemini Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        -592,
        48
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "75eea03d-0cac-4946-b114-8ecbe2d5780f",
      "name": "Structured Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        -304,
        48
      ],
      "parameters": {
        "jsonSchemaExample": "{\n  \"competitor\": \"HubSpot\",\n  \"pricing_summary\": \"HubSpot offers Free, Starter, Professional, and Enterprise tiers.\",\n  \"key_features\": [\"CRM\", \"Automation\", \"Sales Dashboard\"],\n  \"pros\": [\"User-friendly\", \"Free tier available\", \"Strong integrations\"],\n  \"cons\": [\"Expensive enterprise plans\", \"Complex setup\", \"Limited customization\"],\n  \"battle_summary\": \"HubSpot dominates SMB CRM with usability; compete on flexibility and pricing.\"\n}\n"
      },
      "typeVersion": 1.3
    },
    {
      "id": "c0861f1a-46a3-435f-8500-1761d7241ca0",
      "name": "Share Battle Card in description",
      "type": "n8n-nodes-base.zohoCrm",
      "position": [
        16,
        -176
      ],
      "parameters": {
        "dealId": "={{ $('parse competitor info').item.json.newDeals.id }}",
        "resource": "deal",
        "operation": "update",
        "updateFields": {
          "Description": "=Competitor name :  {{ $json.output.competitor }}\n\nBattle Card \u2013 {{ $json.output.competitor }}\n\n\n**Pricing Overview:**\n{{ $json.output.pricing_summary }}\n\n**Top Differentiating Features:**  \n{{ $json.output.key_features[0] }}\n{{ $json.output.key_features[1] }}\n{{ $json.output.key_features[2] }}\n\n**Pros (Sales Perspective):**  \n{{ $json.output.pros[0] }}\n{{ $json.output.pros[1] }}\n{{ $json.output.pros[2] }}\n\n**Cons (Sales Perspective):**  \n{{ $json.output.cons[0] }}\n{{ $json.output.cons[1] }}\n{{ $json.output.cons[2] }}\n\n**Battle Summary:**  \n{{ $json.output.battle_summary }}\n"
        }
      },
      "credentials": {
        "zohoOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "87f6055a-e8f6-4de9-aad6-cb6abb212092",
      "name": "Notify Sales via Gmail",
      "type": "n8n-nodes-base.gmail",
      "position": [
        256,
        -176
      ],
      "parameters": {
        "sendTo": "",
        "message": "=Hi Team,\n\nA new AI-generated Battle Card has been created for the deal: {{$('Get many deals').item.json.Deal_Name || \"Unknown Deal\" }}\n\nCompetitor: {{ $('Basic LLM Chain').item.json.output.competitor }}\n\nPricing Summary: {{ $('Basic LLM Chain').item.json.output.pricing_summary }}\n\nKey Features:  {{ $('Basic LLM Chain').item.json.output.key_features }}\n\nBattle Summary:{{ $('Basic LLM Chain').item.json.output.battle_summary }}\n\n\nYou can view this deal directly in Zoho CRM for more details.\n\n- Automated Competitive Intelligence System\n",
        "options": {},
        "subject": "=New Battle Card Generated \u2013 {{ $('Basic LLM Chain').item.json.output.competitor_name || \"Competitor\" }}",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "47537140-29d0-4cf9-92e2-460915aa4484",
      "name": "Get many deals",
      "type": "n8n-nodes-base.zohoCrm",
      "position": [
        -2368,
        -176
      ],
      "parameters": {
        "options": {
          "sort_by": "Created_Time",
          "sort_order": "desc"
        },
        "resource": "deal",
        "operation": "getAll",
        "returnAll": true
      },
      "credentials": {
        "zohoOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "d57f14c4-c31b-4c31-beb5-61b793b22633",
      "name": "Get Last Check (Code Node)",
      "type": "n8n-nodes-base.code",
      "position": [
        -2368,
        32
      ],
      "parameters": {
        "jsCode": "// Compute timestamp 10 minutes back (same as trigger interval)\nconst nowUtc = new Date();\nconst lookbackMinutes = 10;\nconst lastCheckUtc = new Date(nowUtc.getTime() - lookbackMinutes * 60 * 1000);\n\nfunction pad(n){ return String(n).padStart(2,'0'); }\nfunction formatOffset(date){\n  return `${date.getFullYear()}-${pad(date.getMonth()+1)}-${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}+05:30`;\n}\n\nreturn { json: { lastCheck: formatOffset(lastCheckUtc) } };\n"
      },
      "typeVersion": 2
    },
    {
      "id": "ec5e52ea-cd22-4ec8-bdaa-4fc40ba5b7d1",
      "name": "IF Description Present",
      "type": "n8n-nodes-base.if",
      "position": [
        -1376,
        -64
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "6b1e07cd-8aeb-43a8-aaf4-e27cc1a695f8",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.newDeals.Description }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "4b4d1d47-6010-41e2-9be7-f39f77ffdffe",
      "name": "Basic LLM Chain",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        -512,
        -176
      ],
      "parameters": {
        "text": "=You are a sales intelligence assistant.\nAnalyze the HTML content below (from {{ $('parse competitor info').item.json.competitorName || 'the competitor website' }}) \nand extract key sales insights.\n\nProvide:\n1. Competitor name\n2. Key product tiers and pricing\n3. Top 3 differentiating features\n4. 3 pros and 3 cons from a sales perspective\n5. A 3-line battle summary to help our sales team position against them.\n\nHTML content:\n{{ $json.data }}\n",
        "batching": {},
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.7
    },
    {
      "id": "396e6b00-1a57-4b60-a5d3-2beee93e882b",
      "name": "Sticky Note12",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3472,
        -816
      ],
      "parameters": {
        "width": 640,
        "height": 560,
        "content": "## Workflow Overview\n**How it Wokrs**\n This workflow checks Zoho CRM every 5 minutes, fetches newly created deals, and extracts competitor information from each deal\u2019s Description field. It then scrapes the competitor website, sends the HTML to Gemini for analysis, and converts the response into a structured \u201cBattle Card\u201d (pricing, features, pros, cons, and a short sales positioning summary). The generated insights are written back into the Zoho deal Description to give your sales team immediate competitive intelligence. Finally, a summary email is sent to the team notifying them that a new Battle Card has been created.\n\n**Setup steps**\n\nAdd Zoho OAuth2 credentials.\n\nAdd Gmail OAuth2 credentials.\n\nAdd Gemini/Palm API credentials.\n\nCreate a Deal in zoho CRM with competitor details added in description+\n\nEnsure deal Description contains a competitor name + valid URL.\n\nEnsure \u201cCreated_Time\u201d is present in Zoho data.\n\nReview the regex extraction logic inside parse competitor info.\n\nTest with a new deal containing a real competitor URL."
      },
      "typeVersion": 1
    },
    {
      "id": "9d0a24f8-0839-43bd-97e5-8755c5f5f997",
      "name": "Sticky Note13",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2752,
        -272
      ],
      "parameters": {
        "color": 7,
        "width": 848,
        "height": 464,
        "content": "## Deal Fetching & Timestamp\nFetches all deals and the last run timestamp, then combines them so the workflow can identify newly created records only."
      },
      "typeVersion": 1
    },
    {
      "id": "d1f23ca0-f8d5-4739-aa09-b1ec98ddf133",
      "name": "Sticky Note14",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1888,
        -272
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 368,
        "content": "## New Deal Filtering\nFilters deals created after the previous run and splits them into individual items for further processing."
      },
      "typeVersion": 1
    },
    {
      "id": "3c792712-aa4d-4bf9-8235-394f6d40938f",
      "name": "Sticky Note15",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1424,
        -272
      ],
      "parameters": {
        "color": 7,
        "width": 256,
        "height": 368,
        "content": "## Eligibility Check\nOnly continues for deals that have description and contain potential competitor reference in that."
      },
      "typeVersion": 1
    },
    {
      "id": "1947b8b5-c522-47ea-b0a4-9dfa09a1fbfa",
      "name": "Sticky Note16",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1152,
        -336
      ],
      "parameters": {
        "color": 7,
        "height": 320,
        "content": "## Competitor Extraction\nOnly continues for deals that have description and contain potential competitor reference in that."
      },
      "typeVersion": 1
    },
    {
      "id": "ef52d62c-fd3b-42d8-a3c1-b0db5fcd0009",
      "name": "Sticky Note17",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -896,
        -336
      ],
      "parameters": {
        "color": 7,
        "height": 320,
        "content": "## Website Scraping\nFetch competitor website for AI analysis"
      },
      "typeVersion": 1
    },
    {
      "id": "700cf57c-334e-4520-a556-4d564fad38f1",
      "name": "Sticky Note18",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -640,
        -320
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 544,
        "content": "## AI battle Card Generation\nAnalyzes the HTML and generates a structured Battle Card (pricing/features/pros/cons/summary)."
      },
      "typeVersion": 1
    },
    {
      "id": "1471f1bd-4563-4d6d-bb73-518b0f8874f7",
      "name": "Sticky Note19",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -64,
        -336
      ],
      "parameters": {
        "color": 7,
        "width": 480,
        "height": 544,
        "content": "## Generated Card sent back in desc and email\nUpdates the original Zoho deal\u2019s Description with the generated cared intelligence.Sends a summary email containing competitor highlights and the battle summary."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "c6e16319-f199-4225-93a8-9d740010fd11",
  "connections": {
    "Merge": {
      "main": [
        [
          {
            "node": "Filter New Deals",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request": {
      "main": [
        [
          {
            "node": "Basic LLM Chain",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get many deals": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Basic LLM Chain": {
      "main": [
        [
          {
            "node": "Share Battle Card in description",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split the deals": {
      "main": [
        [
          {
            "node": "IF Description Present",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter New Deals": {
      "main": [
        [
          {
            "node": "Split the deals",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Cron (every 5 min)": {
      "main": [
        [
          {
            "node": "Get Last Check (Code Node)",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get many deals",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "parse competitor info": {
      "main": [
        [
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF Description Present": {
      "main": [
        [
          {
            "node": "parse competitor info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Basic LLM Chain",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Basic LLM Chain",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Get Last Check (Code Node)": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Share Battle Card in description": {
      "main": [
        [
          {
            "node": "Notify Sales via Gmail",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}