AutomationFlowsAI & RAG › Generate B2b Lead Magnet Articles with AI Deep Research and Google Docs

Generate B2b Lead Magnet Articles with AI Deep Research and Google Docs

ByVeena Pandian @veenapandian on n8n.io

This workflow is built for B2B marketers, consultants, founders, and agency owners who need to produce high-quality, research-backed thought leadership content — without spending hours on research and writing.

Chat trigger trigger★★★★☆ complexityAI-powered24 nodesChat TriggerAgentHTTP RequestGoogle SheetsOllama Chat
AI & RAG Trigger: Chat trigger Nodes: 24 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #13835 — we link there as the canonical source.

This workflow follows the Agent → Chat 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 →

Download .json
{
  "id": "29TVA88oq23GYjx9",
  "name": "Generate B2B lead magnet articles with AI deep research to Google Docs",
  "tags": [
    {
      "id": "mHQntpbppFUpZPGm",
      "name": "template",
      "createdAt": "2026-02-17T08:30:26.885Z",
      "updatedAt": "2026-02-17T08:30:26.885Z"
    }
  ],
  "nodes": [
    {
      "id": "58a1733c-99e2-4dec-95bc-bb398cdb90b0",
      "name": "Submit Your Topic",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "position": [
        -256,
        736
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1.1
    },
    {
      "id": "49398999-609c-4c5f-8ffe-238581250345",
      "name": "Refine into 5 Strategic Queries",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -32,
        736
      ],
      "parameters": {
        "text": "=Take this topic and generate 5 strategic research queries for a B2B lead magnet article.\n\nTopic: {{ $json.chatInput }}",
        "options": {
          "systemMessage": "You are a Strategic Research Query Generator for B2B lead magnet content.\n\nYour job is to take a raw topic and transform it into 5 highly strategic research queries that will power a comprehensive authority-building article.\n\nThe final output will be a LinkedIn-style lead magnet article designed to establish thought leadership, generate inbound leads, drive consultation bookings, and build trust with B2B buyers.\n\nTarget audience: B2B founders, consultants, SaaS leaders, sales teams, agencies.\n\nReturn ONLY this JSON. No markdown. No extra text.\n\n{\n  \"originalTopic\": \"The raw topic submitted\",\n  \"refinedTopic\": \"A sharper more compelling version of the topic\",\n  \"articleAngle\": \"The unique positioning angle for this lead magnet\",\n  \"targetReader\": \"Specific B2B persona this targets\",\n  \"strategicQueries\": [\n    {\n      \"queryId\": \"q1\",\n      \"query\": \"Market context research question\",\n      \"purpose\": \"Establish authority with data\",\n      \"sectionItFeeds\": \"Market Overview\",\n      \"searchTerms\": [\"term1\", \"term2\", \"term3\"]\n    },\n    {\n      \"queryId\": \"q2\",\n      \"query\": \"Problem deep-dive research question\",\n      \"purpose\": \"Show understanding of reader pain points\",\n      \"sectionItFeeds\": \"The Problem\",\n      \"searchTerms\": [\"term1\", \"term2\"]\n    },\n    {\n      \"queryId\": \"q3\",\n      \"query\": \"Solution and framework research question\",\n      \"purpose\": \"Provide actionable value\",\n      \"sectionItFeeds\": \"The Framework\",\n      \"searchTerms\": [\"term1\", \"term2\"]\n    },\n    {\n      \"queryId\": \"q4\",\n      \"query\": \"Case study and proof research question\",\n      \"purpose\": \"Build credibility with evidence\",\n      \"sectionItFeeds\": \"Proof & Case Studies\",\n      \"searchTerms\": [\"term1\", \"term2\"]\n    },\n    {\n      \"queryId\": \"q5\",\n      \"query\": \"Future predictions research question\",\n      \"purpose\": \"Position as forward-thinking leader\",\n      \"sectionItFeeds\": \"Future Outlook\",\n      \"searchTerms\": [\"term1\", \"term2\"]\n    }\n  ],\n  \"proposedTitle\": \"Compelling article title that attracts clicks\",\n  \"proposedSubtitle\": \"Supporting subtitle with value proposition\",\n  \"keyInsightToProve\": \"The ONE big idea this article must prove\",\n  \"competitiveEdge\": \"What makes this angle different from existing content\"\n}\n\nRules:\n1. Each query must be specific and actionable\n2. Queries should NOT overlap\n3. Proposed title must be LinkedIn-worthy\n4. searchTerms should be Google-optimized\n5. Return ONLY valid JSON"
        },
        "promptType": "define"
      },
      "typeVersion": 2.1
    },
    {
      "id": "c560923d-f32b-4b3e-90e7-ad0ae8ab7050",
      "name": "Validate Queries",
      "type": "n8n-nodes-base.code",
      "position": [
        320,
        736
      ],
      "parameters": {
        "jsCode": "// Parse and validate the refined queries\nconst rawOutput = $json;\nlet queries = {};\n\ntry {\n  let outputText = rawOutput.output || rawOutput;\n  \n  if (typeof outputText === 'string') {\n    const jsonMatch = outputText.match(/```json\\s*([\\s\\S]*?)\\s*```/) ||\n                     outputText.match(/```\\s*([\\s\\S]*?)\\s*```/) ||\n                     [null, outputText];\n    queries = JSON.parse((jsonMatch[1] || outputText).trim());\n  } else {\n    queries = outputText;\n  }\n} catch (error) {\n  console.error('Parse error:', error);\n  const userTopic = $('Submit Your Topic').item.json.chatInput || 'Business Growth';\n  queries = {\n    originalTopic: userTopic,\n    refinedTopic: userTopic,\n    articleAngle: 'Comprehensive analysis',\n    targetReader: 'B2B founders and leaders',\n    strategicQueries: [\n      { queryId: 'q1', query: `Current state of ${userTopic}`, purpose: 'Market context', sectionItFeeds: 'Market Overview', searchTerms: [userTopic] },\n      { queryId: 'q2', query: `Biggest challenges in ${userTopic}`, purpose: 'Problem analysis', sectionItFeeds: 'The Problem', searchTerms: [userTopic, 'challenges'] },\n      { queryId: 'q3', query: `Best practices for ${userTopic}`, purpose: 'Solutions', sectionItFeeds: 'The Framework', searchTerms: [userTopic, 'best practices'] },\n      { queryId: 'q4', query: `Case studies in ${userTopic}`, purpose: 'Proof', sectionItFeeds: 'Proof & Case Studies', searchTerms: [userTopic, 'case study'] },\n      { queryId: 'q5', query: `Future of ${userTopic}`, purpose: 'Predictions', sectionItFeeds: 'Future Outlook', searchTerms: [userTopic, 'trends 2025'] }\n    ],\n    proposedTitle: `The Ultimate Guide to ${userTopic}`,\n    proposedSubtitle: 'Everything you need to know',\n    keyInsightToProve: `Why ${userTopic} matters now more than ever`,\n    competitiveEdge: 'Data-driven with actionable frameworks'\n  };\n}\n\nqueries.strategicQueries = Array.isArray(queries.strategicQueries) ? queries.strategicQueries : [];\nqueries.briefId = `LM-${Date.now().toString(36).toUpperCase()}`;\nqueries.createdAt = new Date().toISOString();\n\n// \u26a0\ufe0f UPDATE THIS: Replace with your name\nqueries.authorName = 'YOUR_AUTHOR_NAME';\nconst now = new Date();\nqueries.formattedDate = now.toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' });\nqueries.formattedDateTime = now.toLocaleString('en-US', { month: 'long', day: 'numeric', year: 'numeric', hour: 'numeric', minute: '2-digit', hour12: true });\n\nreturn { json: queries };"
      },
      "typeVersion": 2
    },
    {
      "id": "5eaa1623-3220-4524-a69f-b991e397fa33",
      "name": "Split into 5 Research Tasks",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        544,
        736
      ],
      "parameters": {
        "options": {
          "destinationFieldName": "query"
        },
        "fieldToSplitOut": "strategicQueries"
      },
      "typeVersion": 1
    },
    {
      "id": "83517161-f82f-4afe-bf80-da76a356f815",
      "name": "Deep Web Researcher",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        768,
        736
      ],
      "parameters": {
        "text": "=Conduct deep research on this specific query for a B2B lead magnet article.\n\nQuery ID: {{ $json.query.queryId }}\nResearch Query: {{ $json.query.query }}\nPurpose: {{ $json.query.purpose }}\nSection It Feeds: {{ $json.query.sectionItFeeds }}\nSearch Terms: {{ $json.query.searchTerms.join(', ') }}\n\nOverall Topic: {{ $json.refinedTopic }}\nAngle: {{ $json.articleAngle }}\nTarget Reader: {{ $json.targetReader }}\nKey Insight to Prove: {{ $json.keyInsightToProve }}",
        "options": {
          "systemMessage": "You are a Deep Research Specialist for B2B thought leadership content.\n\nYour job is to conduct thorough research on a specific query and produce rich data-driven content for a lead magnet article.\n\nYou are one of 5 parallel research agents. Each handles ONE query. Your output will be compiled with others into a complete article.\n\nReturn ONLY valid JSON:\n\n{\n  \"queryId\": \"q1\",\n  \"sectionTitle\": \"Clear compelling section title\",\n  \"sectionContent\": \"Full section content in markdown. 400-600 words. Include subheadings using ###, bullet points, bold text, and data. Write in an authoritative but accessible tone for LinkedIn readers.\",\n  \"keyStats\": [\n    {\"stat\": \"73% of B2B buyers...\", \"source\": \"Gartner 2024\"},\n    {\"stat\": \"$4.2 trillion market...\", \"source\": \"McKinsey Report\"}\n  ],\n  \"quotableInsight\": \"One powerful sentence that could be pulled as a LinkedIn quote\",\n  \"examples\": [\n    {\"company\": \"Company Name\", \"result\": \"What they achieved\", \"relevance\": \"Why it matters\"}\n  ],\n  \"actionableFramework\": {\n    \"name\": \"Framework name if applicable\",\n    \"steps\": [\"Step 1\", \"Step 2\", \"Step 3\"]\n  },\n  \"linkedInHooks\": [\"Hook 1 for this section\", \"Hook 2\"],\n  \"sources\": [\n    {\"title\": \"Source title\", \"url\": \"https://example.com\", \"year\": \"2024\"}\n  ],\n  \"seoKeywords\": [\"keyword1\", \"keyword2\"],\n  \"wordCount\": 500\n}\n\nWriting Rules:\n1. Write 400-600 words of actual content\n2. Include at least 2-3 specific statistics with sources\n3. Include at least 1 company example\n4. Make it LinkedIn-worthy - punchy insightful shareable\n5. The quotableInsight should be tweetable on its own\n6. Return ONLY valid JSON no extra text\n7. Write like a respected industry thought leader not a textbook"
        },
        "promptType": "define"
      },
      "typeVersion": 2.1
    },
    {
      "id": "082e1c21-bfcd-42eb-8b49-f94c3e550dea",
      "name": "Parse Research Output",
      "type": "n8n-nodes-base.code",
      "position": [
        1120,
        736
      ],
      "parameters": {
        "jsCode": "// Parse individual research output\nconst rawOutput = $json;\nconst taskContext = $input.all()[0].json;\nlet research = {};\n\ntry {\n  let text = rawOutput.output || rawOutput;\n  if (typeof text === 'string') {\n    const jsonMatch = text.match(/```json\\s*([\\s\\S]*?)\\s*```/) ||\n                     text.match(/```\\s*([\\s\\S]*?)\\s*```/) ||\n                     [null, text];\n    research = JSON.parse((jsonMatch[1] || text).trim());\n  } else {\n    research = text;\n  }\n} catch (error) {\n  research = {\n    queryId: taskContext.query?.queryId || 'unknown',\n    sectionTitle: taskContext.query?.sectionItFeeds || 'Research Section',\n    sectionContent: typeof rawOutput.output === 'string' ? rawOutput.output : 'Content pending',\n    keyStats: [],\n    quotableInsight: '',\n    examples: [],\n    actionableFramework: null,\n    linkedInHooks: [],\n    sources: [],\n    seoKeywords: [],\n    wordCount: 0\n  };\n}\n\nresearch.queryId = research.queryId || taskContext.query?.queryId || 'unknown';\nresearch.sectionTitle = research.sectionTitle || taskContext.query?.sectionItFeeds || 'Section';\nresearch.sectionContent = research.sectionContent || '';\nresearch.keyStats = Array.isArray(research.keyStats) ? research.keyStats : [];\nresearch.quotableInsight = research.quotableInsight || '';\nresearch.examples = Array.isArray(research.examples) ? research.examples : [];\nresearch.linkedInHooks = Array.isArray(research.linkedInHooks) ? research.linkedInHooks : [];\nresearch.sources = Array.isArray(research.sources) ? research.sources : [];\nresearch.seoKeywords = Array.isArray(research.seoKeywords) ? research.seoKeywords : [];\nresearch.wordCount = (research.sectionContent || '').split(/\\s+/).length;\nresearch.processedAt = new Date().toISOString();\nresearch.refinedTopic = taskContext.refinedTopic;\nresearch.briefId = taskContext.briefId;\nresearch.proposedTitle = taskContext.proposedTitle;\nresearch.targetReader = taskContext.targetReader;\nresearch.articleAngle = taskContext.articleAngle;\nresearch.authorName = taskContext.authorName;\nresearch.formattedDate = taskContext.formattedDate;\nresearch.formattedDateTime = taskContext.formattedDateTime;\n\nreturn { json: research };"
      },
      "typeVersion": 2
    },
    {
      "id": "ec8f0ab9-7dff-443f-a74f-eb3e59e20b04",
      "name": "Build TOC and Compile Research",
      "type": "n8n-nodes-base.code",
      "position": [
        1568,
        736
      ],
      "parameters": {
        "jsCode": "// Compile all research into structured content\nconst allItems = $input.all();\nconst results = allItems.map(item => item.json);\n\n// Sort by queryId\nresults.sort((a, b) => {\n  const aNum = parseInt((a.queryId || '0').replace(/\\D/g, '')) || 0;\n  const bNum = parseInt((b.queryId || '0').replace(/\\D/g, '')) || 0;\n  return aNum - bNum;\n});\n\n// Build Table of Contents\nconst toc = results.map((r, i) => `${i + 1}. ${r.sectionTitle}`);\n\n// Compile sections\nconst sections = results.map(r => ({\n  queryId: r.queryId,\n  title: r.sectionTitle,\n  content: r.sectionContent,\n  keyStats: r.keyStats || [],\n  quotableInsight: r.quotableInsight || '',\n  examples: r.examples || [],\n  framework: r.actionableFramework,\n  hooks: r.linkedInHooks || [],\n  sources: r.sources || [],\n  seoKeywords: r.seoKeywords || [],\n  wordCount: (r.sectionContent || '').split(/\\s+/).length\n}));\n\n// Aggregate all data\nconst allStats = sections.flatMap(s => s.keyStats);\nconst allHooks = sections.flatMap(s => s.hooks);\nconst allSources = sections.flatMap(s => s.sources);\nconst allKeywords = [...new Set(sections.flatMap(s => s.seoKeywords))];\nconst allQuotes = sections.map(s => s.quotableInsight).filter(q => q);\nconst totalWords = sections.reduce((sum, s) => sum + s.wordCount, 0);\n\nconst refinedTopic = results[0]?.refinedTopic || 'Research Report';\nconst briefId = results[0]?.briefId || 'N/A';\nconst proposedTitle = results[0]?.proposedTitle || refinedTopic;\nconst targetReader = results[0]?.targetReader || 'B2B Leaders';\nconst articleAngle = results[0]?.articleAngle || 'Comprehensive analysis';\nconst authorName = results[0]?.authorName || 'YOUR_AUTHOR_NAME';\nconst formattedDate = results[0]?.formattedDate || new Date().toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' });\nconst formattedDateTime = results[0]?.formattedDateTime || new Date().toLocaleString('en-US', { month: 'long', day: 'numeric', year: 'numeric', hour: 'numeric', minute: '2-digit', hour12: true });\n\nconst compiled = {\n  refinedTopic,\n  briefId,\n  proposedTitle,\n  targetReader,\n  articleAngle,\n  authorName,\n  formattedDate,\n  formattedDateTime,\n  tableOfContents: toc,\n  sections,\n  allStats,\n  allHooks,\n  allQuotes,\n  allSources,\n  allKeywords,\n  totalWordCount: totalWords,\n  sectionCount: sections.length,\n  sourceCount: allSources.length,\n  compiledAt: new Date().toISOString(),\n  fullResearchContent: sections.map(s => `\n## ${s.title}\n\n${s.content}\n\n${s.quotableInsight ? '> ' + s.quotableInsight + '\\n\\n' : ''}\n  `).join('\\n---\\n\\n')\n};\n\nreturn { json: compiled };"
      },
      "typeVersion": 2
    },
    {
      "id": "ef31a5e3-3b93-481f-8e8d-48cfe0b51942",
      "name": "Final Editor and Polish",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1792,
        736
      ],
      "parameters": {
        "text": "=Write a complete LinkedIn-ready lead magnet article.\n\nAuthor: {{ $json.authorName }}\nDate: {{ $json.formattedDate }}\nTopic: {{ $json.refinedTopic }}\nTitle: {{ $json.proposedTitle }}\nAngle: {{ $json.articleAngle }}\nTarget: {{ $json.targetReader }}\n\nResearch:\n{{ $json.fullResearchContent }}\n\nStats:\n{{ $json.allStats.map(s => s.stat + ' - ' + s.source).join('\\n') }}\n\nSources:\n{{ $json.allSources.map(s => s.title).join('\\n') }}",
        "options": {
          "systemMessage": "You are an expert B2B content writer.\n\nWrite ONLY the article content. Do NOT include:\n- Any thinking or planning text\n- Phrases like \"The user wants\" or \"Let me analyze\"\n- Meta-commentary about the writing process\n\nSTART IMMEDIATELY with the title.\n\nUse this EXACT structure (plain text, no markdown symbols):\n\n[Title]\n\n[Subtitle]\n\nBy [Author] | [Date]\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nTHE BIG IDEA\n\n[2-3 compelling paragraphs with a provocative stat]\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nTABLE OF CONTENTS\n\n[List 5 chapters]\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nCHAPTER 1: [TITLE]\n\n[Content with paragraphs. Mark important stats and company names with {BOLD}text{/BOLD} tags. Mark section headings with {H3}heading{/H3} tags.]\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\n[Repeat for chapters 2-5]\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nKEY TAKEAWAYS\n\n\u2022 [Takeaway 1]\n\u2022 [Takeaway 2]\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nWHAT TO DO NEXT\n\n1. [Action 1]\n2. [Action 2]\n3. [Action 3]\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nABOUT THE AUTHOR\n\n[Bio for author]\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nSOURCES AND REFERENCES\n\n[Numbered list]\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\n[CTA]\n\nRULES:\n1. Start with the title - NO thinking text\n2. Length: 2500-4000 words\n3. Include ALL research and statistics\n4. Mark text to be bold with {BOLD}text{/BOLD}\n5. Mark subheadings with {H3}heading{/H3}\n6. Use current date not February 2026\n7. Plain text output - formatting tags will be processed later\n\nWrite the article now:"
        },
        "promptType": "define"
      },
      "typeVersion": 2.1
    },
    {
      "id": "7d77d794-1c2d-4818-a271-fb38a0a85753",
      "name": "Prepare Document Content",
      "type": "n8n-nodes-base.code",
      "position": [
        2144,
        736
      ],
      "parameters": {
        "jsCode": "// Clean and prepare article with formatting markers\nconst editorOutput = $json;\nconst compiledData = $node['Build TOC and Compile Research'].json;\nconst queryData = $node['Validate Queries'].json;\n\nlet articleText = '';\nif (typeof editorOutput.output === 'string') {\n  articleText = editorOutput.output;\n} else if (typeof editorOutput === 'string') {\n  articleText = editorOutput;\n} else {\n  articleText = JSON.stringify(editorOutput, null, 2);\n}\n\n// Remove AI thinking text - find first real content line\nconst lines = articleText.split('\\n');\nlet startIndex = 0;\nfor (let i = 0; i < lines.length; i++) {\n  const line = lines[i].trim().toLowerCase();\n  if (line.includes('the user wants') || \n      line.includes('let me analyze') ||\n      line.includes('looking at') ||\n      line.includes('i need to') ||\n      line.includes('i\\'ll create')) {\n    continue;\n  }\n  if (lines[i].trim().length > 20 && !line.startsWith('by ') && !line.includes('author')) {\n    startIndex = i;\n    break;\n  }\n}\n\narticleText = lines.slice(startIndex).join('\\n');\n\n// Clean up markdown and fix dates\narticleText = articleText\n  .replace(/```[a-z]*\\s*/g, '')\n  .replace(/#{1,6}\\s+/g, '')\n  .replace(/\\*\\*([^*]+)\\*\\*/g, '{BOLD}$1{/BOLD}')\n  .replace(/February 2026/gi, compiledData.formattedDate)\n  .replace(/January 2025/gi, compiledData.formattedDate)\n  .replace(/\\x00/g, '')\n  .replace(/[\\u2018\\u2019]/g, \"'\")\n  .replace(/[\\u201C\\u201D]/g, '\"')\n  .trim();\n\nconst docTitle = queryData.proposedTitle || `Lead Magnet: ${compiledData.refinedTopic}`;\n\nreturn {\n  json: {\n    documentTitle: docTitle,\n    articleContent: articleText,\n    refinedTopic: compiledData.refinedTopic,\n    proposedTitle: queryData.proposedTitle || docTitle,\n    proposedSubtitle: queryData.proposedSubtitle || '',\n    articleAngle: queryData.articleAngle || '',\n    targetReader: compiledData.targetReader || 'B2B Leaders',\n    authorName: compiledData.authorName || 'YOUR_AUTHOR_NAME',\n    formattedDate: compiledData.formattedDate,\n    briefId: compiledData.briefId,\n    totalWordCount: compiledData.totalWordCount,\n    sectionCount: compiledData.sectionCount,\n    sourceCount: compiledData.sourceCount,\n    seoKeywords: compiledData.allKeywords || [],\n    linkedInHooks: compiledData.allHooks || [],\n    quotableInsights: compiledData.allQuotes || [],\n    generatedAt: new Date().toISOString()\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "9d954276-045f-4c05-a8ec-9493873ce98b",
      "name": "Create Google Doc",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2368,
        736
      ],
      "parameters": {
        "url": "https://docs.googleapis.com/v1/documents",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"title\": \"{{ $json.documentTitle }}\"\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "googleDocsOAuth2Api"
      },
      "typeVersion": 4.2
    },
    {
      "id": "4096dc3e-4c0e-433a-b1fa-e362f89b5485",
      "name": "Extract Doc ID",
      "type": "n8n-nodes-base.code",
      "position": [
        2592,
        736
      ],
      "parameters": {
        "jsCode": "const createResponse = $json;\nconst documentId = createResponse.documentId;\nconst documentUrl = `https://docs.google.com/document/d/${documentId}/edit`;\n\nif (!documentId) {\n  throw new Error('Failed to create Google Doc');\n}\n\nreturn {\n  json: {\n    documentId: documentId,\n    documentUrl: documentUrl\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "a6ed5aef-b453-4224-99d8-fc9f8664db5e",
      "name": "Build Format Requests",
      "type": "n8n-nodes-base.code",
      "position": [
        2816,
        736
      ],
      "parameters": {
        "jsCode": "// Build Google Docs API formatting requests\nconst docData = $('Prepare Document Content').item.json;\nconst articleText = docData.articleContent;\n\n// Parse text and build formatting requests\nconst requests = [];\nlet currentIndex = 1;\nconst lines = articleText.split('\\n');\nlet fullText = '';\nconst formatRanges = [];\n\nfor (let i = 0; i < lines.length; i++) {\n  const line = lines[i];\n  \n  // Track bold text\n  const boldMatches = [...line.matchAll(/\\{BOLD\\}(.*?)\\{\\/BOLD\\}/g)];\n  for (const match of boldMatches) {\n    const cleanedLine = line.replace(/\\{BOLD\\}|\\{\\/BOLD\\}/g, '');\n    const textBefore = cleanedLine.substring(0, cleanedLine.indexOf(match[1]));\n    const startIdx = currentIndex + fullText.length + textBefore.length;\n    formatRanges.push({\n      type: 'bold',\n      start: startIdx,\n      end: startIdx + match[1].length\n    });\n  }\n  \n  // Track H3 headings\n  const h3Match = line.match(/\\{H3\\}(.*?)\\{\\/H3\\}/);\n  if (h3Match) {\n    const cleanedLine = line.replace(/\\{H3\\}|\\{\\/H3\\}/g, '');\n    formatRanges.push({\n      type: 'heading3',\n      start: currentIndex + fullText.length,\n      end: currentIndex + fullText.length + cleanedLine.length\n    });\n  }\n  \n  // Add cleaned text\n  const cleanLine = line.replace(/\\{BOLD\\}|\\{\\/BOLD\\}|\\{H3\\}|\\{\\/H3\\}/g, '');\n  fullText += cleanLine + '\\n';\n}\n\n// Insert text first\nrequests.push({\n  insertText: {\n    location: { index: 1 },\n    text: fullText\n  }\n});\n\n// Then apply formatting (in reverse order to maintain indices)\nformatRanges.reverse().forEach(range => {\n  if (range.type === 'bold') {\n    requests.push({\n      updateTextStyle: {\n        range: {\n          startIndex: range.start,\n          endIndex: range.end\n        },\n        textStyle: {\n          bold: true\n        },\n        fields: 'bold'\n      }\n    });\n  } else if (range.type === 'heading3') {\n    requests.push({\n      updateParagraphStyle: {\n        range: {\n          startIndex: range.start,\n          endIndex: range.end\n        },\n        paragraphStyle: {\n          namedStyleType: 'HEADING_3'\n        },\n        fields: 'namedStyleType'\n      }\n    });\n  }\n});\n\nreturn {\n  json: {\n    documentId: $json.documentId,\n    requests: requests\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "50243f02-0191-4caa-a1c0-9f45e5b608ba",
      "name": "Apply Formatting to Doc",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        3040,
        736
      ],
      "parameters": {
        "url": "=https://docs.googleapis.com/v1/documents/{{ $json.documentId }}:batchUpdate",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify({ requests: $json.requests }) }}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "googleDocsOAuth2Api"
      },
      "typeVersion": 4.2
    },
    {
      "id": "70830e27-a8ec-47bf-a394-e32ccb1a5c8f",
      "name": "Make Doc Shareable",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        3264,
        736
      ],
      "parameters": {
        "url": "=https://www.googleapis.com/drive/v3/files/{{ $('Extract Doc ID').item.json.documentId }}/permissions",
        "method": "POST",
        "options": {},
        "jsonBody": "{\n  \"role\": \"reader\",\n  \"type\": \"anyone\"\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "googleDriveOAuth2Api"
      },
      "typeVersion": 4.2
    },
    {
      "id": "bc1d0fe2-b818-4ef9-b29e-c7d98330d9ff",
      "name": "Generate Chat Response",
      "type": "n8n-nodes-base.code",
      "position": [
        3488,
        736
      ],
      "parameters": {
        "jsCode": "const docId = $('Extract Doc ID').item.json.documentId;\nconst docData = $('Prepare Document Content').item.json;\n\nconst editUrl = `https://docs.google.com/document/d/${docId}/edit?usp=sharing`;\nconst viewUrl = `https://docs.google.com/document/d/${docId}/preview`;\nconst pdfUrl = `https://docs.google.com/document/d/${docId}/export?format=pdf`;\n\nconst linkedInPreview = docData.linkedInHooks && docData.linkedInHooks.length > 0 \n  ? docData.linkedInHooks[0] \n  : `Check out my latest research on ${docData.refinedTopic}`;\n\nconst wordCount = docData.totalWordCount;\nconst readTime = Math.ceil(wordCount / 200);\n\nconst chatMessage = `Your Lead Magnet is Ready!\\n\\nTitle: ${docData.proposedTitle}\\nAuthor: ${docData.authorName}\\nDate: ${docData.formattedDate}\\nAngle: ${docData.articleAngle}\\nTarget Reader: ${docData.targetReader}\\n\\nArticle Statistics:\\n- Word Count: ${wordCount.toLocaleString()} words\\n- Reading Time: ~${readTime} minutes\\n- Sections: ${docData.sectionCount} chapters\\n- Sources: ${docData.sourceCount} references\\n- Brief ID: ${docData.briefId}\\n\\nAccess Your Document:\\n- Edit: ${editUrl}\\n- View: ${viewUrl}\\n- Download PDF: ${pdfUrl}\\n\\nTop Quotable Insights:\\n${docData.quotableInsights.slice(0, 3).map((q, i) => `${i + 1}. \"${q}\"`).join('\\n')}\\n\\nSEO Keywords: ${docData.seoKeywords.slice(0, 10).join(' | ')}\\n\\nLinkedIn Post Hook:\\n${linkedInPreview}\\n\\nNext Steps:\\n1. Open the Google Doc and review\\n2. Important text is already bold\\n3. Headings are already formatted\\n4. Add your brand styling (fonts, colors, logo)\\n5. Publish to LinkedIn Articles or your blog\\n6. Share the PDF as a downloadable lead magnet`;\n\nreturn {\n  json: {\n    output: chatMessage,\n    status: 'success',\n    documentTitle: docData.proposedTitle,\n    authorName: docData.authorName,\n    publicationDate: docData.formattedDate,\n    editUrl: editUrl,\n    viewUrl: viewUrl,\n    pdfUrl: pdfUrl,\n    topic: docData.refinedTopic,\n    title: docData.proposedTitle,\n    subtitle: docData.proposedSubtitle,\n    angle: docData.articleAngle,\n    targetReader: docData.targetReader,\n    briefId: docData.briefId,\n    generatedAt: docData.generatedAt,\n    stats: {\n      wordCount: wordCount,\n      readTime: readTime,\n      sections: docData.sectionCount,\n      sources: docData.sourceCount,\n      seoKeywords: (docData.seoKeywords || []).length\n    },\n    linkedInPostPreview: linkedInPreview,\n    quotableInsights: docData.quotableInsights || [],\n    seoKeywords: docData.seoKeywords || []\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "dc0e8a8c-920c-45b8-831d-cfecf998b6d6",
      "name": "Log to Tracking Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3488,
        528
      ],
      "parameters": {
        "columns": {
          "value": {},
          "schema": [],
          "mappingMode": "autoMapInputData",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "url",
          "value": "YOUR_GOOGLE_SHEET_URL"
        },
        "documentId": {
          "__rl": true,
          "mode": "url",
          "value": "YOUR_GOOGLE_SHEET_URL"
        }
      },
      "typeVersion": 4.6
    },
    {
      "id": "05c40466-e05c-4b92-a1f3-f69690558353",
      "name": "Ollama Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOllama",
      "position": [
        768,
        1120
      ],
      "parameters": {
        "model": "YOUR_MODEL_NAME",
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "46c462e3-59d0-4b92-8951-99de86ba24b6",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1136,
        -240
      ],
      "parameters": {
        "color": "#96AB49",
        "width": 860,
        "height": 722,
        "content": "## Generate B2B lead magnet articles with AI deep research to Google Docs\n\nThis workflow transforms any topic into a comprehensive, research-backed B2B lead magnet article \u2014 automatically saved as a formatted Google Doc.\n\n## How it works\n1. **Submit a topic** via the chat trigger\n2. **AI generates 5 strategic research queries** covering market context, pain points, frameworks, case studies, and future trends\n3. **5 parallel research agents** each produce 400\u2013600 words of data-rich content\n4. **Research is compiled** into a structured article with TOC, stats, and sources\n5. **A writing agent** produces the final 2,500\u20134,000 word article\n6. **Output is saved** as a formatted Google Doc with bold text and headings\n7. **Article metadata** is logged to a Google Sheet for tracking\n\n## Setup steps\n1. Configure your **Ollama credentials** (or swap for OpenAI / Anthropic / Gemini)\n2. Connect **Google Docs OAuth2** credentials\n3. Connect **Google Drive OAuth2** credentials\n4. Connect **Google Sheets OAuth2** and update the sheet URL in the \"Log to Tracking Sheet\" node\n5. In the \"Validate Queries\" Code node, replace `YOUR_AUTHOR_NAME` with your name\n6. Activate the workflow and open the chat trigger URL\n\n## Customization\n- Swap the LLM model to any LangChain-compatible provider\n- Adjust word count targets in agent system prompts\n- Modify the article structure in the \"Final Editor and Polish\" prompt\n- Add downstream nodes for email delivery, CMS posting, or Slack notifications"
      },
      "typeVersion": 1
    },
    {
      "id": "4b304f68-6260-452d-82d9-3c5785244009",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -112,
        528
      ],
      "parameters": {
        "color": "#382E2E",
        "width": 280,
        "height": 152,
        "content": "## 1. Topic Refinement\nUser submits a topic via chat. AI refines it into 5 strategic research queries with SEO terms, angles, and target personas."
      },
      "typeVersion": 1
    },
    {
      "id": "c4ee28ba-eb4a-461a-b165-984130559a7f",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        688,
        496
      ],
      "parameters": {
        "color": "#382E2E",
        "width": 316,
        "height": 200,
        "content": "## 2. Parallel Deep Research\nEach of the 5 queries is researched independently by an AI agent, producing stats, examples, frameworks, and quotable insights (400\u2013600 words each)."
      },
      "typeVersion": 1
    },
    {
      "id": "79c74b31-76fc-4317-861d-4ee2b2fb5811",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1584,
        480
      ],
      "parameters": {
        "color": "#382E2E",
        "width": 324,
        "height": 216,
        "content": "## 3. Compile & Write Final Article\nAll research is merged into a structured document. A writing agent produces the complete 2,500\u20134,000 word lead magnet with formatting tags."
      },
      "typeVersion": 1
    },
    {
      "id": "3eba0d7e-ff43-48aa-9270-a7c01046755e",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2512,
        464
      ],
      "parameters": {
        "color": "#382E2E",
        "width": 392,
        "height": 184,
        "content": "## 4. Format & Publish to Google Docs\nArticle is created as a Google Doc via API. Bold text and headings are applied programmatically. Public sharing is enabled automatically."
      },
      "typeVersion": 1
    },
    {
      "id": "fea65222-8fba-4e64-82e9-6ae4cf3c0833",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3424,
        320
      ],
      "parameters": {
        "color": "#382E2E",
        "width": 256,
        "height": 152,
        "content": "## 5. Deliver & Track\nReturns edit, view, and PDF download links to the user via chat. Logs article metadata to Google Sheets for tracking."
      },
      "typeVersion": 1
    },
    {
      "id": "6c07bfbd-8128-4ed4-befe-60083519941f",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        80,
        1104
      ],
      "parameters": {
        "color": 3,
        "width": 320,
        "height": 80,
        "content": "\u26a0\ufe0f **Update YOUR_AUTHOR_NAME** in this Code node to your actual name before running the workflow."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "6c541177-c679-4389-92cb-4be870e7d321",
  "connections": {
    "Extract Doc ID": {
      "main": [
        [
          {
            "node": "Build Format Requests",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Queries": {
      "main": [
        [
          {
            "node": "Split into 5 Research Tasks",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Google Doc": {
      "main": [
        [
          {
            "node": "Extract Doc ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Ollama Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Refine into 5 Strategic Queries",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "Deep Web Researcher",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "Final Editor and Polish",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Submit Your Topic": {
      "main": [
        [
          {
            "node": "Refine into 5 Strategic Queries",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Make Doc Shareable": {
      "main": [
        [
          {
            "node": "Generate Chat Response",
            "type": "main",
            "index": 0
          },
          {
            "node": "Log to Tracking Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Deep Web Researcher": {
      "main": [
        [
          {
            "node": "Parse Research Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Format Requests": {
      "main": [
        [
          {
            "node": "Apply Formatting to Doc",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Research Output": {
      "main": [
        [
          {
            "node": "Build TOC and Compile Research",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Apply Formatting to Doc": {
      "main": [
        [
          {
            "node": "Make Doc Shareable",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Final Editor and Polish": {
      "main": [
        [
          {
            "node": "Prepare Document Content",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Document Content": {
      "main": [
        [
          {
            "node": "Create Google Doc",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split into 5 Research Tasks": {
      "main": [
        [
          {
            "node": "Deep Web Researcher",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build TOC and Compile Research": {
      "main": [
        [
          {
            "node": "Final Editor and Polish",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Refine into 5 Strategic Queries": {
      "main": [
        [
          {
            "node": "Validate Queries",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow is built for B2B marketers, consultants, founders, and agency owners who need to produce high-quality, research-backed thought leadership content — without spending hours on research and writing.

Source: https://n8n.io/workflows/13835/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

This comprehensive workflow automates the complete financial document processing pipeline using AI. Upload invoices via chat, drop expense receipts into a folder, or add bank statements - the system a

Chat Trigger, HTTP Request, Google Sheets +8
AI & RAG

Who’s it for Creators who want to create faceless videos automatically, while keeping human oversight and quality control.

Read Write File, Agent, OpenAI Chat +7
AI & RAG

The Best Linkedin Posting System. Uses httpRequest, lmChatOpenAi, agent, chatTrigger. Chat trigger; 49 nodes.

HTTP Request, OpenAI Chat, Agent +8
AI & RAG

Who is this workflow for? This workflow is designed for SEO analysts, content creators, marketing agencies, and developers who need to index a website and then interact with its content as if it were

Agent, OpenAI Chat, Memory Buffer Window +10
AI & RAG

This project is an automation workflow that generates a personalized resume and cover letter for each job listing. Generates an HTML resume from your data. Hosts it live on GitHub Pages. Converts it t

HTTP Request, Agent, OpenAI Chat +10