> GSheets CRM
上級
これはCRM, Multimodal AI分野の自動化ワークフローで、24個のノードを含みます。主にIf, Set, Code, Gmail, Webhookなどのノードを使用。 Google スプレッドシートメール通知と時間追跡を使った自動 prospective客から顧客へのパイプライン
前提条件
- •Googleアカウント + Gmail API認証情報
- •HTTP Webhookエンドポイント(n8nが自動生成)
- •Google Sheets API認証情報
ワークフロープレビュー
ノード接続関係を可視化、ズームとパンをサポート
ワークフローをエクスポート
以下のJSON設定をn8nにインポートして、このワークフローを使用できます
{
"id": "sbTxG7FVDyFq0sLR",
"meta": {
"instanceId": "{{INSTANCE_ID}}",
"templateCredsSetupCompleted": true
},
"name": "GSheets CRM",
"tags": [],
"nodes": [
{
"id": "c0760f3c-0feb-43bb-9b52-cc9307e0b98f",
"name": "Webhook: リードステージ変更",
"type": "n8n-nodes-base.webhook",
"notes": "Receives JSON when a lead's Stage (Leads!E) changes.\nExpected body keys:\n- name (Leads!A)\n- email (Leads!C)\n- source_id (for mapping 1=Instagram,2=Facebook) OR source_text\n- stage (new stage text)\n- previous_stage (optional)",
"position": [
-896,
-80
],
"webhookId": "{{WEBHOOK_ID_LEAD_STAGE_CHANGED}}",
"parameters": {
"path": "lead-stage-changed",
"options": {
"responseData": "OK"
},
"httpMethod": "POST"
},
"typeVersion": 1
},
{
"id": "a91971ec-9414-4d0d-98d9-273761071c30",
"name": "メールフィールド準備",
"type": "n8n-nodes-base.set",
"notes": "Derives firstName and sourcePlatform for the email body.",
"position": [
-672,
-80
],
"parameters": {
"fields": {
"values": [
{
"name": "firstName",
"stringValue": "=={{ $json.body.name ? $json.body.name.trim().split(' ')[0] : 'there' }}"
},
{
"name": "sourcePlatform ",
"stringValue": "={{ $json.body.source_text || 'Unknown' }}"
},
{
"name": "stage",
"stringValue": "={{ $json.body.stage }}"
},
{
"name": "previousStage",
"stringValue": "={{ $json.body.previous_stage || '' }}"
}
]
},
"options": {
"includeBinary": false
}
},
"typeVersion": 3
},
{
"id": "00ef748d-22e8-4436-a0e7-7ef1ed9017fe",
"name": "Gmail: ステージ変更メール送信",
"type": "n8n-nodes-base.gmail",
"notes": "Sends the templated email on any Stage change.",
"position": [
-224,
-176
],
"webhookId": "{{GMAIL_NODE_WEBHOOK_ID_STAGE_CHANGE}}",
"parameters": {
"sendTo": "={{ $('Prepare Email Fields').item.json.body.email }}",
"message": "=Hi {{ $('Prepare Email Fields').item.json.body.name }},<br><br>Thanks for the call earlier & happy I was able to meet you. Just letting you know that I'll work on a proposal immediately and have something over to you in the next 2-3 hours.<br><br>Stay tuned & let me know if you have any questions.<br><br>Thanks,<br>{{SENDER_NAME}}",
"options": {},
"subject": "Next Steps"
},
"credentials": {
"gmailOAuth2": {
"id": "{{GMAIL_CREDENTIAL_ID}}",
"name": "{{GMAIL_CREDENTIAL_NAME}}"
}
},
"typeVersion": 2
},
{
"id": "baa49e6a-3c2e-4c42-ae96-9b2f0e5a0db3",
"name": "IF: ステージ == 受注",
"type": "n8n-nodes-base.if",
"notes": "Branch for when the lead has been marked Won.",
"position": [
-224,
16
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "5feb2d51-b3ba-4b5e-9064-4735e10d5a38",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.stage }}",
"rightValue": "Won"
}
]
}
},
"typeVersion": 2
},
{
"id": "855b796a-8588-4f43-8b39-48406c37c67d",
"name": "開始タイムスタンプ整形",
"type": "n8n-nodes-base.dateTime",
"notes": "Produces Start Date & Time as: dd/mm/yyyy at HH:MM",
"position": [
0,
16
],
"parameters": {
"value": "={{ $now }}",
"custom": true,
"options": {},
"toFormat": "DD/MM/YYYY 'at' HH:mm"
},
"typeVersion": 1
},
{
"id": "25f0b4f3-0305-4ce6-83f8-e37fc90d51ca",
"name": "GS: 顧客追加(受注時)",
"type": "n8n-nodes-base.googleSheets",
"notes": "Appends the new client with Project Status=In Progress and Start Date & Time.",
"position": [
224,
16
],
"parameters": {
"columns": {
"value": {
"Name": "={{ $json.body.name }}",
"Client Email": "={{ $json.body.email }}",
"Start Date & Time": "={{ $json.data }}"
},
"schema": [
{
"id": "Name",
"type": "string",
"display": true,
"required": false,
"displayName": "Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Client Type",
"type": "string",
"display": true,
"required": false,
"displayName": "Client Type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Client Email",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Client Email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Project Status",
"type": "string",
"display": true,
"required": false,
"displayName": "Project Status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Tenure",
"type": "string",
"display": true,
"required": false,
"displayName": "Tenure",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Start Date & Time",
"type": "string",
"display": true,
"required": false,
"displayName": "Start Date & Time",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "End Date & Time",
"type": "string",
"display": true,
"required": false,
"displayName": "End Date & Time",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Time to Deliver",
"type": "string",
"display": true,
"required": false,
"displayName": "Time to Deliver",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {
"useAppend": true,
"cellFormat": "USER_ENTERED"
},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "{{CLIENTS_GID}}",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/{{GOOGLE_SHEETS_DOC_ID}}/edit#gid={{CLIENTS_GID}}",
"cachedResultName": "Clients"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "{{GOOGLE_SHEETS_DOC_ID}}",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/{{GOOGLE_SHEETS_DOC_ID}}/edit",
"cachedResultName": "{{SHEET_NAME}}"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "{{GSHEETS_CREDENTIAL_ID}}",
"name": "{{GSHEETS_CREDENTIAL_NAME}}"
}
},
"typeVersion": 4
},
{
"id": "100c9018-23b7-4724-93ef-373566ae9c42",
"name": "Webhook: リードは適格?",
"type": "n8n-nodes-base.webhook",
"notes": "Receives JSON when Leads!H (Qualified?) is checked.\nExpected body keys:\n- name (A)\n- email (C)\n- qualified (boolean or 'TRUE'/1)",
"position": [
-896,
-624
],
"webhookId": "{{WEBHOOK_ID_LEAD_QUALIFIED}}",
"parameters": {
"path": "lead-qualified",
"options": {
"responseData": "OK"
},
"httpMethod": "POST"
},
"typeVersion": 1
},
{
"id": "e5fe57ce-c457-4f03-9c96-7ac385b2a42f",
"name": "IF: 適格である",
"type": "n8n-nodes-base.if",
"position": [
-672,
-624
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "285b4bc9-5a4b-4f6b-bd55-eb54d6a6fcc1",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.body.qualified }}",
"rightValue": "=\"true\""
}
]
}
},
"typeVersion": 2
},
{
"id": "04851d87-b2c6-4383-9687-382f3bee1e7b",
"name": "Gmail: Cal.com招待状送信",
"type": "n8n-nodes-base.gmail",
"notes": "Sends the booking link when Qualified? is checked.",
"position": [
-448,
-624
],
"webhookId": "{{GMAIL_NODE_WEBHOOK_ID_CAL_INVITE}}",
"parameters": {
"sendTo": "={{ $json.body.email }}",
"message": "=Hi {{$json.body.name ? $json.body.name.split(' ')[0] : 'there'}},<br><br>Congrats — you’re qualified and we are super excited to know more from you! Please book your discovery call here: <a href=\"{{CAL_COM_BOOKING_URL}}\" target=\"_blank\">Schedule on Cal.com</a>.<br><br>Thanks,<br>{{SENDER_NAME}}",
"options": {},
"subject": "Book Your Discovery Call"
},
"credentials": {
"gmailOAuth2": {
"id": "{{GMAIL_CREDENTIAL_ID}}",
"name": "{{GMAIL_CREDENTIAL_NAME}}"
}
},
"typeVersion": 2
},
{
"id": "99f6f896-ac20-454b-a480-88a71aabe0b0",
"name": "GS: リードステージを「面談予約済」に更新",
"type": "n8n-nodes-base.googleSheets",
"notes": "Uses Email (Column C) as key to update Stage (E) to 'Meeting Booked'.",
"position": [
-672,
-368
],
"parameters": {
"columns": {
"value": {
"Stage": "Meeting Booked",
"Client Email": "={{ $json.body.payload.attendees[0].email }}"
},
"schema": [
{
"id": "Name",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Date Updated",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Date Updated",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Client Email",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Client Email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Lead Source",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Lead Source",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Stage",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Stage",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Asignee",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Asignee",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Discovery Call URL",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Discovery Call URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Qualitfied?",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Qualitfied?",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "row_number",
"type": "number",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "row_number",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"Client Email"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {
"cellFormat": "USER_ENTERED"
},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid={{LEADS_GID}}",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/{{GOOGLE_SHEETS_DOC_ID}}/edit#gid={{LEADS_GID}}",
"cachedResultName": "Leads"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "{{GOOGLE_SHEETS_DOC_ID}}",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/{{GOOGLE_SHEETS_DOC_ID}}/edit",
"cachedResultName": "{{SHEET_NAME}}"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "{{GSHEETS_CREDENTIAL_ID}}",
"name": "{{GSHEETS_CREDENTIAL_NAME}}"
}
},
"typeVersion": 4
},
{
"id": "b2acf148-b6bc-49d3-8e76-fe890459c1dc",
"name": "Webhook: 顧客ステータス変更",
"type": "n8n-nodes-base.webhook",
"notes": "Receives JSON when Clients!D (Project Status) changes.\nExpected body keys:\n- email (Clients!C)\n- project_status (Clients!D new value)",
"position": [
-880,
304
],
"webhookId": "{{WEBHOOK_ID_CLIENT_STATUS_CHANGED}}",
"parameters": {
"path": "client-status-changed",
"options": {
"responseData": "OK"
},
"httpMethod": "POST"
},
"typeVersion": 1
},
{
"id": "01223e18-22c3-4622-ba66-0425aad4bcd6",
"name": "IF: 納品済み?",
"type": "n8n-nodes-base.if",
"position": [
-656,
304
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "8be5b372-0114-4595-ab9a-d7903d63a716",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.body.project_status }}",
"rightValue": "Delivered"
}
]
}
},
"typeVersion": 2
},
{
"id": "438ffb35-490f-49d1-9031-c32447b59992",
"name": "GS: 顧客をメールで検索",
"type": "n8n-nodes-base.googleSheets",
"notes": "Fetches the row to read Start Date & Time (F) for duration calc.",
"position": [
-432,
304
],
"parameters": {
"options": {},
"filtersUI": {
"values": [
{
"lookupValue": "={{ $json.body.email }}",
"lookupColumn": "Client Email"
}
]
},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "{{CLIENTS_GID}}",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/{{GOOGLE_SHEETS_DOC_ID}}/edit#gid={{CLIENTS_GID}}",
"cachedResultName": "Clients"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "{{GOOGLE_SHEETS_DOC_ID}}",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/{{GOOGLE_SHEETS_DOC_ID}}/edit",
"cachedResultName": "{{SHEET_NAME}}"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "{{GSHEETS_CREDENTIAL_ID}}",
"name": "{{GSHEETS_CREDENTIAL_NAME}}"
}
},
"typeVersion": 4
},
{
"id": "1579d825-5a67-4e52-b7d5-f4dc493cf790",
"name": "終了タイムスタンプ整形",
"type": "n8n-nodes-base.dateTime",
"notes": "End Date & Time formatted as dd/mm/yyyy at HH:MM",
"position": [
-208,
304
],
"parameters": {
"value": "={{ $now }}",
"custom": true,
"options": {},
"toFormat": "DD/MM/YYYY 'at' HH:mm"
},
"typeVersion": 1
},
{
"id": "1aec66f5-ce82-4375-9202-a3ba2a5ad118",
"name": "GS: 顧客の終了時間と期間を更新",
"type": "n8n-nodes-base.googleSheets",
"notes": "Sets End Date & Time (G) and Time To Deliver (H).",
"position": [
240,
304
],
"parameters": {
"columns": {
"value": {
"Client Email": "={{ $json[\"Client Email\"] }}",
"End Date & Time": "={{ $json.endStr }}",
"Time to Deliver": "={{ $json.duration }}"
},
"schema": [
{
"id": "Name",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Client Type",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Client Type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Client Email",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Client Email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Project Status",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Project Status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Tenure",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Tenure",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Start Date & Time",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "Start Date & Time",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "End Date & Time",
"type": "string",
"display": true,
"required": false,
"displayName": "End Date & Time",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Time to Deliver",
"type": "string",
"display": true,
"required": false,
"displayName": "Time to Deliver",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "row_number",
"type": "number",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "row_number",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"Client Email"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {
"cellFormat": "USER_ENTERED"
},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "{{CLIENTS_GID}}",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/{{GOOGLE_SHEETS_DOC_ID}}/edit#gid={{CLIENTS_GID}}",
"cachedResultName": "Clients"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "{{GOOGLE_SHEETS_DOC_ID}}",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/{{GOOGLE_SHEETS_DOC_ID}}/edit",
"cachedResultName": "{{SHEET_NAME}}"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "{{GSHEETS_CREDENTIAL_ID}}",
"name": "{{GSHEETS_CREDENTIAL_NAME}}"
}
},
"typeVersion": 4
},
{
"id": "1f2a3e16-70c7-402f-ace7-782f9de34fd3",
"name": "コード",
"type": "n8n-nodes-base.code",
"position": [
16,
304
],
"parameters": {
"jsCode": "// Compute delivery duration from \"Start Date & Time\" (F) and formatted \"End\" from previous node\n// Expects this node to run AFTER \"Format End Timestamp\" and AFTER the Clients row lookup\n\nconst items = $input.all();\n\n// Helper: parse \"dd/mm/yyyy at HH:MM\"\nfunction parseDT(s) {\n if (!s) return null;\n const m = String(s).match(/(\\d{2})\\/(\\d{2})\\/(\\d{4}).*?(\\d{2}):(\\d{2})/);\n if (!m) return null;\n const [, d, M, y, h, min] = m;\n return new Date(Number(y), Number(M) - 1, Number(d), Number(h), Number(min), 0);\n}\n\n// Get the formatted end timestamp from the Date & Time node\nconst endStrFromNode = $node[\"Format End Timestamp\"]?.json?.data || \"\";\n\nfor (const item of items) {\n const row = item.json || {};\n\n // Try several keys for Start column F (depending on how Google Sheets node labeled it)\n const startStr =\n row[\"Start Date & Time\"] ??\n row[\"F\"] ??\n row[\"Start\"] ??\n \"\";\n\n // Prefer the value from Date & Time node; fall back to any end value already present\n const endStr = endStrFromNode || row[\"End Date & Time\"] || \"\";\n\n const start = parseDT(startStr);\n const end = parseDT(endStr);\n\n let duration = \"N/A\";\n if (start && end) {\n const ms = end - start;\n const days = Math.floor(ms / 86_400_000);\n const hrs = Math.floor((ms % 86_400_000) / 3_600_000);\n const mins = Math.floor((ms % 3_600_000) / 60_000);\n duration = `${days}d ${hrs}h ${mins}m`;\n }\n\n // Attach results to the item\n item.json.endStr = endStr;\n item.json.duration = duration;\n}\n\nreturn items;\n"
},
"typeVersion": 2
},
{
"id": "12c036dc-4e13-4bfd-95d2-48da0e8337b6",
"name": "If",
"type": "n8n-nodes-base.if",
"position": [
-448,
-80
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "37fbb2ef-5861-4fc8-ab06-71fe4364be63",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.stage }}",
"rightValue": "Awaiting Proposal"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "ec815439-bfb1-4edb-8a70-9db1c167a868",
"name": "Webhook: 面談予約済",
"type": "n8n-nodes-base.webhook",
"position": [
-896,
-368
],
"webhookId": "{{WEBHOOK_ID_MEETING_BOOKED}}",
"parameters": {
"path": "cal-booked",
"options": {},
"httpMethod": "POST"
},
"typeVersion": 2.1
},
{
"id": "26784981-b9f6-44ca-8329-62072dd4fd0f",
"name": "付箋",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1232,
-848
],
"parameters": {
"width": 1968,
"height": 1408,
"content": "# Google Sheets Automated CRM"
},
"typeVersion": 1
},
{
"id": "815c2626-dd90-4976-92d7-ce93bad40e1e",
"name": "付箋1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2080,
-848
],
"parameters": {
"color": 6,
"width": 816,
"height": 4128,
"content": "# The App Script Needed (Use this for your Google Worksheet App Script)\n\n/**\n * ScaleFlow CRM — Google Apps Script bridge to n8n\n * Spreadsheet: \"ScaleFlow CRM\"\n * Tabs: \"Leads\", \"Clients\"\n *\n * WHAT IT DOES\n * - When a Lead’s Stage (Leads!E) changes → POST to n8n /lead-stage-changed\n * - When Qualified? checkbox (Leads!H) is edited → POST to n8n /lead-qualified\n * - When a Client’s Project Status (Clients!D) changes → POST to n8n /client-status-changed\n *\n * STEPS\n * 1) Paste this into Extensions → Apps Script.\n * 2) Replace the WEBHOOK URLs below with your n8n endpoints.\n * 3) Save. First edit will prompt for authorization. (Optional) Run createInstallableTrigger() once.\n */\n\nconst WEBHOOKS = {\n STAGE_CHANGED: 'https://{{YOUR_N8N_DOMAIN}}/webhook/lead-stage-changed',\n LEAD_QUALIFIED: 'https://{{YOUR_N8N_DOMAIN}}/webhook/lead-qualified',\n CLIENT_STATUS_CHANGED: 'https://{{YOUR_N8N_DOMAIN}}/webhook/client-status-changed',\n};\n\nconst TABS = {\n LEADS: 'Leads',\n CLIENTS: 'Clients',\n};\n\n// Column indexes (1-based)\nconst COL = {\n NAME: 1, // Leads!A\n CLIENT_TYPE: 2, // Clients!B\n EMAIL: 3, // Leads/Clients!C\n LEAD_SOURCE: 4, // Leads!D\n LEAD_STAGE: 5, // Leads!E\n LEAD_ASSIGNEE: 6, // Leads!F\n PROJECT_STATUS: 4,// Clients!D\n QUALIFIED: 8, // Leads!H (checkbox)\n};\n\n/**\n * MAIN: fires on any cell edit\n */\nfunction onEdit(e) {\n try {\n if (!e || !e.range) return;\n // Only process single-cell edits\n if (e.range.getNumRows() !== 1 || e.range.getNumColumns() !== 1) return;\n\n const sheet = e.range.getSheet();\n const tabName = sheet.getName();\n const row = e.range.getRow();\n const col = e.range.getColumn();\n\n // Skip header row\n if (row === 1) return;\n\n if (tabName === TABS.LEADS) {\n handleLeadsEdit_(sheet, row, col, e);\n } else if (tabName === TABS.CLIENTS) {\n handleClientsEdit_(sheet, row, col, e);\n }\n } catch (err) {\n console.error('onEdit error:', err);\n }\n}\n\n/**\n * Handle edits on Leads tab\n */\nfunction handleLeadsEdit_(sheet, row, col, e) {\n // Read row A..H (adjust width if you have more columns)\n const values = sheet.getRange(row, 1, 1, 8).getValues()[0];\n const name = asString_(values[COL.NAME - 1]);\n const email = asString_(values[COL.EMAIL - 1]);\n const sourceText = asString_(values[COL.LEAD_SOURCE - 1]);\n const stageText = asString_(values[COL.LEAD_STAGE - 1]);\n const qualifiedVal = values[COL.QUALIFIED - 1];\n\n // 1) Stage changed (Leads!E)\n if (col === COL.LEAD_STAGE) {\n const payload = {\n name,\n email,\n source_text: sourceText || '',\n stage: stageText || '',\n previous_stage: e.oldValue || '',\n row: row,\n tab: TABS.LEADS,\n };\n postJson_(WEBHOOKS.STAGE_CHANGED, payload);\n }\n\n // 2) Qualified? checkbox edited (Leads!H)\n if (col === COL.QUALIFIED) {\n const payload = {\n name,\n email,\n qualified: isChecked_(qualifiedVal),\n row: row,\n tab: TABS.LEADS,\n };\n postJson_(WEBHOOKS.LEAD_QUALIFIED, payload);\n }\n}\n\n/**\n * Handle edits on Clients tab\n */\nfunction handleClientsEdit_(sheet, row, col, e) {\n // Read row A..H (adjust width if you have more columns)\n const values = sheet.getRange(row, 1, 1, 8).getValues()[0];\n const email = asString_(values[COL.EMAIL - 1]);\n const projectStatus = asString_(values[COL.PROJECT_STATUS - 1]);\n\n // 3) Project Status changed (Clients!D)\n if (col === COL.PROJECT_STATUS) {\n const payload = {\n email,\n project_status: projectStatus || '',\n previous_status: e.oldValue || '',\n row: row,\n tab: TABS.CLIENTS,\n };\n postJson_(WEBHOOKS.CLIENT_STATUS_CHANGED, payload);\n }\n}\n\n/**\n * POST JSON helper\n */\nfunction postJson_(url, obj) {\n if (!url || url.indexOf('{{YOUR_N8N_DOMAIN}}') !== -1) {\n console.warn('Webhook URL not set. Skipping POST:', url, obj);\n return;\n }\n try {\n const res = UrlFetchApp.fetch(url, {\n method: 'post',\n contentType: 'application/json',\n payload: JSON.stringify(obj),\n muteHttpExceptions: true,\n });\n // Optional: log for debugging\n console.log('POST', url, res.getResponseCode(), safeTrunc_(res.getContentText(), 500));\n } catch (err) {\n console.error('postJson_ error:', url, err && err.message);\n }\n}\n\n/**\n * UTILITIES\n */\nfunction isChecked_(val) {\n // Accepts true/false, \"TRUE\"/\"FALSE\", 1/0\n if (val === true) return true;\n if (val === false) return false;\n const s = String(val).trim().toUpperCase();\n return s === 'TRUE' || s === '1' || s === 'CHECKED' || s === 'YES';\n}\n\nfunction asString_(v) {\n return v == null ? '' : String(v);\n}\n\nfunction safeTrunc_(s, n) {\n if (!s) return '';\n return s.length > n ? s.slice(0, n) + '…' : s;\n}\n\n/**\n * OPTIONAL: create an installable onEdit trigger (runs with full auth scope)\n * Run this once if you want to avoid simple-trigger limitations.\n */\nfunction createInstallableTrigger() {\n const ss = SpreadsheetApp.getActive();\n // Clear existing triggers for safety\n ScriptApp.getProjectTriggers().forEach(t => {\n if (t.getHandlerFunction && t.getHandlerFunction() === 'onEdit') {\n ScriptApp.deleteTrigger(t);\n }\n });\n ScriptApp.newTrigger('onEdit').forSpreadsheet(ss).onEdit().create();\n}\n\n/**\n * OPTIONAL: quick test (does not fire onEdit)\n * Replace payloads and run from editor to verify webhooks.\n */\nfunction testPing_() {\n postJson_(WEBHOOKS.STAGE_CHANGED, {\n name: 'Test User',\n email: 'test@example.com',\n source_text: 'Instagram',\n stage: 'Proposal',\n previous_stage: 'Screening',\n row: 2,\n tab: TABS.LEADS,\n });\n\n postJson_(WEBHOOKS.LEAD_QUALIFIED, {\n name: 'Test User',\n email: 'test@example.com',\n qualified: true,\n row: 2,\n tab: TABS.LEADS,\n });\n\n postJson_(WEBHOOKS.CLIENT_STATUS_CHANGED, {\n email: 'client@example.com',\n project_status: 'Delivered',\n previous_status: 'In Progress',\n row: 3,\n tab: TABS.CLIENTS,\n });\n}\n"
},
"typeVersion": 1
},
{
"id": "7b60fbcd-c39a-4313-967a-e7b8310286c1",
"name": "付箋2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-944,
-688
],
"parameters": {
"color": 4,
"width": 848,
"height": 240,
"content": "# Lead Qualification"
},
"typeVersion": 1
},
{
"id": "bff994fa-80d2-4ccd-8964-72fc8a694cc3",
"name": "付箋3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-944,
-448
],
"parameters": {
"color": 4,
"width": 848,
"height": 256,
"content": "# Changing Stage to Meeting Booked\n"
},
"typeVersion": 1
},
{
"id": "ea32e27d-3fc6-4bed-a61d-57ec7aa24fc0",
"name": "付箋4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-944,
-192
],
"parameters": {
"color": 4,
"width": 1440,
"height": 384,
"content": "# Proposal Follow-Up / Client Won Flow\n"
},
"typeVersion": 1
},
{
"id": "5eb61a5b-b07c-42a7-9ff4-d178985e04b2",
"name": "付箋5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-944,
192
],
"parameters": {
"color": 4,
"width": 1440,
"height": 304,
"content": "# Project Fulfillment Duration\n"
},
"typeVersion": 1
}
],
"active": true,
"pinData": {},
"settings": {
"callerPolicy": "workflowsFromSameOwner",
"errorWorkflow": "{{ERROR_WORKFLOW_ID}}",
"executionOrder": "v1"
},
"versionId": "fbf5f5f3-e31e-4f4d-a480-f8c382bdfe04",
"connections": {
"12c036dc-4e13-4bfd-95d2-48da0e8337b6": {
"main": [
[
{
"node": "00ef748d-22e8-4436-a0e7-7ef1ed9017fe",
"type": "main",
"index": 0
}
],
[
{
"node": "baa49e6a-3c2e-4c42-ae96-9b2f0e5a0db3",
"type": "main",
"index": 0
}
]
]
},
"1f2a3e16-70c7-402f-ace7-782f9de34fd3": {
"main": [
[
{
"node": "1aec66f5-ce82-4375-9202-a3ba2a5ad118",
"type": "main",
"index": 0
}
]
]
},
"01223e18-22c3-4622-ba66-0425aad4bcd6": {
"main": [
[
{
"node": "438ffb35-490f-49d1-9031-c32447b59992",
"type": "main",
"index": 0
}
]
]
},
"e5fe57ce-c457-4f03-9c96-7ac385b2a42f": {
"main": [
[
{
"node": "04851d87-b2c6-4383-9687-382f3bee1e7b",
"type": "main",
"index": 0
}
]
]
},
"baa49e6a-3c2e-4c42-ae96-9b2f0e5a0db3": {
"main": [
[
{
"node": "855b796a-8588-4f43-8b39-48406c37c67d",
"type": "main",
"index": 0
}
],
[]
]
},
"1579d825-5a67-4e52-b7d5-f4dc493cf790": {
"main": [
[
{
"node": "1f2a3e16-70c7-402f-ace7-782f9de34fd3",
"type": "main",
"index": 0
}
]
]
},
"a91971ec-9414-4d0d-98d9-273761071c30": {
"main": [
[
{
"node": "12c036dc-4e13-4bfd-95d2-48da0e8337b6",
"type": "main",
"index": 0
}
]
]
},
"855b796a-8588-4f43-8b39-48406c37c67d": {
"main": [
[
{
"node": "25f0b4f3-0305-4ce6-83f8-e37fc90d51ca",
"type": "main",
"index": 0
}
]
]
},
"ec815439-bfb1-4edb-8a70-9db1c167a868": {
"main": [
[
{
"node": "99f6f896-ac20-454b-a480-88a71aabe0b0",
"type": "main",
"index": 0
}
]
]
},
"100c9018-23b7-4724-93ef-373566ae9c42": {
"main": [
[
{
"node": "e5fe57ce-c457-4f03-9c96-7ac385b2a42f",
"type": "main",
"index": 0
}
]
]
},
"438ffb35-490f-49d1-9031-c32447b59992": {
"main": [
[
{
"node": "1579d825-5a67-4e52-b7d5-f4dc493cf790",
"type": "main",
"index": 0
}
]
]
},
"c0760f3c-0feb-43bb-9b52-cc9307e0b98f": {
"main": [
[
{
"node": "a91971ec-9414-4d0d-98d9-273761071c30",
"type": "main",
"index": 0
}
]
]
},
"b2acf148-b6bc-49d3-8e76-fe890459c1dc": {
"main": [
[
{
"node": "01223e18-22c3-4622-ba66-0425aad4bcd6",
"type": "main",
"index": 0
}
]
]
}
}
}よくある質問
このワークフローの使い方は?
上記のJSON設定コードをコピーし、n8nインスタンスで新しいワークフローを作成して「JSONからインポート」を選択、設定を貼り付けて認証情報を必要に応じて変更してください。
このワークフローはどんな場面に適していますか?
上級 - 顧客管理, マルチモーダルAI
有料ですか?
このワークフローは完全無料です。ただし、ワークフローで使用するサードパーティサービス(OpenAI APIなど)は別途料金が発生する場合があります。
関連ワークフロー
競合他社コンテンツギャップ分析ツール:構題マッピングの自動化
Gemini AI、Apify、Google Sheetsを使用して競合企業のコンテンツギャップを分析
If
Set
Code
+
If
Set
Code
30 ノードMychel Garzon
その他
複数の採用サイトからの求人情報の自動化
5 つの求人プラットフォームと AI リジュームジェネレーターを使った就職・応募の自動化
If
Set
Code
+
If
Set
Code
34 ノードGerald Denor
個人の生産性
09 - リードプロフィール強化ツール
自動化されたリード情報の豊富さとパーソナライズされたアウトレーシュ:HubSpot、Phantombuster、GPT
If
Set
Code
+
If
Set
Code
30 ノードAvkash Kakdiya
リードナーチャリング
GRC - セキュリティアンケートの自動回答
自動化したセキュリティアンケートの回答:GPT-4oとGoogle Sheets
If
Set
Code
+
If
Set
Code
11 ノードAdnan Tariq
セキュリティ運用
リード獲得の自動化、AI資格検証、そして ElevenLabs による個別化された音声フォローアップ
OpenAI および ElevenLabs を基にした自動化されたリードキャプチャと AI による個別化音声フォローアップ
If
Set
Code
+
If
Set
Code
22 ノードMarth
リードナーチャリング
詐欺防止型リードキャプチャ・育成千リードシステム
AIによるスコアリング、テーブル追跡、マルチチャネルアラートを使って詐欺対策リードをキャプチャーし育成
If
Set
Code
+
If
Set
Code
28 ノードJitesh Dugar
コンテンツ作成
ワークフロー情報
難易度
上級
ノード数24
カテゴリー2
ノードタイプ8
作成者
Ziad Adel
@ziadadelAI Automation Growth Partner with 5 years of experience in the tech and hyper growing startups industry
外部リンク
n8n.ioで表示 →
このワークフローを共有