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
- n8n instance (cloud or self-hosted)
- OpenAI API key with GPT-4 access
- Google Sheets or Airtable account (for content brief storage)
- Gmail account (for notifications)
Prerequisites
- Basic understanding of n8n workflows
- Content brief template with fields: target keyword, audience, tone, word count, key points
- Familiarity with AI prompt engineering concepts
Setup Requirements
- Configure OpenAI credentials in n8n
- Set up Google Sheets/Airtable with content brief structure
- Create email templates for notifications
Complete Node-by-Node Build Instructions
Node 1: Google Sheets Trigger
- Add a “Google Sheets” trigger node
- Configure authentication with your Google account
- Select “On Row Added” as the trigger event
- Choose your content briefs spreadsheet
- Set the worksheet containing your briefs
- Test the connection to ensure proper data retrieval
Node 2: Data Validation
- Add a “Code” node after the trigger
- Name it “Validate Brief Data”
- 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
- Add an “OpenAI” node
- Select “Chat” operation
- Configure the model as “gpt-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
- Add another “OpenAI” node
- Name it “Generate Introduction”
- 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
- Add an “OpenAI” node named “Generate Main Content”
- Set a higher max_tokens value (2000-3000)
- 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
- Add an “OpenAI” node named “Generate Conclusion”
- 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
- Add a “Code” node named “Combine Full Post”
- 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
- Add a “Google Sheets” node
- Set operation to “Update”
- Configure to update the same row that triggered the workflow
- Map the generated content to appropriate columns
- Add a “Status” column update to mark as “Complete”
Node 9: Send Notification Email
- Add a “Gmail” node
- Set operation to “Send Email”
- Configure recipient email
- 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
- Add an “IF” node after validation
- Connect error paths to a “Gmail” node
- Configure error notification email
- 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": [
[
{