This workflow corresponds to n8n.io template #17659 — we link there as the canonical source.
This workflow follows the Gmail → Google Docs 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 →
{
"id": "xLuOFju6NA8w8Yxh",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "AI Seller Lead Qualifier and CMA-Lite Report Generator",
"tags": [],
"nodes": [
{
"id": "c897d114-bf9e-423a-9140-21b5440a27c4",
"name": "Webhook: Seller Valuation Request",
"type": "n8n-nodes-base.webhook",
"position": [
-896,
-128
],
"parameters": {
"path": "646c05c5-10d2-40ca-a49e-e30a8761c407",
"options": {},
"httpMethod": "POST"
},
"typeVersion": 2.1
},
{
"id": "1fe67534-8c9f-4c6d-9ee1-0611eb61574a",
"name": "Typeform: Seller Valuation Request",
"type": "n8n-nodes-base.typeformTrigger",
"disabled": true,
"position": [
-896,
96
],
"parameters": {
"formId": "ELCfX43n",
"onlyAnswers": false,
"simplifyAnswers": false
},
"credentials": {
"typeformApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.1
},
{
"id": "b331d6a0-4b00-4194-a803-f2a63c869536",
"name": "Extract & Normalize Property Details",
"type": "n8n-nodes-base.code",
"position": [
-464,
-16
],
"parameters": {
"jsCode": "const input = $input.first().json;\n\nlet fields = {};\nlet recordId = '';\n\n// Check all possible payload locations\nconst formResponse = input.form_response // raw webhook format\n || input // Typeform trigger format (already unwrapped)\n || {};\n\nconst answers = formResponse.answers\n || input.answers\n || [];\n\nconst token = formResponse.token\n || input.token\n || `submission-${Date.now()}`;\n\nrecordId = token;\n\nif (answers.length > 0) {\n // ============================================================\n // TYPEFORM FIELD REF MAP\n // These refs are specific to the Seller Valuation Request form\n // created during template setup. If you create your own Typeform,\n // fire one test submission, inspect the answers[].field.ref\n // values in n8n's execution panel, and update this map to match.\n // ============================================================\n const refMap = {\n 'c57114eb-e074-4bd8-8a47-587e5f85906b': 'sellerName',\n '272a6dd8-b438-41d3-9fdf-e2abb0e29d03': 'sellerEmail',\n '1726ff1b-c2da-499f-ae99-4a777663e2fc': 'sellerPhone',\n '0f1d33ef-9e31-414a-b453-65dba4539d75': 'propertyAddress',\n 'e3fa5552-c98d-46a0-8882-63a2750307c6': 'propertyType',\n '5caf6ac4-06d3-4cff-b012-937f9884c9a5': 'bedrooms',\n '5c225bb8-5a0c-4a59-98f8-34568aa28735': 'condition',\n 'fd7c0b82-15fd-45d7-a275-a901e3fd39bf': 'timeline',\n '01c7b64b-d0af-4882-97fb-17fb18d4ad9e': 'reasonForSelling',\n 'b10c926e-cd63-4ce4-a8c0-b30b39ad286e': 'expectedPrice'\n };\n\n for (const answer of answers) {\n const ref = answer.field?.ref || '';\n const type = answer.type || '';\n\n let value = null;\n if (type === 'text') value = answer.text;\n else if (type === 'email') value = answer.email;\n else if (type === 'phone_number') value = answer.phone_number;\n else if (type === 'choice') value = answer.choice?.label;\n else if (type === 'number') value = String(answer.number);\n else if (type === 'long_text') value = answer.text;\n\n const fieldName = refMap[ref];\n if (fieldName && value !== null) {\n fields[fieldName] = value;\n }\n }\n\n} else {\n // Flat webhook JSON format\n const body = input.body || input;\n recordId = body.id || body.recordId || `webhook-${Date.now()}`;\n\n fields = {\n sellerName: body.sellerName || body.name || null,\n sellerEmail: body.sellerEmail || body.email || null,\n sellerPhone: body.sellerPhone || body.phone || null,\n propertyAddress: body.propertyAddress || body.address || null,\n propertyType: body.propertyType || body.type || null,\n bedrooms: body.bedrooms || body.beds || null,\n bathrooms: body.bathrooms || body.baths || null,\n condition: body.condition || null,\n timeline: body.timeline || null,\n reasonForSelling: body.reasonForSelling || body.reason || null,\n expectedPrice: body.expectedPrice || body.price || null\n };\n}\n\nreturn [{\n json: {\n sellerName: fields.sellerName || null,\n sellerEmail: fields.sellerEmail || null,\n sellerPhone: fields.sellerPhone || null,\n propertyAddress: fields.propertyAddress || null,\n propertyType: fields.propertyType || null,\n bedrooms: fields.bedrooms || null,\n bathrooms: fields.bathrooms || null,\n condition: fields.condition || null,\n timeline: fields.timeline || null,\n reasonForSelling: fields.reasonForSelling || null,\n expectedPrice: fields.expectedPrice || null,\n recordId,\n timestamp: new Date().toISOString()\n }\n}];"
},
"typeVersion": 2
},
{
"id": "b2048a6e-621d-454a-ab0a-b82e003e8478",
"name": "Generate CMA-Lite Report",
"type": "@n8n/n8n-nodes-langchain.googleGemini",
"position": [
-256,
-16
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "list",
"value": "models/gemini-3-flash-preview"
},
"options": {
"systemMessage": "You are a professional real estate valuation assistant with deep market knowledge. A homeowner has requested a property valuation. Generate a professional CMA-lite report and qualify the seller's readiness.\n\nREPORT SECTIONS \u2014 generate content for each:\n\n1. Executive Summary: 2-3 sentences summarizing the estimated value and key factors affecting it.\n\n2. Estimated Value Range: Provide a realistic price range based on the property details provided. Use the seller's expected price as a reference point but give an independent assessment. Format as \"$XXX,000 \u2014 $XXX,000\".\n\n3. Key Value Factors: Exactly 3 bullet point factors that most influence this property's value \u2014 be specific to the property details provided.\n\n4. Market Context: 2-3 sentences about current market conditions for this property type and location.\n\n5. Pricing Strategy: 2-3 sentences recommending a listing approach based on the seller's timeline and property condition.\n\n6. Recommended Next Steps: Exactly 3 actionable steps guiding the seller toward a listing consultation.\n\nSELLER SCORING \u2014 apply these rules strictly:\n- Hot: MUST meet at least one of these criteria:\n * Timeline is \"Immediately\" or \"1-3 months\"\n * Reason is \"Relocating\" or involves financial pressure\n * Seller used urgent language in any field\n Score as Hot even if condition is Fair or price expectation seems off.\n- Warm: Timeline is \"3-6 months\" OR reason is Upsizing/Downsizing with no urgency signals\n- Cold: Timeline is \"Just exploring\" OR no clear reason provided OR very early stage with no commitment signals\n\nWhen in doubt between Hot and Warm \u2014 score Hot if timeline is under 3 months. Timeline is the primary scoring factor.\n\nACKNOWLEDGMENT EMAIL:\nDraft a short warm email (2-3 sentences) to accompany the report link. Reference their property address specifically. Never mention AI or automation.\n\nFormat email_body as two parts separated by \\n\\n:\n Part 1: Greeting line only e.g. \"Dear {name},\"\n Part 2: Message body as single paragraph\n\nOutput ONLY valid JSON, no preamble, no markdown backticks:\n{\n \"executiveSummary\": \"text\",\n \"estimatedValueRange\": \"$XXX,000 \u2014 $XXX,000\",\n \"keyValueFactors\": [\"factor 1\", \"factor 2\", \"factor 3\"],\n \"marketContext\": \"text\",\n \"pricingStrategy\": \"text\",\n \"recommendedNextSteps\": [\"step 1\", \"step 2\", \"step 3\"],\n \"score\": \"Hot or Warm or Cold\",\n \"reasoning\": \"one sentence\",\n \"email_subject\": \"Your Property Valuation Report is Ready\",\n \"email_body\": \"Dear {name},\\n\\nBody here.\"\n}"
},
"messages": {
"values": [
{
"content": "=Seller name: {{ $json.sellerName }}\nProperty address: {{ $json.propertyAddress }}\nProperty type: {{ $json.propertyType }}\nBedrooms: {{ $json.bedrooms }}\nBathrooms: {{ $json.bathrooms }}\nProperty condition: {{ $json.condition }}\nSeller timeline: {{ $json.timeline }}\nReason for selling: {{ $json.reasonForSelling }}\nSeller's expected price: {{ $json.expectedPrice }}"
}
]
},
"builtInTools": {}
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "d59e929b-8506-4134-815f-e96372e57e21",
"name": "Parse AI Output",
"type": "n8n-nodes-base.code",
"position": [
80,
-16
],
"parameters": {
"jsCode": "// ============================================================\n// UPDATE THIS NAME IF YOU RENAME THE NODE ON THE CANVAS\nconst EXTRACT_NODE = 'Extract & Normalize Property Details';\n// ============================================================\n\nconst propertyData = $(EXTRACT_NODE).first().json;\nconst inputJson = $input.first().json;\n\n// Handle all Gemini response formats\nlet rawText = '';\nconst allItems = $input.all();\n\nfor (const item of allItems) {\n const text = item.json?.content?.parts?.[0]?.text\n || item.json?.candidates?.[0]?.content?.parts?.[0]?.text\n || item.json?.output\n || '';\n if (text && text.includes('\"score\"')) {\n rawText = text;\n break;\n }\n}\n\nif (!rawText) {\n rawText = inputJson.output\n || inputJson.candidates?.[0]?.content?.parts?.[0]?.text\n || (inputJson.score ? JSON.stringify(inputJson) : '')\n || '';\n}\n\n// Strip markdown fences\nconst cleaned = rawText\n .replace(/```json\\s*/gi, '')\n .replace(/```\\s*/gi, '')\n .trim();\n\n// Parse with fallback\nlet parsed;\ntry {\n parsed = JSON.parse(cleaned);\n} catch (e) {\n parsed = {\n executiveSummary: 'We have received your property details and are preparing your valuation report.',\n estimatedValueRange: 'To be determined \u2014 please schedule a consultation.',\n keyValueFactors: ['Property condition', 'Location', 'Current market conditions'],\n marketContext: 'Market conditions vary. Please contact us for a detailed analysis.',\n pricingStrategy: 'We recommend scheduling a consultation for a personalized pricing strategy.',\n recommendedNextSteps: ['Schedule a consultation', 'Prepare property documents', 'Review comparable sales'],\n score: 'Warm',\n reasoning: 'AI parsing failed \u2014 manual review recommended.',\n email_subject: 'Your Property Valuation Request',\n email_body: `Dear ${propertyData.sellerName || 'there'},\\n\\nThank you for submitting your property details. We have received your valuation request and will be in touch shortly with your report.`\n };\n}\n\n// HTML formatter\nfunction escapeHtml(text) {\n if (!text) return '';\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>');\n}\n\nfunction formatEmailHtml(text) {\n if (!text) return '';\n const paragraphs = text\n .split(/\\n\\s*\\n/)\n .map(p => p.replace(/\\s+/g, ' ').trim())\n .filter(Boolean);\n return paragraphs.map(p => `<p>${escapeHtml(p)}</p>`).join('');\n}\n\n// HubSpot deal stage + dynamic close date\nconst dealStageMap = {\n 'Hot': { stage: 'appointmentscheduled', days: 30 },\n 'Warm': { stage: 'qualifiedtobuy', days: 90 },\n 'Cold': { stage: 'presentationscheduled',days: 180 }\n};\nconst dealConfig = dealStageMap[parsed.score] || dealStageMap['Warm'];\n\n// Google Calendar booking link\n// Replace with your actual Google Calendar appointment schedule URL\nconst BOOKING_LINK = 'YOUR_GOOGLE_CALENDAR_BOOKING_URL';\n\n// Build Google Docs report content\nconst reportContent = `Property Valuation Report\n${propertyData.propertyAddress || 'Property Address Not Provided'}\nPrepared: ${new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })}\n\nEXECUTIVE SUMMARY\n${parsed.executiveSummary}\n\nESTIMATED VALUE RANGE\n${parsed.estimatedValueRange}\n\nKEY VALUE FACTORS\n- ${(parsed.keyValueFactors || []).join('\\n\u2022 ')}\n\nMARKET CONTEXT\n${parsed.marketContext}\n\nPRICING STRATEGY\n${parsed.pricingStrategy}\n\nRECOMMENDED NEXT STEPS\n1. ${(parsed.recommendedNextSteps || [])[0] || ''}\n2. ${(parsed.recommendedNextSteps || [])[1] || ''}\n3. ${(parsed.recommendedNextSteps || [])[2] || ''}\n\n---\nThis report was prepared based on information provided by the seller \nand general market knowledge. For a full comparative market analysis, \nplease schedule a consultation with your agent.`;\n\n// Build agent notification HTML\nconst agentNotificationHtml = `\n <p><strong>${parsed.score === 'Hot' ? '\ud83d\udd25 Hot' : '\ud83d\udccb New'} Seller Lead</strong></p>\n <p>\n <strong>Name:</strong> ${escapeHtml(propertyData.sellerName || 'Unknown')}<br>\n <strong>Email:</strong> ${escapeHtml(propertyData.sellerEmail || 'Not provided')}<br>\n <strong>Phone:</strong> ${escapeHtml(propertyData.sellerPhone || 'Not provided')}<br>\n <strong>Property:</strong> ${escapeHtml(propertyData.propertyAddress || 'Not provided')}<br>\n <strong>Type:</strong> ${escapeHtml(propertyData.propertyType || 'Not specified')} \u2014 \n ${escapeHtml(propertyData.bedrooms || '?')} bed / \n ${escapeHtml(propertyData.bathrooms || '?')} bath<br>\n <strong>Condition:</strong> ${escapeHtml(propertyData.condition || 'Not specified')}<br>\n <strong>Timeline:</strong> ${escapeHtml(propertyData.timeline || 'Not specified')}<br>\n <strong>Reason:</strong> ${escapeHtml(propertyData.reasonForSelling || 'Not specified')}<br>\n <strong>Expected Price:</strong> ${escapeHtml(propertyData.expectedPrice || 'Not provided')}\n </p>\n <p>\n <strong>AI Score:</strong> ${escapeHtml(parsed.score)}<br>\n <strong>Reasoning:</strong> ${escapeHtml(parsed.reasoning)}<br>\n <strong>Estimated Value:</strong> ${escapeHtml(parsed.estimatedValueRange)}\n </p>\n <hr>\n <p>\n \ud83d\udcc4 <strong>Valuation Report:</strong> [Report link will appear here after Google Docs creation]<br>\n \ud83d\udcc5 <strong>Send Booking Link:</strong> <a href=\"${BOOKING_LINK}\">${BOOKING_LINK}</a>\n </p>\n`;\n\n// Slack notification\nconst slackNotification =\n `\ud83d\udd25 *Hot Seller Lead*\\n` +\n `*Name:* ${propertyData.sellerName || 'Unknown'}\\n` +\n `*Property:* ${propertyData.propertyAddress || 'Not provided'}\\n` +\n `*Timeline:* ${propertyData.timeline || 'Not specified'}\\n` +\n `*Estimated Value:* ${parsed.estimatedValueRange}\\n` +\n `*Score:* ${parsed.score} \u2014 ${parsed.reasoning}`;\n\nreturn [{\n json: {\n // Property details\n sellerName: propertyData.sellerName,\n sellerEmail: propertyData.sellerEmail,\n sellerPhone: propertyData.sellerPhone,\n propertyAddress: propertyData.propertyAddress,\n propertyType: propertyData.propertyType,\n bedrooms: propertyData.bedrooms,\n bathrooms: propertyData.bathrooms,\n condition: propertyData.condition,\n timeline: propertyData.timeline,\n reasonForSelling: propertyData.reasonForSelling,\n expectedPrice: propertyData.expectedPrice,\n // AI report sections\n executiveSummary: parsed.executiveSummary,\n estimatedValueRange: parsed.estimatedValueRange,\n keyValueFactors: parsed.keyValueFactors,\n marketContext: parsed.marketContext,\n pricingStrategy: parsed.pricingStrategy,\n recommendedNextSteps: parsed.recommendedNextSteps,\n // Qualification\n score: parsed.score,\n reasoning: parsed.reasoning,\n // Email content\n email_subject: parsed.email_subject,\n email_body: formatEmailHtml(parsed.email_body),\n // Google Docs report text\n reportContent,\n // HubSpot config\n hubspotDealStage: dealConfig.stage,\n closeDate: new Date(Date.now() + dealConfig.days * 86400000).getTime(),\n // Notifications\n agentNotificationHtml,\n slackNotification,\n // Metadata\n recordId: propertyData.recordId,\n timestamp: propertyData.timestamp,\n bookingLink: BOOKING_LINK\n }\n}];"
},
"typeVersion": 2
},
{
"id": "b9a912fa-e1a3-4412-bc77-f89cbee6f77e",
"name": "Create Valuation Report in Google Docs",
"type": "n8n-nodes-base.googleDocs",
"position": [
272,
-16
],
"parameters": {
"title": "=Valuation Report \u2014 {{ $json.propertyAddress }} \u2014 {{ $json.timestamp.substring(0,10) }}",
"folderId": "1lRYt5BMGvebbZz6JPghqFXQsPO3jUlZt"
},
"credentials": {
"googleDocsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 2
},
{
"id": "88c6a8ee-6e81-40ab-9ab9-116be320af2b",
"name": "Build Report URL",
"type": "n8n-nodes-base.set",
"position": [
848,
-16
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "2b13b415-d5c8-4756-8c2a-58e29b61bd61",
"name": "reportUrl",
"type": "string",
"value": "=https://docs.google.com/document/d/{{ $json.documentId }}/edit"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "dd71bf37-1c1b-48cf-8ef6-2f062ae207c1",
"name": "Share Document Publicly",
"type": "n8n-nodes-base.httpRequest",
"position": [
1056,
-16
],
"parameters": {
"url": "=https://www.googleapis.com/drive/v3/files/{{ $('Create Valuation Report in Google Docs').first().json.id }}/permissions",
"method": "POST",
"options": {},
"jsonBody": "{\n \"role\": \"reader\",\n \"type\": \"anyone\"\n}",
"sendBody": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "googleDocsOAuth2Api"
},
"credentials": {
"googleDocsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.4
},
{
"id": "9ea8cf6b-e53b-4139-9206-a4cd83920c89",
"name": "Send Report to Seller",
"type": "n8n-nodes-base.gmail",
"position": [
1264,
-16
],
"parameters": {
"sendTo": "={{ $('Parse AI Output').first().json.sellerEmail }}",
"message": "={{ $('Parse AI Output').first().json.email_body }} <p>\ud83d\udcc4 <strong>Your Valuation Report:</strong> <a href=\"{{ $('Build Report URL').first().json.reportUrl }}\"> Click here to view your report </a></p> <p>We look forward to helping you achieve the best possible outcome for your property.</p>",
"options": {
"appendAttribution": false
},
"subject": "={{ $('Parse AI Output').first().json.email_subject }}"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "a4635c40-c597-482e-9350-e86d908ad195",
"name": "HubSpot: Upsert Seller Contact",
"type": "n8n-nodes-base.hubspot",
"position": [
1472,
-16
],
"parameters": {
"email": "={{ $('Parse AI Output').first().json.sellerEmail }}",
"options": {
"resolveData": false
},
"authentication": "appToken",
"additionalFields": {
"lastName": "={{ $('Parse AI Output').first().json.sellerName?.split(' ').slice(1).join(' ') || '' }}",
"firstName": "={{ $('Parse AI Output').first().json.sellerName?.split(' ')[0] || '' }}",
"phoneNumber": "={{ $('Parse AI Output').first().json.sellerPhone }}",
"lifeCycleStage": "lead",
"customPropertiesUi": {
"customPropertiesValues": [
{
"value": "={{ $('Parse AI Output').first().json.score }}",
"property": "lead_score"
},
{
"value": "={{ $('Parse AI Output').first().json.propertyAddress }}",
"property": "property_interest"
},
{
"value": "Seller Valuation Request",
"property": "portal_source"
}
]
}
}
},
"credentials": {
"hubspotAppToken": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "f72e8b75-b817-47f7-87a4-bae68cea38bf",
"name": "HubSpot: Create Seller Deal",
"type": "n8n-nodes-base.hubspot",
"position": [
1664,
-16
],
"parameters": {
"stage": "={{ $('Parse AI Output').first().json.hubspotDealStage }}",
"resource": "deal",
"authentication": "appToken",
"additionalFields": {
"dealName": "={{ $('Parse AI Output').first().json.sellerName }} \u2014 {{ $('Parse AI Output').first().json.propertyAddress }}",
"pipeline": "=default",
"closeDate": "={{ $('Parse AI Output').first().json.closeDate }}"
}
},
"credentials": {
"hubspotAppToken": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "c28cd21b-8eb7-467e-876f-85deba8e56c5",
"name": "Log to Valuation Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
1856,
-16
],
"parameters": {
"columns": {
"value": {
"Email": "={{ $('Parse AI Output').first().json.sellerEmail }}",
"Phone": "='{{ $('Parse AI Output').first().json.sellerPhone }}",
"Bedrooms": "={{ $('Parse AI Output').first().json.bedrooms }}",
"Timeline": "={{ $('Parse AI Output').first().json.timeline }}",
"recordId": "={{ $('Parse AI Output').first().json.recordId }}",
"Bathrooms": "={{ $('Parse AI Output').first().json.bathrooms }}",
"Condition": "={{ $('Parse AI Output').first().json.condition }}",
"Timestamp": "={{ $('Parse AI Output').first().json.timestamp }}",
"Email Sent": "={{ $('Parse AI Output').first().json.sellerEmail ? 'true' : 'false' }}",
"Seller Name": "={{ $('Parse AI Output').first().json.sellerName }}",
"Seller Score": "={{ $('Parse AI Output').first().json.score }}",
"Property Type": "={{ $('Parse AI Output').first().json.propertyType }}",
"Agent Notified": "false",
"Expected Price": "={{ $('Parse AI Output').first().json.expectedPrice }}",
"Google Docs URL": "={{ $('Build Report URL').first().json.reportUrl }}",
"HubSpot Deal ID": "={{ $('HubSpot: Create Seller Deal').first().json.id }}",
"Score Reasoning": "={{ $('Parse AI Output').first().json.reasoning }}",
"Property Address": "={{ $('Parse AI Output').first().json.propertyAddress }}",
"HubSpot Contact ID": "={{ $('HubSpot: Upsert Seller Contact').first().json.vid }}",
"Reason for Selling": "={{ $('Parse AI Output').first().json.reasonForSelling }}"
},
"schema": [
{
"id": "recordId",
"type": "string",
"display": true,
"required": false,
"displayName": "recordId",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Timestamp",
"type": "string",
"display": true,
"required": false,
"displayName": "Timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Seller Name",
"type": "string",
"display": true,
"required": false,
"displayName": "Seller Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Email",
"type": "string",
"display": true,
"required": false,
"displayName": "Email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Phone",
"type": "string",
"display": true,
"required": false,
"displayName": "Phone",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Property Address",
"type": "string",
"display": true,
"required": false,
"displayName": "Property Address",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Property Type",
"type": "string",
"display": true,
"required": false,
"displayName": "Property Type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Bedrooms",
"type": "string",
"display": true,
"required": false,
"displayName": "Bedrooms",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Bathrooms",
"type": "string",
"display": true,
"required": false,
"displayName": "Bathrooms",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Condition",
"type": "string",
"display": true,
"required": false,
"displayName": "Condition",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Timeline",
"type": "string",
"display": true,
"required": false,
"displayName": "Timeline",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Reason for Selling",
"type": "string",
"display": true,
"required": false,
"displayName": "Reason for Selling",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Expected Price",
"type": "string",
"display": true,
"required": false,
"displayName": "Expected Price",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Seller Score",
"type": "string",
"display": true,
"required": false,
"displayName": "Seller Score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Score Reasoning",
"type": "string",
"display": true,
"required": false,
"displayName": "Score Reasoning",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Google Docs URL",
"type": "string",
"display": true,
"required": false,
"displayName": "Google Docs URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Email Sent",
"type": "string",
"display": true,
"required": false,
"displayName": "Email Sent",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "HubSpot Contact ID",
"type": "string",
"display": true,
"required": false,
"displayName": "HubSpot Contact ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "HubSpot Deal ID",
"type": "string",
"display": true,
"required": false,
"displayName": "HubSpot Deal ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Agent Notified",
"type": "string",
"display": true,
"required": false,
"displayName": "Agent Notified",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1B_M8vqGeueJAJiDNj43_XRU3fuK60PUL_7AbLva4Ozc/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "url",
"value": ""
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "2e36e1aa-acf2-4fe1-8f8e-a5027c9cfeec",
"name": "Is Seller Hot?",
"type": "n8n-nodes-base.if",
"position": [
2048,
-16
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "34172853-8848-4951-82bd-8e9b746beb33",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $('Parse AI Output').first().json.score.toLowerCase() }}",
"rightValue": "hot"
}
]
}
},
"typeVersion": 2.3
},
{
"id": "aafbbe24-5bb1-4af2-8bac-af5b97ec41c8",
"name": "Notify Agent for Hot Seller",
"type": "n8n-nodes-base.gmail",
"position": [
2352,
-192
],
"parameters": {
"sendTo": "user@example.com",
"message": "={{ $('Parse AI Output').first().json.agentNotificationHtml .replace('[Report link will appear here after Google Docs creation]', '<a href=\"' + $('Build Report URL').first().json.reportUrl + '\">' + $('Build Report URL').first().json.reportUrl + '</a>') }}",
"options": {
"appendAttribution": false
},
"subject": "=\ud83d\udd25 Hot Seller Lead \u2014 {{ $('Parse AI Output').first().json.propertyAddress }}"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "2ca0eb5b-1e6e-46dc-8fff-1937210bfc9f",
"name": "Update Row: Agent Notified",
"type": "n8n-nodes-base.googleSheets",
"position": [
2560,
-192
],
"parameters": {
"columns": {
"value": {
"recordId": "={{ $('Parse AI Output').first().json.recordId }}",
"Agent Notified": "true"
},
"schema": [
{
"id": "recordId",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "recordId",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Timestamp",
"type": "string",
"display": true,
"required": false,
"displayName": "Timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Seller Name",
"type": "string",
"display": true,
"required": false,
"displayName": "Seller Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Email",
"type": "string",
"display": true,
"required": false,
"displayName": "Email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Phone",
"type": "string",
"display": true,
"required": false,
"displayName": "Phone",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Property Address",
"type": "string",
"display": true,
"required": false,
"displayName": "Property Address",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Property Type",
"type": "string",
"display": true,
"required": false,
"displayName": "Property Type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Bedrooms",
"type": "string",
"display": true,
"required": false,
"displayName": "Bedrooms",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Bathrooms",
"type": "string",
"display": true,
"required": false,
"displayName": "Bathrooms",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Condition",
"type": "string",
"display": true,
"required": false,
"displayName": "Condition",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Timeline",
"type": "string",
"display": true,
"required": false,
"displayName": "Timeline",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Reason for Selling",
"type": "string",
"display": true,
"required": false,
"displayName": "Reason for Selling",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Expected Price",
"type": "string",
"display": true,
"required": false,
"displayName": "Expected Price",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Seller Score",
"type": "string",
"display": true,
"required": false,
"displayName": "Seller Score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Score Reasoning",
"type": "string",
"display": true,
"required": false,
"displayName": "Score Reasoning",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Google Docs URL",
"type": "string",
"display": true,
"required": false,
"displayName": "Google Docs URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Email Sent",
"type": "string",
"display": true,
"required": false,
"displayName": "Email Sent",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "HubSpot Contact ID",
"type": "string",
"display": true,
"required": false,
"displayName": "HubSpot Contact ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "HubSpot Deal ID",
"type": "string",
"display": true,
"required": false,
"displayName": "HubSpot Deal ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Agent Notified",
"type": "string",
"display": true,
"required": false,
"displayName": "Agent Notified",
"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": [
"recordId"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1B_M8vqGeueJAJiDNj43_XRU3fuK60PUL_7AbLva4Ozc/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "url",
"value": ""
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "d11a34fd-55ab-4cf7-89b0-433309119839",
"name": "Insert Content",
"type": "n8n-nodes-base.httpRequest",
"position": [
656,
-16
],
"parameters": {
"url": "=https://docs.googleapis.com/v1/documents/{{ $('Create Valuation Report in Google Docs').first().json.id }}:batchUpdate",
"body": "={{ $json.requestBody }}",
"method": "POST",
"options": {},
"sendBody": true,
"contentType": "raw",
"authentication": "predefinedCredentialType",
"rawContentType": "application/json",
"nodeCredentialType": "googleDocsOAuth2Api"
},
"credentials": {
"googleDocsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.4
},
{
"id": "90b04984-9d5c-46f6-aeb6-15afd3ecf9a1",
"name": "Build Docs Insert Request",
"type": "n8n-nodes-base.code",
"position": [
464,
-16
],
"parameters": {
"jsCode": "// Get report content from Parse AI Output\nconst reportContent = $('Parse AI Output').first().json.reportContent;\nconst documentId = $('Create Valuation Report in Google Docs').first().json.documentId;\n\n// Build the batchUpdate request object properly\n// This avoids JSON serialization issues with newlines and special characters\nconst requestBody = {\n requests: [\n {\n insertText: {\n location: {\n index: 1\n },\n text: reportContent\n }\n }\n ]\n};\n\nreturn [{\n json: {\n documentId,\n requestBody: JSON.stringify(requestBody),\n requestBodyParsed: requestBody\n }\n}];"
},
"typeVersion": 2
},
{
"id": "0dd3fbf1-7d7e-4483-be93-deafe86f1260",
"name": "Notify Agent via Slack",
"type": "n8n-nodes-base.slack",
"position": [
2352,
128
],
"parameters": {
"text": "={{ $('Parse AI Output').first().json.slackNotification }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "name",
"value": "#hot-leads"
},
"otherOptions": {
"includeLinkToWorkflow": false
}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.5
},
{
"id": "3adf276c-1472-4471-9b87-ceaaffbf17fc",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1888,
-576
],
"parameters": {
"width": 768,
"height": 1040,
"content": "## AI Seller Valuation Request & CMA-Lite Report Generator\n\nWhen a homeowner asks \"what's my home worth?\", most agents respond days later with a generic answer or spend 45 minutes manually preparing a report. The agent who responds first with a professional valuation wins the listing.\n\nThis workflow responds in minutes, not days. When a seller submits their property details, AI generates a professional CMA-lite valuation report covering estimated value range, key value factors, market context, and pricing strategy. The report is saved to Google Docs and emailed to the seller with a shareable link. Simultaneously, the seller is qualified as Hot, Warm, or Cold \u2014 Hot sellers trigger an instant agent notification with the report link and a listing consultation booking link.\n\n### Requirements\n- **Gmail** OAuth2 \u2014 seller email + agent notification\n- **Gemini** API key \u2014 report generation + qualification\n- **Google Docs** OAuth2 \u2014 valuation report creation\n- **Google Sheets** OAuth2 \u2014 lead logging\n- **HubSpot** Service Key \u2014 contact + deal creation\n- **Slack** OAuth2 \u2014 optional Hot seller alerts\n- **Typeform** API \u2014 optional premium form trigger\n\n### Setup\n1. Connect **Gmail**, **Gemini**, **Google Docs**, **Google Sheets**, and **HubSpot** credentials.\n2. Create a Google Drive folder named **Valuation Reports** and note the folder ID from the URL.\n3. Create three HubSpot custom contact properties: `lead_score`, `property_interest`, `portal_source`.\n4. Copy the *Seller Valuation Database* sheet template and link it to the Sheets nodes.\n5. Replace **YOUR_GOOGLE_CALENDAR_BOOKING_URL** in the Parse AI Output node with your Google Calendar appointment scheduling page URL.\n6. Update the agent email in the Notify Agent node.\n7. Choose your trigger \u2014 Webhook (default, active) or Typeform (optional, disabled). See trigger note below.\n\n### Customization\n- Edit scoring rules in the Gemini prompt to adjust Hot / Warm / Cold thresholds for your market.\n- Edit report sections in the system prompt to add or remove CMA sections.\n- Change close date offsets in Parse AI Output: Hot = 30 days, Warm = 90 days, Cold = 180 days."
},
"typeVersion": 1
},
{
"id": "740d4c9f-ee3a-4527-a045-d2b30eaef580",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1056,
-512
],
"parameters": {
"color": "#FAFAFA",
"width": 480,
"height": 864,
"content": "## Choose Your Trigger\n\n**Option A \u2014 Webhook (active, default)**\nWorks immediately with any form tool \u2014 Typeform free, Google Forms, Tally, Jotform, or any website contact form that can send a POST request. No extra credentials.\n\n**Option B \u2014 Typeform (disabled)**\nRicher conversational intake experience. Requires a permanent public n8n URL and Typeform API credential. Enable this node and disable the Webhook node to use it.\nNeed help setting up? contact@qualmatic.io"
},
"typeVersion": 1
},
{
"id": "2a36ae25-c392-4612-95ca-bb4bd5085970",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-560,
-512
],
"parameters": {
"color": "#FAFAFA",
"width": 262,
"height": 864,
"content": "## Extract & Normalize Property Details\nMaps both Typeform's nested answer format AND flat webhook JSON into clean named fields used by all downstream nodes.\nHandles all Typeform answer types \u2014 text, email, phone, multiple choice, and long text \u2014 automatically."
},
"typeVersion": 1
},
{
"id": "625f1d3f-d466-41d0-8de9-3622abc3bbc8",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-272,
-512
],
"parameters": {
"color": "#FAFAFA",
"width": 480,
"height": 864,
"content": "## Generate CMA-Lite Report\nOne Gemini AI call generates the full valuation report and qualifies the seller's readiness simultaneously.\n\nReport includes: Executive Summary, Estimated Value Range, Key Value Factors, Market Context, Pricing Strategy, and Recommended Next Steps.\n\nSeller is scored Hot, Warm, or Cold based on timeline and selling motivation. If AI fails, a fallback acknowledgment sends and raw data logs to Sheets."
},
"typeVersion": 1
},
{
"id": "fd065e9e-a35d-4461-9678-f237f6447bb8",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
224,
-512
],
"parameters": {
"color": "#FAFAFA",
"width": 976,
"height": 864,
"content": "## Create & Share Valuation Report\nCreates a new Google Docs document with the full formatted report content. Sets the document to \"Anyone with the link can view\" so the seller can open it without a Google account. The report URL is stored for use in the seller email and agent notification."
},
"typeVersion": 1
},
{
"id": "59bbd28c-4e6c-44d9-9e97-e64fd392dfd1",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
1216,
-512
],
"parameters": {
"color": "#FAFAFA",
"width": 784,
"height": 864,
"content": "## HubSpot, Email & Sheets\nSends the report link to the seller via Gmail. Creates or updates the seller contact in HubSpot and creates a deal in the correct pipeline stage based on the AI score with dynamic close dates. Everything logs to Google Sheets as a backup record."
},
"typeVersion": 1
},
{
"id": "deff9940-a2f2-48be-9c18-f5da721a6723",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
2016,
-512
],
"parameters": {
"color": "#FAFAFA",
"width": 752,
"height": 864,
"content": "## Hot Seller Alert\nHot sellers trigger an instant agent notification with the full property profile, AI score reasoning, estimated value range, report link, and a listing consultation booking link \u2014 everything needed to act immediately. Slack alert fires optionally alongside the email. Warm and Cold sellers are fully processed but do not trigger agent notifications."
},
"typeVersion": 1
},
{
"id": "6d1a9b22-d2e2-4945-80b1-d8898814ab54",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"position": [
224,
-112
],
"parameters": {
"color": 3,
"width": 208,
"height": 752,
"content": "\n\n\n\n\n\n\n\n\n\n\n\n## Google Docs Credential Required\nThis node requires a separate Google Docs OAuth2\ncredential different from Google Sheets OAuth2.\nEnable both the Google Docs API and Google Drive API in your Google Cloud Console before connecting. All reports save to your Google Drive. Consider\ncreating a dedicated \"Valuation Reports\" folder."
},
"typeVersion": 1
},
{
"id": "63d6f286-016f-4538-9390-d2d8d2b2f2d0",
"name": "Sticky Note9",
"type": "n8n-nodes-base.stickyNote",
"position": [
-16,
-112
],
"parameters": {
"color": 3,
"width": 224,
"height": 752,
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n## Placeholder to Update Before Going Live\n\n**Google Calendar Booking URL**\nReplace YOUR_GOOGLE_CALENDAR_BOOKING_URL in this\nCode node with your Google Calendar appointment\nscheduling page URL.\n"
},
"typeVersion": 1
},
{
"id": "3c689063-6254-43ef-935f-e1cbd8c7af12",
"name": "Sticky Note10",
"type": "n8n-nodes-base.stickyNote",
"position": [
1776,
-320
],
"parameters": {
"color": 3,
"width": 720,
"height": 272,
"content": "## Agent Email Address to Update Before Going Live\n\nReplace YOUR_AGENT_EMAIL@EXAMPLE.COM with the agent's real email address."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "35362598-9239-49f7-affd-3024cb82d3b2",
"nodeGroups": [],
"connections": {
"Insert Content": {
"main": [
[
{
"node": "Build Report URL",
"type": "main",
"index": 0
}
]
]
},
"Is Seller Hot?": {
"main": [
[
{
"node": "Notify Agent for Hot Seller",
"type": "main",
"index": 0
},
{
"node": "Notify Agent via Slack",
"type": "main",
"index": 0
}
]
]
},
"Parse AI Output": {
"main": [
[
{
"node": "Create Valuation Report in Google Docs",
"type": "main",
"index": 0
}
]
]
},
"Build Report URL": {
"main": [
[
{
"node": "Share Document Publicly",
"type": "main",
"index": 0
}
]
]
},
"Send Report to Seller": {
"main": [
[
{
"node": "HubSpot: Upsert Seller Contact",
"type": "main",
"index": 0
}
]
]
},
"Log to Valuation Sheet": {
"main": [
[
{
"node": "Is Seller Hot?",
"type": "main",
"index": 0
}
]
]
},
"Share Document Publicly": {
"main": [
[
{
"node": "Send Report to Seller",
"type": "main",
"index": 0
}
]
]
},
"Generate CMA-Lite Report": {
"main": [
[
{
"node": "Parse AI Output",
"type": "main",
"index": 0
}
]
]
},
"Build Docs Insert Request": {
"main": [
[
{
"node": "Insert Content",
"type": "main",
"index": 0
}
]
]
},
"HubSpot: Create Seller Deal": {
"main": [
[
{
"node": "Log to Valuation Sheet",
"type": "main",
"index": 0
}
]
]
},
"Notify Agent for Hot Seller": {
"main": [
[
{
"node": "Update Row: Agent Notified",
"type": "main",
"index": 0
}
]
]
},
"HubSpot: Upsert Seller Contact": {
"main": [
[
{
"node": "HubSpot: Create Seller Deal",
"type": "main",
"index": 0
}
]
]
},
"Webhook: Seller Valuation Request": {
"main": [
[
{
"node": "Extract & Normalize Property Details",
"type": "main",
"index": 0
}
]
]
},
"Typeform: Seller Valuation Request": {
"main": [
[
{
"node": "Extract & Normalize Property Details",
"type": "main",
"index": 0
}
]
]
},
"Extract & Normalize Property Details": {
"main": [
[
{
"node": "Generate CMA-Lite Report",
"type": "main",
"index": 0
}
]
]
},
"Create Valuation Report in Google Docs": {
"main": [
[
{
"node": "Build Docs Insert Request",
"type": "main",
"index": 0
}
]
]
}
}
}
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.
gmailOAuth2googleDocsOAuth2ApigooglePalmApigoogleSheetsOAuth2ApihubspotAppTokenslackApitypeformApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
When a seller asks what their home is worth, this workflow generates a professional CMA-lite valuation report in Google Docs using Gemini AI, emails them the link within minutes, creates a HubSpot deal in the right pipeline stage, and alerts you instantly for hot sellers. A…
Source: https://n8n.io/workflows/17659/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This template is perfect for: Marketing Teams looking to automatically qualify inbound leads from campaigns Sales Teams wanting to prioritize high-value prospects instantly Agencies offering lead qual
When a property portal sends a lead notification to your Gmail, this workflow parses the email with Gemini AI, qualifies the lead, sends an instant acknowledgment, creates a HubSpot contact and deal i
Automate lead intake, AI qualification, and next‑step outreach. Qualified leads get a scheduled meeting, Zoom details, an email confirmation, CRM update, and Mailchimp enrollment. Not‑qualified leads
Automate your lead qualification pipeline — capture Typeform Webhook leads, enrich with APIs, score intelligently, and route to HubSpot, Slack, and Sheets in real-time.
For Temp_Smart Lead Routing & Qualification System (Typeform to HubSpot). Uses httpRequest, hubspot, slack, googleSheets. Webhook trigger; 27 nodes.