Home/ Workflows/ Copywriters/ Content Creation
Workflow · Copywriters

AI Content Brief to Blog Post Workflow

Automate the transformation of content briefs into full blog posts using AI, streamlining your copywriting workflow from concept to publication-ready content.

AI Content Brief to Blog Post Workflow

Why This Automation Matters

As a copywriter, you know that transforming a basic content brief into a comprehensive, engaging blog post can be time-consuming and repetitive. This n8n workflow automates the entire process, taking your content briefs and using AI to generate well-structured, SEO-optimized blog posts complete with headlines, subheadings, and calls-to-action.

This automation eliminates hours of manual writing work, ensures consistent quality across all your content, and allows you to focus on strategy and refinement rather than first-draft creation. Perfect for agencies handling multiple clients or solo copywriters looking to scale their output.

What You Need Before Starting

Required Tools & Accounts

Prerequisites

Setup Requirements

Complete Node-by-Node Build Instructions

Node 1: Google Sheets Trigger

  1. Add a “Google Sheets” trigger node
  2. Configure authentication with your Google account
  3. Select “On Row Added” as the trigger event
  4. Choose your content briefs spreadsheet
  5. Set the worksheet containing your briefs
  6. Test the connection to ensure proper data retrieval

Node 2: Data Validation

  1. Add a “Code” node after the trigger
  2. Name it “Validate Brief Data”
  3. Insert validation logic to check required fields:
    if (!$input.first().json.target_keyword || !$input.first().json.audience) {
      throw new Error('Missing required brief data');
    }
    return $input.all();

Node 3: Generate Blog Outline

  1. Add an “OpenAI” node
  2. Select “Chat” operation
  3. Configure the model as “gpt-4”
  4. Set the prompt:
    Create a detailed blog post outline for:
    Target Keyword: {{$node["Google Sheets Trigger"].json["target_keyword"]}}
    Audience: {{$node["Google Sheets Trigger"].json["audience"]}}
    Tone: {{$node["Google Sheets Trigger"].json["tone"]}}
    Key Points: {{$node["Google Sheets Trigger"].json["key_points"]}}
    
    Include: SEO title, meta description, H1, H2s, H3s, and conclusion structure.

Node 4: Generate Introduction

  1. Add another “OpenAI” node
  2. Name it “Generate Introduction”
  3. Use the outline from the previous node:
    Based on this outline: {{$node["Generate Blog Outline"].json.choices[0].message.content}}
    
    Write an engaging introduction (150-200 words) that:
    - Hooks the reader immediately
    - Introduces the main topic
    - Previews what they'll learn
    - Matches the {{$node["Google Sheets Trigger"].json["tone"]}} tone

Node 5: Generate Main Content

  1. Add an “OpenAI” node named “Generate Main Content”
  2. Set a higher max_tokens value (2000-3000)
  3. Create the prompt:
    Using this outline: {{$node["Generate Blog Outline"].json.choices[0].message.content}}
    And this introduction: {{$node["Generate Introduction"].json.choices[0].message.content}}
    
    Write the main body content covering all H2 and H3 sections. 
    Target length: {{$node["Google Sheets Trigger"].json["word_count"]}} words
    Include practical examples and actionable advice.
    Maintain {{$node["Google Sheets Trigger"].json["tone"]}} tone throughout.

Node 6: Generate Conclusion & CTA

  1. Add an “OpenAI” node named “Generate Conclusion”
  2. Configure the prompt:
    Based on this blog post content:
    {{$node["Generate Main Content"].json.choices[0].message.content}}
    
    Write a compelling conclusion (100-150 words) that:
    - Summarizes key takeaways
    - Includes a clear call-to-action
    - Encourages engagement

