{
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "name": "Gmail to Google Sheets Lead Tracker",
  "tags": [],
  "nodes": [
    {
      "id": "7f3426d1-b085-49c6-a960-c0d4e485db97",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -608,
        48
      ],
      "parameters": {
        "width": 480,
        "height": 768,
        "content": "## Gmail to Google Sheets Lead Tracker\n\n### How it works\n\nThis workflow monitors Gmail for new incoming messages and extracts lead information from each email. It checks the configured Google Sheet for matching existing leads, then only appends the lead when it is not already present. The flow is arranged left to right from email intake, through duplicate validation, to final sheet update.\n\n### Setup steps\n\n- Connect Gmail credentials for the trigger node and configure the mailbox, label, or search criteria that should produce new lead emails.\n- Connect Google Sheets credentials for both sheet nodes.\n- In the extraction code node, update the editable settings and parsing logic to match the lead fields in your email format.\n- Configure the Google Sheet ID, sheet/tab name, and column mappings for reading existing leads and appending new rows.\n\n### Customization\n\nAdjust the duplicate-check code to use the fields that uniquely identify a lead, such as email address, phone number, company, or a combination of values."
      },
      "typeVersion": 1
    },
    {
      "id": "e4e385b2-7fb3-44bf-a098-0a22a1f07059",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -48,
        144
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 320,
        "content": "## Capture and extract lead\n\nStarts when a new Gmail message arrives and runs configurable code to extract lead details from the email content."
      },
      "typeVersion": 1
    },
    {
      "id": "83d7d46d-0aa5-4593-a6f2-7943caeba900",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        480,
        160
      ],
      "parameters": {
        "color": 7,
        "width": 688,
        "height": 304,
        "content": "## Validate against existing leads\n\nReads the current lead tracker from Google Sheets, compares the extracted lead against existing rows, and branches based on whether it is new."
      },
      "typeVersion": 1
    },
    {
      "id": "2bd32099-9f54-4443-86a5-61f7c38747c0",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1216,
        48
      ],
      "parameters": {
        "color": 7,
        "width": 240,
        "height": 336,
        "content": "## Append new lead\n\nAdds the lead to the Google Sheet when the duplicate check determines it is a new lead."
      },
      "typeVersion": 1
    },
    {
      "id": "22222222-2222-4222-8222-222222222201",
      "name": "Gmail Trigger",
      "type": "n8n-nodes-base.gmailTrigger",
      "position": [
        0,
        300
      ],
      "parameters": {
        "simple": true,
        "filters": {
          "q": "label:Leads",
          "readStatus": "unread"
        },
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        }
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "22222222-2222-4222-8222-222222222202",
      "name": "Extract Lead Details",
      "type": "n8n-nodes-base.code",
      "position": [
        260,
        300
      ],
      "parameters": {
        "jsCode": "// ===== EDIT YOUR SETTINGS HERE =====\nconst GOOGLE_SHEET_ID = 'your-google-sheet-id';\nconst SHEET_NAME = 'Leads';\n\nconst email = $input.first().json;\n\nconst fromValue = email.from?.value?.[0] || email.from || {};\nconst senderEmail =\n  typeof fromValue === 'string'\n    ? fromValue.match(/[\\w.+-]+@[\\w.-]+\\.\\w+/)?.[0] || fromValue\n    : fromValue.address || '';\nconst senderName =\n  typeof fromValue === 'string'\n    ? fromValue.replace(senderEmail, '').replace(/[<>\"]/g, '').trim()\n    : fromValue.name || '';\n\nconst subject = email.subject || '';\nconst body = email.textPlain || email.text || email.snippet || '';\nconst messageId = email.id || email.messageId || '';\nconst receivedAt = email.date || new Date().toISOString();\n\nconst phoneMatch = body.match(/(\\+?\\d[\\d\\s\\-().]{7,}\\d)/);\nconst phone = phoneMatch ? phoneMatch[1].trim() : '';\n\nreturn [\n  {\n    json: {\n      googleSheetId: GOOGLE_SHEET_ID,\n      sheetName: SHEET_NAME,\n      email: senderEmail,\n      name: senderName,\n      subject,\n      body: body.slice(0, 500),\n      phone,\n      messageId,\n      receivedAt,\n    },\n  },\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "22222222-2222-4222-8222-222222222203",
      "name": "Read Leads in Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        520,
        300
      ],
      "parameters": {
        "options": {},
        "resource": "sheet",
        "operation": "read",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $json.sheetName }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.googleSheetId }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5,
      "alwaysOutputData": true
    },
    {
      "id": "22222222-2222-4222-8222-222222222204",
      "name": "Verify Unique Lead",
      "type": "n8n-nodes-base.code",
      "position": [
        780,
        300
      ],
      "parameters": {
        "jsCode": "const lead = $('Extract Lead Details').first().json;\nconst rows = $input.all();\n\nconst isDuplicate = rows.some((item) => {\n  const row = item.json;\n  const existingEmail = row.Email || row.email || row['Email Address'] || '';\n  const existingMessageId = row['Message ID'] || row.messageId || row.MessageId || '';\n\n  if (existingMessageId && lead.messageId && existingMessageId === lead.messageId) {\n    return true;\n  }\n\n  return (\n    existingEmail &&\n    lead.email &&\n    String(existingEmail).toLowerCase() === String(lead.email).toLowerCase()\n  );\n});\n\nreturn [\n  {\n    json: {\n      ...lead,\n      isDuplicate,\n    },\n  },\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "22222222-2222-4222-8222-222222222205",
      "name": "Determine New Lead Status",
      "type": "n8n-nodes-base.if",
      "position": [
        1020,
        300
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "is-new-lead-check",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.isDuplicate }}",
              "rightValue": false
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "22222222-2222-4222-8222-222222222206",
      "name": "Add Lead to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1260,
        220
      ],
      "parameters": {
        "columns": {
          "value": {
            "Name": "={{ $json.name }}",
            "Email": "={{ $json.email }}",
            "Phone": "={{ $json.phone }}",
            "Message": "={{ $json.body }}",
            "Subject": "={{ $json.subject }}",
            "Message ID": "={{ $json.messageId }}",
            "Received At": "={{ $json.receivedAt }}"
          },
          "schema": [
            {
              "id": "Email",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Subject",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Subject",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Phone",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Phone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Message",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Message",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Received At",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Received At",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Message ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Message ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": []
        },
        "options": {},
        "resource": "sheet",
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $json.sheetName }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.googleSheetId }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "gmail-leads-v1",
  "connections": {
    "Gmail Trigger": {
      "main": [
        [
          {
            "node": "Extract Lead Details",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verify Unique Lead": {
      "main": [
        [
          {
            "node": "Determine New Lead Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Lead Details": {
      "main": [
        [
          {
            "node": "Read Leads in Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Leads in Sheets": {
      "main": [
        [
          {
            "node": "Verify Unique Lead",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Determine New Lead Status": {
      "main": [
        [
          {
            "node": "Add Lead to Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}