This workflow corresponds to n8n.io template #12715 — we link there as the canonical source.
This workflow follows the Agent → Form Trigger 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": "WNMNYGtBnhK3XivgdCN0w",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Generate sales proposals with Gemini and Google Docs",
"tags": [
{
"id": "K6D3K6nP6k9TByzr",
"name": "sales-automation",
"createdAt": "2026-01-14T17:39:47.009Z",
"updatedAt": "2026-01-14T17:39:47.009Z"
},
{
"id": "NCFzdO7mRAguwdoQ",
"name": "proposal-generation",
"createdAt": "2026-01-21T20:39:12.676Z",
"updatedAt": "2026-01-21T20:39:12.676Z"
},
{
"id": "VoJMSzkknWaPzhGO",
"name": "google-docs",
"createdAt": "2026-01-21T20:39:12.679Z",
"updatedAt": "2026-01-21T20:39:12.679Z"
}
],
"nodes": [
{
"id": "95aec752-5f78-481d-b7df-11097d6521c5",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
1920,
448
],
"parameters": {
"color": 5,
"width": 380,
"height": 816,
"content": "## How it works\n\nThis workflow generates professional sales proposals from a simple form:\n\n1. **Form** - Sales rep submits client details, pain points, and pricing\n2. **Calculate** - Computes ROI, savings, and break-even metrics\n3. **Generate** - Gemini AI writes executive summary, challenges, solution strategy, and team bios\n4. **Create** - Copies your Google Doc template and populates all placeholders\n\nThe AI tailors content to the client's industry and pain points while incorporating your calculated financial metrics.\n\n## Setup steps\n\n1. **Google Doc template** - Create a doc with placeholders: `{{client_name}}`, `{{executive_summary}}`, `{{key_challenges}}`, `{{solution_strategy}}`, `{{team_bios}}`, `{{formatted_roi}}`, `{{formatted_net_savings}}`, `{{formatted_break_even}}`, `{{next_steps}}`, `{{date}}`\n2. **Credentials** - Connect Google Drive, Google Docs, and Gemini API\n3. **Configure Copy node** - Point to your template document\n4. **Customize AI** - Edit the system message in \"Generate proposal content\" to match your company's tone\n5. **Test** - Submit the form and check the generated proposal"
},
"typeVersion": 1
},
{
"id": "9a99fd38-b5fe-45e8-9f9c-f9318bc3b3c0",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
2400,
608
],
"parameters": {
"color": 7,
"width": 280,
"height": 96,
"content": "**Data preparation**\nForm collects client info. Code node calculates ROI, savings, and break-even from financials."
},
"typeVersion": 1
},
{
"id": "5b84d41d-8a9a-402a-8eef-a3bb0628fc86",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
2816,
608
],
"parameters": {
"color": 7,
"width": 280,
"height": 96,
"content": "**AI generation**\nGemini writes proposal sections based on pain points and financials. Parser extracts JSON fields."
},
"typeVersion": 1
},
{
"id": "cd31ccaa-8356-4b3a-b266-e5ead83fef69",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
3376,
608
],
"parameters": {
"color": 7,
"width": 300,
"height": 96,
"content": "**Document creation**\nCopies template, formats bullet points, and replaces all placeholders with generated content."
},
"typeVersion": 1
},
{
"id": "49b28a3b-13e6-4e01-9453-6144be48c82d",
"name": "Receive proposal details",
"type": "n8n-nodes-base.formTrigger",
"position": [
2400,
752
],
"parameters": {
"options": {},
"formTitle": "Proposal Generation Form",
"formFields": {
"values": [
{
"fieldName": "user_company_name",
"fieldLabel": "Your Company Name"
},
{
"fieldName": "team_members_input",
"fieldType": "textarea",
"fieldLabel": "Team Members & Roles",
"placeholder": "ane Doe (Lead Engineer), John Smith (Project Manager)"
},
{
"fieldName": "client_name",
"fieldLabel": "Client Name",
"placeholder": "For the cover page and headers.",
"requiredField": true
},
{
"fieldName": "client_industry",
"fieldLabel": "Client Industry",
"placeholder": "Helps the AI customize the tone (e.g., Medical vs. Construction).",
"requiredField": true
},
{
"fieldName": "key_pain_points",
"fieldType": "textarea",
"fieldLabel": "Key Pain Points",
"placeholder": "The raw notes the AI will turn into \"Key Challenges.\"",
"requiredField": true
},
{
"fieldName": "current_annual_spend",
"fieldType": "number",
"fieldLabel": "Current Annual Spend ($)",
"placeholder": "Crucial for the ROI Logic (e.g., \"50000\").",
"requiredField": true
},
{
"fieldName": "offer_type",
"fieldType": "dropdown",
"fieldLabel": "Offer Type",
"defaultValue": "Selects which \"Company Context\" to load (e.g., \"SEO Retainer\" vs. \"Web Dev\").",
"fieldOptions": {
"values": [
{
"option": "SEO Retainer"
},
{
"option": "Web Dev"
}
]
},
"requiredField": true
},
{
"fieldName": "proposed_solution_cost",
"fieldType": "number",
"fieldLabel": "Proposed Solution Cost ($)",
"placeholder": "Crucial for the ROI Logic (e.g., \"12000\").",
"requiredField": true
},
{
"fieldName": "project_start_date",
"fieldType": "date",
"fieldLabel": "Project Start Date",
"requiredField": true
}
]
},
"formDescription": "Fill out these fields for your client to generate a proposal."
},
"typeVersion": 2.4
},
{
"id": "a2afdd6b-a539-44a5-8740-cfb714337059",
"name": "Calculate ROI metrics",
"type": "n8n-nodes-base.code",
"position": [
2608,
752
],
"parameters": {
"jsCode": "// 1. Get the data\nconst formData = items[0].json;\n\n// 2. Helper function to clean inputs\nfunction cleanNumber(value) {\n if (typeof value === 'number') return value;\n if (!value) return 0;\n return parseFloat(value.toString().replace(/[^0-9.-]+/g,\"\"));\n}\n\n// 3. Extract and Clean Variables\nconst currentSpend = cleanNumber(formData.current_annual_spend || 0);\nconst solutionCost = cleanNumber(formData.proposed_solution_cost || 0);\nconst clientName = formData.client_name || \"Valued Client\";\nconst painPoints = formData.key_pain_points || \"\";\n\n// --- CONFIGURATION ---\nconst efficiencyAssumption = 1.0; \n// ---------------------\n\n// 4. Perform Calculations\nconst grossSavings = currentSpend * efficiencyAssumption; \nconst netSavings = grossSavings - solutionCost;\nlet roiPercent = 0;\nlet breakEvenMonths = 0;\n\nif (solutionCost > 0) {\n roiPercent = (netSavings / solutionCost) * 100;\n breakEvenMonths = solutionCost / (grossSavings / 12);\n}\n\n// 5. Format for Humans\nconst currencyFormatter = new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: 'USD',\n maximumFractionDigits: 0\n});\n\nreturn {\n json: {\n client_name: clientName,\n pain_points: painPoints,\n \n // Financials\n raw_savings: netSavings,\n raw_roi: roiPercent,\n \n // Formatted Text\n formatted_current_spend: currencyFormatter.format(currentSpend),\n formatted_solution_cost: currencyFormatter.format(solutionCost),\n formatted_net_savings: currencyFormatter.format(netSavings),\n formatted_roi: Math.round(roiPercent) + \"%\",\n formatted_break_even: breakEvenMonths.toFixed(1) + \" Months\",\n \n // AI Context\n ai_financial_context: `By implementing this solution, ${clientName} is projected to see a ${Math.round(roiPercent)}% ROI, recovering the initial investment in approximately ${breakEvenMonths.toFixed(1)} months.`\n }\n}"
},
"typeVersion": 2
},
{
"id": "a1eac7e9-acf9-497b-88d8-670b643deded",
"name": "Generate proposal content",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
2816,
752
],
"parameters": {
"text": "=Here are the details for the new proposal:\n\nCLIENT: {{ $('Receive proposal details').item.json.client_name }}\nMY COMPANY: {{ $('Receive proposal details').first().json.user_company_name }}\nMY TEAM MEMBERS (Raw List): {{ $('Receive proposal details').first().json.team_members_input }}\n\nPAIN POINTS: {{ $('Receive proposal details').item.json.key_pain_points }}\n\nFINANCIAL DATA:\n- ROI: {{ $('Calculate ROI metrics').first().json.formatted_roi }}\n- Annual Savings: {{ $('Calculate ROI metrics').first().json.formatted_net_savings }}\n- Break Even: {{ $('Calculate ROI metrics').first().json.formatted_break_even }}\n\nFINANCIAL NARRATIVE:\n{{ $('Calculate ROI metrics').first().json.ai_financial_context }}\n\nPlease generate the JSON proposal now.",
"options": {
"systemMessage": "You are an expert Enterprise Sales Engineer. Your goal is to write a winning business proposal based on the client data provided.\n\n### YOUR WRITING RULES:\n1. Tone: Professional, confident, and value-driven.\n2. Financials: Always tie the solution back to the financial savings provided.\n3. Team Section: You must write the \"team_bio_section\" as a complete narrative text block (not a JSON list).\n - Start with a warm introductory sentence (e.g., \"We have assembled a team of experts dedicated to [Client Name]'s success...\").\n - Then, list the team members provided in the \"MY TEAM MEMBERS\" input using a dash (-) for each new line. Include their Name, Title, and a brief 1-sentence bio.\n - End with a closing sentence about their commitment to the project (e.g., \"This team will be your dedicated support...\").\n - DO NOT invent a fake company name. Use the \"MY COMPANY\" name provided.\n\n### OUTPUT FORMAT:\nOutput ONLY a valid JSON object with these keys:\n{\n \"short_outcome_phrase\": \"A 2-5 word strategic goal based on their pain points.\",\n \"executive_summary\": \"A 3-4 sentence hook summarizing the problem and value.\",\n \"key_challenges_bullet_points\": \"A list of the 3 biggest pain points.\",\n \"solution_strategy\": \"A 2 paragraph roadmap of the solution.\",\n \"team_bio_section\": \"A single text string containing the Intro, the List (with line breaks), and the Outro.\",\n \"call_to_action\": \"A closing sentence urging them to sign.\"\n}"
},
"promptType": "define"
},
"typeVersion": 3.1
},
{
"id": "317d80a5-dd25-47a2-a385-43a424014653",
"name": "Gemini 1.5 Flash",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
2800,
960
],
"parameters": {
"options": {}
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "7aea949b-296c-408f-8c38-dd419a53e182",
"name": "Parse AI response",
"type": "n8n-nodes-base.code",
"position": [
3168,
752
],
"parameters": {
"jsCode": "// 1. Get the raw text output from the AI Agent\nconst rawOutput = $('Generate proposal content').first().json.output;\n\ntry {\n // 2. Locate the JSON object within the text\n const jsonMatch = rawOutput.match(/\\{[\\s\\S]*\\}/);\n\n if (!jsonMatch) {\n throw new Error(\"No JSON object found in AI response\");\n }\n\n // 3. Parse the cleaned string into a real Object\n const cleanJson = JSON.parse(jsonMatch[0]);\n\n // 4. Return the clean data\n return {\n json: cleanJson\n };\n\n} catch (error) {\n return {\n json: {\n error: \"Failed to parse JSON\",\n message: error.message,\n raw_ai_response: rawOutput\n }\n };\n}"
},
"typeVersion": 2
},
{
"id": "7965738d-fdd8-4877-bc93-c32bb1287367",
"name": "Copy proposal template",
"type": "n8n-nodes-base.googleDrive",
"position": [
3376,
752
],
"parameters": {
"name": "={{ $('Receive proposal details').item.json.client_name }} Proposal",
"fileId": {
"__rl": true,
"mode": "list",
"value": "1SCu_o75YfEPgTaP3JgaLYncZ8hz--AQ_wNPpJq4qrFE",
"cachedResultUrl": "https://docs.google.com/document/d/1SCu_o75YfEPgTaP3JgaLYncZ8hz--AQ_wNPpJq4qrFE/edit?usp=drivesdk",
"cachedResultName": "Proposal Template Master"
},
"options": {},
"operation": "copy"
},
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 3
},
{
"id": "dca9cd9e-4dc8-47e6-8138-a93d9a925f16",
"name": "Format bullet points",
"type": "n8n-nodes-base.code",
"position": [
3584,
752
],
"parameters": {
"jsCode": "// 1. Get the raw data\nconst aiData = $('Parse AI response').first().json;\n\n// 2. Helper function\nfunction formatAsBullets(input) {\n if (Array.isArray(input)) {\n const cleanItems = input.map(item => item.replace(/^[-\u2022*]\\s*/, '').trim());\n return \"\u2022 \" + cleanItems.join(\"\\n\u2022 \");\n }\n return input || \"\"; \n}\n\n// 3. Format fields\nconst challengesClean = formatAsBullets(aiData.key_challenges_bullet_points);\nconst biosClean = formatAsBullets(aiData.team_bio_section);\n\nreturn {\n json: {\n ready_challenges: challengesClean,\n ready_bios: biosClean\n }\n}"
},
"typeVersion": 2
},
{
"id": "c46fc679-3e25-4459-81a5-cb376acaf2ca",
"name": "Populate proposal document",
"type": "n8n-nodes-base.googleDocs",
"position": [
3792,
752
],
"parameters": {
"actionsUi": {
"actionFields": [
{
"text": "{{client_name}}",
"action": "replaceAll",
"replaceText": "={{ $('Receive proposal details').item.json.client_name }}"
},
{
"text": "{{user_company_name}}",
"action": "replaceAll",
"replaceText": "={{ $('Receive proposal details').item.json.user_company_name }}"
},
{
"text": "{{dynamic_title}}",
"action": "replaceAll",
"replaceText": "={{ $('Receive proposal details').item.json.client_name }}+ {{ $('Receive proposal details').first().json['user_company_name'] }}: {{ $('Parse AI response').first().json['short_outcome_phrase'] }}"
},
{
"text": "{{formatted_roi}}",
"action": "replaceAll",
"replaceText": "={{ $('Calculate ROI metrics').item.json.formatted_roi }}"
},
{
"text": "{{executive_summary}}",
"action": "replaceAll",
"replaceText": "={{ $('Parse AI response').item.json.executive_summary }}"
},
{
"text": "{{key_challenges}}",
"action": "replaceAll",
"replaceText": "={{ $json.ready_challenges }}"
},
{
"text": "{{solution_strategy}}",
"action": "replaceAll",
"replaceText": "={{ $('Parse AI response').item.json.solution_strategy }}"
},
{
"text": "{{team_bios}}",
"action": "replaceAll",
"replaceText": "={{ $('Parse AI response').item.json.team_bio_section }}"
},
{
"text": "{{next_steps}}",
"action": "replaceAll",
"replaceText": "={{ $('Parse AI response').item.json.call_to_action }}"
},
{
"text": "{{formatted_net_savings}}",
"action": "replaceAll",
"replaceText": "={{ $('Calculate ROI metrics').item.json.formatted_net_savings }}"
},
{
"text": "{{formatted_solution_cost}}",
"action": "replaceAll",
"replaceText": "={{ $('Calculate ROI metrics').item.json.formatted_solution_cost }}"
},
{
"text": "{{formatted_break_even}}",
"action": "replaceAll",
"replaceText": "={{ $('Calculate ROI metrics').item.json.formatted_break_even }}"
},
{
"text": "{{date}}",
"action": "replaceAll",
"replaceText": "={{ $now.toFormat('MMMM dd, yyyy') }}"
}
]
},
"operation": "update",
"documentURL": "={{ $('Copy proposal template').item.json.id }}"
},
"credentials": {
"googleDocsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 2
}
],
"active": true,
"settings": {
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "d7076d3a-3856-4857-b4fd-96125a4353c3",
"connections": {
"Gemini 1.5 Flash": {
"ai_languageModel": [
[
{
"node": "Generate proposal content",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Parse AI response": {
"main": [
[
{
"node": "Copy proposal template",
"type": "main",
"index": 0
}
]
]
},
"Format bullet points": {
"main": [
[
{
"node": "Populate proposal document",
"type": "main",
"index": 0
}
]
]
},
"Calculate ROI metrics": {
"main": [
[
{
"node": "Generate proposal content",
"type": "main",
"index": 0
}
]
]
},
"Copy proposal template": {
"main": [
[
{
"node": "Format bullet points",
"type": "main",
"index": 0
}
]
]
},
"Receive proposal details": {
"main": [
[
{
"node": "Calculate ROI metrics",
"type": "main",
"index": 0
}
]
]
},
"Generate proposal content": {
"main": [
[
{
"node": "Parse AI response",
"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.
googleDocsOAuth2ApigoogleDriveOAuth2ApigooglePalmApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Generate professional sales proposals from a simple form—AI writes the content, you deliver the document.
Source: https://n8n.io/workflows/12715/ — 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 n8n template automatically crawls technical documentation websites, scrapes their content, and converts it into clean, structured, developer-friendly documentation. Each page is organized into fo
This n8n template automates complaint mining from unstructured text sources and turns raw user feedback into clear, actionable insights. It uses AI to identify recurring complaints, pain points, and t
Streamline your recruitment process with AI-powered resume analysis that goes beyond keyword matching.
This workflow automates batch video publishing prep from a Google Drive folder with AI-generated, platform-specific copy and a simple approval queue in Google Sheets. Perfect for Agencies, content cre
This workflow automates the entire UX research planning process — from gathering context to delivering a ready-to-share Google Doc report. Built for UX researchers and designers, it combines AI-powere