Node 7: Combine Content

  1. Add a “Code” node named “Combine Full Post”
  2. Insert code to merge all content sections:
    const outline = $node["Generate Blog Outline"].json.choices[0].message.content;
    const intro = $node["Generate Introduction"].json.choices[0].message.content;
    const mainContent = $node["Generate Main Content"].json.choices[0].message.content;
    const conclusion = $node["Generate Conclusion"].json.choices[0].message.content;
    
    const fullPost = {
      outline: outline,
      introduction: intro,
      mainContent: mainContent,
      conclusion: conclusion,
      fullBlogPost: intro + "\n\n" + mainContent + "\n\n" + conclusion,
      wordCount: (intro + mainContent + conclusion).split(' ').length,
      targetKeyword: $node["Google Sheets Trigger"].json["target_keyword"]
    };
    
    return [{ json: fullPost }];

Node 8: Update Spreadsheet

  1. Add a “Google Sheets” node
  2. Set operation to “Update”
  3. Configure to update the same row that triggered the workflow
  4. Map the generated content to appropriate columns
  5. Add a “Status” column update to mark as “Complete”

Node 9: Send Notification Email

  1. Add a “Gmail” node
  2. Set operation to “Send Email”
  3. Configure recipient email
  4. Create email template:
    Subject: Blog Post Generated: {{$node["Google Sheets Trigger"].json["target_keyword"]}}
    
    Your blog post has been generated successfully!
    
    Target Keyword: {{$node["Google Sheets Trigger"].json["target_keyword"]}}
    Word Count: {{$node["Combine Full Post"].json["wordCount"]}}
    
    Check your spreadsheet for the complete content.

Node 10: Error Handling

  1. Add an “IF” node after validation
  2. Connect error paths to a “Gmail” node
  3. Configure error notification email
  4. Set up retry logic for API failures

Full Workflow JSON Code Block

