AutomationFlowsAI & RAG › PDF to Blog Post with AI

PDF to Blog Post with AI

Original n8n title: 📄🛠️pdf2blog

📄🛠️PDF2Blog. Uses stickyNote, formTrigger, extractFromFile, ghost. Event-driven trigger; 12 nodes.

Event trigger★★★★☆ complexityAI-powered12 nodesForm TriggerGhostOpenAI ChatOutput Parser StructuredAgent
AI & RAG Trigger: Event Nodes: 12 Complexity: ★★★★☆ AI nodes: yes Added:

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 →

Download .json
{
  "id": "dMiUunCiaMsCr1Wu",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "\ud83d\udcc4\ud83d\udee0\ufe0fPDF2Blog",
  "tags": [],
  "nodes": [
    {
      "id": "58a4923b-3e8f-4abd-bebc-6488f8b04101",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        580,
        1340
      ],
      "parameters": {
        "color": 3,
        "width": 461,
        "height": 359.27075107113785,
        "content": "## Upload PDF and Extract Text"
      },
      "typeVersion": 1
    },
    {
      "id": "eb0ec98a-9c9d-4203-9586-9e81e23e7232",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1087.027580347215,
        1340
      ],
      "parameters": {
        "color": 4,
        "width": 508.8267597424673,
        "height": 532.0416571599118,
        "content": "## Create Blog Post"
      },
      "typeVersion": 1
    },
    {
      "id": "b2d3cb70-4335-43a2-80db-889559ebf020",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2020,
        1340
      ],
      "parameters": {
        "color": 6,
        "width": 370.4721755771028,
        "height": 352.3823858238478,
        "content": "## Publish Draft Blog Post to Ghost"
      },
      "typeVersion": 1
    },
    {
      "id": "766daeb8-23e8-4ee9-acee-ea2a787bbfda",
      "name": "Upload PDF",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        660,
        1480
      ],
      "parameters": {
        "path": "pdf",
        "options": {},
        "formTitle": "PDF2Blog",
        "formFields": {
          "values": [
            {
              "fieldType": "file",
              "fieldLabel": "Upload PDF File",
              "multipleFiles": false,
              "requiredField": true,
              "acceptFileTypes": ".pdf"
            }
          ]
        },
        "formDescription": "Transform PDFs into captivating blog posts"
      },
      "typeVersion": 2.1
    },
    {
      "id": "055a734e-7128-487a-b109-a64214010bb2",
      "name": "Extract Text",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        860,
        1480
      ],
      "parameters": {
        "options": {},
        "operation": "pdf",
        "binaryPropertyName": "Upload_PDF_File"
      },
      "typeVersion": 1
    },
    {
      "id": "44256745-276a-4c88-80b6-d12a568d07e9",
      "name": "Post to Ghost",
      "type": "n8n-nodes-base.ghost",
      "position": [
        2140,
        1480
      ],
      "parameters": {
        "title": "={{ $json.title }}",
        "source": "adminApi",
        "content": "={{ $json.content }}",
        "operation": "create",
        "additionalFields": {}
      },
      "credentials": {
        "ghostAdminApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "9796d4eb-e9d6-43bb-80c0-c527f3dc8843",
      "name": "gpt-4o-mini",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1180,
        1680
      ],
      "parameters": {
        "model": "gpt-4o-mini-2024-07-18",
        "options": {
          "responseFormat": "json_object"
        }
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "719e7578-df85-441c-8d2f-cb7d3f7bb92f",
      "name": "Structured Output - JSON",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1400,
        1680
      ],
      "parameters": {
        "jsonSchemaExample": "{\n    \"title\": \"title\",\n    \"content\": \"content\"\n}"
      },
      "typeVersion": 1.2
    },
    {
      "id": "5f16e695-3585-468f-8fcb-794f5e3b56d4",
      "name": "Separate Title & Content",
      "type": "n8n-nodes-base.code",
      "position": [
        1660,
        1480
      ],
      "parameters": {
        "jsCode": "try {\n  // Check if input exists and has the expected structure\n  const input = $input.all();\n  if (!input || !input.length) {\n    throw new Error('No input data received');\n  }\n\n  const firstItem = input[0];\n  if (!firstItem || !firstItem.json || !firstItem.json.output || !firstItem.json.output.output) {\n    throw new Error('Invalid input structure: missing required properties');\n  }\n\n  const output = firstItem.json.output.output;\n  \n  // Validate title exists\n  if (!output.title) {\n    throw new Error('Missing title in output');\n  }\n\n  // Validate content exists\n  if (!output.content) {\n    throw new Error('Missing content in output');\n  }\n\n  const title = output.title;\n  const content = output.content.replace(/<h1>.*?<\\/h1>/s, '').trim();\n\n  // Validate final content is not empty after processing\n  if (!content) {\n    throw new Error('Content is empty after processing');\n  }\n\n  console.log('Successfully processed content');\n\n  console.log(title)\n  console.log(content)\n  \n  return { title, content };\n\n} catch (error) {\n  // Log the error for debugging\n  console.error('Error processing content:', error.message);\n  \n  // Return a graceful failure object\n  return {\n    error: true,\n    message: error.message,\n    title: '',\n    content: '',\n    timestamp: new Date().toISOString()\n  };\n}"
      },
      "typeVersion": 2
    },
    {
      "id": "e4d41cf6-575d-469a-a7c5-fba0fc1cc568",
      "name": "If",
      "type": "n8n-nodes-base.if",
      "position": [
        1840,
        1480
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "aaf83c73-65f3-4a88-87f3-25b1acaf93ef",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.title }}",
              "rightValue": ""
            },
            {
              "id": "d9af5bce-f0fb-4c20-8b6a-b01a3bf3e1d1",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.content }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "b6b64f53-b689-440c-bc2e-478bccbfa5f5",
      "name": "Do Nothing",
      "type": "n8n-nodes-base.noOp",
      "position": [
        2020,
        1740
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "20b12b54-d329-4c70-9fa2-0dc598477a66",
      "name": "Create Structured Blog Post",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1200,
        1480
      ],
      "parameters": {
        "text": "={{ $json.text }}",
        "agent": "conversationalAgent",
        "options": {
          "systemMessage": "=Analyze the provided PDF article and create a compelling blog post that will be returned in JSON format with two fields: \"title\" and \"content\". Follow these specifications:\n\n## Title Requirements\n- Create an engaging, SEO-friendly title under 10 words\n- Must not contain a colon\n- Should capture the article's essence\n- Will be formatted as an H1 in the content\n\n## Content Structure\n- Introduction (150-200 words)\n  * Compelling hook\n  * Topic context and importance\n  * Preview of main points\n\n- Main Content (6-8 chapters)\n  * Each chapter requires:\n    - Relevant H2 heading\n    - 300-400 words of unique content\n    - Specific topic focus\n    - Source material quotes/data\n    - Smooth transitions\n\n- Conclusion (200-250 words)\n  * Key takeaways\n  * Final thoughts/implications\n\n## Formatting Guidelines\n- Use proper HTML tags throughout\n- Structure with <p> tags for paragraphs\n- Include appropriate spacing\n- Use <blockquote> for direct quotes\n- Maintain consistent formatting\n- Write in clear, professional tone\n- Break up long paragraphs\n- Use engaging subheadings\n- Include transitional phrases\n\nThe content should be original, avoid direct copying, and maintain a consistent voice throughout. The final JSON response should contain only the title and content fields, with the content including all HTML formatting."
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "retryOnFail": true,
      "typeVersion": 1.6
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "ae25fae9-8ae8-4a49-ae90-dd2a89599f08",
  "connections": {
    "If": {
      "main": [
        [
          {
            "node": "Post to Ghost",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Do Nothing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload PDF": {
      "main": [
        [
          {
            "node": "Extract Text",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "gpt-4o-mini": {
      "ai_languageModel": [
        [
          {
            "node": "Create Structured Blog Post",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Extract Text": {
      "main": [
        [
          {
            "node": "Create Structured Blog Post",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Separate Title & Content": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output - JSON": {
      "ai_outputParser": [
        [
          {
            "node": "Create Structured Blog Post",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Create Structured Blog Post": {
      "main": [
        [
          {
            "node": "Separate Title & Content",
            "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.

Pro

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

How this works

Transform lengthy PDFs into engaging blog posts effortlessly, saving hours of manual rewriting for content creators and researchers. This workflow suits bloggers, marketers, and educators who need to repurpose documents into polished articles without losing key details. It begins with uploading a PDF via a simple form trigger, then leverages AI to extract and refine the text before publishing directly to Ghost, ensuring your content reaches your audience seamlessly.

Use this workflow when you have a single PDF ready for quick conversion to a blog post, especially for time-sensitive topics like reports or whitepapers. Avoid it for highly technical PDFs requiring custom formatting or when integrating with multiple platforms beyond Ghost. Common variations include swapping Ghost for WordPress or adding image extraction for richer posts.

About this workflow

📄🛠️PDF2Blog. Uses stickyNote, formTrigger, extractFromFile, ghost. Event-driven trigger; 12 nodes.

Source: https://github.com/Zie619/n8n-workflows — 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

Purpose of workflow: This AI-powered workflow is designed to automatically generate comprehensive, well-researched articles on any given topic. It utilizes a team of AI agents to streamline the resear

Form Trigger, Ghost, Chain Llm +6
AI & RAG

From PDF to Powerful Blog Posts: AI-Powered Content Transformation

Form Trigger, Ghost, OpenAI Chat +2
AI & RAG

📄🌐PDF2Blog - Create Blog Post on Ghost CRM from PDF Document. Uses formTrigger, ghost, lmChatOpenAi, outputParserStructured. Event-driven trigger; 12 nodes.

Form Trigger, Ghost, OpenAI Chat +2
AI & RAG

🎯 Create viral TikToks, Shorts, Reels, podcasts, and ASMR videos in minutes — all on autopilot.

OpenAI, HTTP Request, Form Trigger +7
AI & RAG

Digistars - Scrape & Crawl. Uses httpRequest, n8n-nodes-firecrawl-scraper, googleSheets, lmChatOpenAi. Event-driven trigger; 63 nodes.

HTTP Request, N8N Nodes Firecrawl Scraper, Google Sheets +5