{
  "name": "AI Content Brief to Blog Post",
  "nodes": [
    {
      "parameters": {
        "operation": "appendOrUpdate",
        "documentId": "your-spreadsheet-id",
        "sheetName": "Content Briefs",
        "columns": {
          "mappingMode": "autoMapInputData",
          "value": {},
          "matchingColumns": [
            "id"
          ],
          "schema": []
        },
        "options": {}
      },
      "id": "google-sheets-trigger",
      "name": "Google Sheets Trigger",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        240,
        300
      ],
      "webhookId": "trigger",
      "typeVersion": 4
    },
    {
      "parameters": {
        "jsCode": "if (!$input.first().json.target_keyword || !$input.first().json.audience) {\n  throw new Error('Missing required brief data');\n}\nreturn $input.all();"
      },
      "id": "validate-data",
      "name": "Validate Brief Data",
      "type": "n8n-nodes-base.code",
      "position": [
        460,
        300
      ],
      "typeVersion": 2
    },
    {
      "parameters": {
        "resource": "chat",
        "model": "gpt-4",
        "messages": {
          "values": [
            {
              "role": "user",
              "content": "Create a detailed blog post outline for:\nTarget Keyword: {{$node[\"Google Sheets Trigger\"].json[\"target_keyword\"]}}\nAudience: {{$node[\"Google Sheets Trigger\"].json[\"audience\"]}}\nTone: {{$node[\"Google Sheets Trigger\"].json[\"tone\"]}}\nKey Points: {{$node[\"Google Sheets Trigger\"].json[\"key_points\"]}}\n\nInclude: SEO title, meta description, H1, H2s, H3s, and conclusion structure."
            }
          ]
        },
        "options": {}
      },
      "id": "generate-outline",
      "name": "Generate Blog Outline",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        680,
        300
      ],
      "typeVersion": 1.3
    },
    {
      "parameters": {
        "resource": "chat",
        "model": "gpt-4",
        "messages": {
          "values": [
            {
              "role": "user",
              "content": "Based on this outline: {{$node[\"Generate Blog Outline\"].json.choices[0].message.content}}\n\nWrite an engaging introduction (150-200 words) that:\n- Hooks the reader immediately\n- Introduces the main topic\n- Previews what they'll learn\n- Matches the {{$node[\"Google Sheets Trigger\"].json[\"tone\"]}} tone"
            }
          ]
        },
        "options": {}
      },
      "id": "generate-intro",
      "name": "Generate Introduction",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        900,
        300
      ],
      "typeVersion": 1.3
    },
    {
      "parameters": {
        "resource": "chat",
        "model": "gpt-4",
        "messages": {
          "values": [
            {
              "role": "user",
              "content": "Using this outline: {{$node[\"Generate Blog Outline\"].json.choices[0].message.content}}\nAnd this introduction: {{$node[\"Generate Introduction\"].json.choices[0].message.content}}\n\nWrite the main body content covering all H2 and H3 sections.\nTarget length: {{$node[\"Google Sheets Trigger\"].json[\"word_count\"]}} words\nInclude practical examples and actionable advice.\nMaintain {{$node[\"Google Sheets Trigger\"].json[\"tone\"]}} tone throughout."
            }
          ]
        },
        "options": {
          "maxTokens": 3000
        }
      },
      "id": "generate-main",
      "name": "Generate Main Content",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        1120,
        300
      ],
      "typeVersion": 1.3
    },
    {
      "parameters": {
        "resource": "chat",
        "model": "gpt-4",
        "messages": {
          "values": [
            {
              "role": "user",
              "content": "Based on this blog post content:\n{{$node[\"Generate Main Content\"].json.choices[0].message.content}}\n\nWrite a compelling conclusion (100-150 words) that:\n- Summarizes key takeaways\n- Includes a clear call-to-action\n- Encourages engagement"
            }
          ]
        },
        "options": {}
      },
      "id": "generate-conclusion",
      "name": "Generate Conclusion",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        1340,
        300
      ],
      "typeVersion": 1.3
    },
    {
      "parameters": {
        "jsCode": "const outline = $node[\"Generate Blog Outline\"].json.choices[0].message.content;\nconst intro = $node[\"Generate Introduction\"].json.choices[0].message.content;\nconst mainContent = $node[\"Generate Main Content\"].json.choices[0].message.content;\nconst conclusion = $node[\"Generate Conclusion\"].json.choices[0].message.content;\n\nconst fullPost = {\n  outline: outline,\n  introduction: intro,\n  mainContent: mainContent,\n  conclusion: conclusion,\n  fullBlogPost: intro + \"\\n\\n\" + mainContent + \"\\n\\n\" + conclusion,\n  wordCount: (intro + mainContent + conclusion).split(' ').length,\n  targetKeyword: $node[\"Google Sheets Trigger\"].json[\"target_keyword\"]\n};\n\nreturn [{ json: fullPost }];"
      },
      "id": "combine-content",
      "name": "Combine Full Post",
      "type": "n8n-nodes-base.code",
      "position": [
        1560,
        300
      ],
      "typeVersion": 2
    },
    {
      "parameters": {
        "operation": "update",
        "documentId": "your-spreadsheet-id",
        "sheetName": "Content Briefs",
        "columnToMatchOn": "id",
        "valueToMatchOn": "={{$node['Google Sheets Trigger'].json['id']}}",
        "fieldsToUpdate": {
          "values": [
            {
              "fieldId": "status",
              "fieldValue": "Complete"
            },
            {
              "fieldId": "generated_content",
              "fieldValue": "={{$node['Combine Full Post'].json['fullBlogPost']}}"
            },
            {
              "fieldId": "word_count",
              "fieldValue": "={{$node['Combine Full Post'].json['wordCount']}}"
            }
          ]
        },
        "options": {}
      },
      "id": "update-spreadsheet",
      "name": "Update Spreadsheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1780,
        300
      ],
      "typeVersion": 4
    },
    {
      "parameters": {
        "sendTo": "your-email@example.com",
        "subject": "Blog Post Generated: {{$node[\"Google Sheets Trigger\"].json[\"target_keyword\"]}}",
        "message": "Your blog post has been generated successfully!\n\nTarget Keyword: {{$node[\"Google Sheets Trigger\"].json[\"target_keyword\"]}}\nWord Count: {{$node[\"Combine Full Post\"].json[\"wordCount\"]}}\n\nCheck your spreadsheet for the complete content.",
        "options": {}
      },
      "id": "send-notification",
      "name": "Send Notification",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2000,
        300
      ],
      "typeVersion": 2.1
    }
  ],
  "connections": {
    "Google Sheets Trigger": {
      "main": [
        [
          {
            "node": "Validate Brief Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Brief Data": {
      "main": [
        [
          {