AutoFlowLab
← Tutorials

AI Content Pipeline Automation: Notion to WordPress in n8n

Build an n8n content pipeline turning a Notion idea backlog into outlines, drafts, and edited posts with distinct AI passes, human review, and publishing.

April 28, 2026 · intermediate · 1.5 hours setup

The bottleneck in most small-business content operations isn’t ideas — it’s the unglamorous middle: turning a one-line idea into an outline, the outline into a draft, the draft into something publishable, and then actually remembering to publish it. Ideas pile up in Notion; the blog gets one post a month.

This tutorial builds a pipeline in n8n that automates the middle while keeping a human firmly in the approval seat. An idea card in Notion moves through three distinct AI passes — outline, draft, edit — each with its own prompt, lands back in Notion as “Ready for Review,” and once a human flips the status to “Approved,” n8n publishes to WordPress and queues social posts in Buffer. Single-pass “write me a blog post” prompts produce mush; the three-pass structure is what makes the output worth reviewing instead of rewriting.

Pipeline architecture

Two workflows, both driven by Notion status changes:

Workflow A (drafting):
Schedule Trigger (hourly)
  → Notion: Get pages where Status = "Idea"
  → Loop Over Items
      → OpenAI pass 1: outline
      → OpenAI pass 2: draft
      → OpenAI pass 3: edit
      → Notion: write draft to page, set Status = "Ready for Review"

Workflow B (publishing):
Schedule Trigger (every 15 min)
  → Notion: Get pages where Status = "Approved"
  → Notion: read page content
  → WordPress: create post (draft → publish)
  → Buffer/HTTP: queue social posts
  → Notion: set Status = "Published", store URL

You’ll need: an n8n instance, a Notion integration token, an OpenAI API key, a WordPress site with an application password, and (optionally) a Buffer access token.

The complete two-workflow setup is in the template — import via Workflow → Import from File:

Free template · n8n

AI Content Pipeline

ai-content-pipeline-n8n.json

Download JSON

Step 1: Structure the Notion database

Create a Notion database called Content Pipeline with these properties — exact names matter because the workflow filters on them:

  • Title (title) — the working headline
  • Status (select): Idea, Outlining, Drafting, Ready for Review, Approved, Published, Rejected
  • Angle (text) — one or two sentences on the take; this is the single highest-leverage input you give the AI
  • Keyword (text) — target search phrase
  • Audience (text) — who it’s for
  • Published URL (URL) — filled by the workflow

Create a Notion integration at notion.so/my-integrations, copy the secret, and — the step everyone forgets — open the database, hit ••• → Connections, and add your integration. Without that explicit share, every API call returns an empty result with no error.

Step 2: Workflow A trigger and idea fetch

  1. Schedule Trigger node, every hour. Hourly is right for content — there’s no urgency, and it batches nicely.
  2. Notion node: resource Database Page, operation Get Many, pick your database. Add a filter: Status → select → equals → Idea. Set Limit to 3 so a backlog of 40 ideas doesn’t fire 120 LLM calls in one run.
  3. Immediately after, a second Notion node (operation Update) sets each fetched page’s Status to Outlining. This claim-before-work step prevents double-processing if a run overlaps a slow predecessor.
  4. Loop Over Items node with batch size 1, so each idea moves through the passes independently and one failure doesn’t sink the batch.

Step 3: Pass 1 — the outline prompt

Add an OpenAI node (Chat → Message a Model), temperature 0.7 for this pass — outlining benefits from some creativity. System message:

You are a senior content strategist for a small-business blog about
AI workflow automation. Produce a detailed outline for the post
described by the user. Return ONLY JSON:

{
  "working_title": "string, 50-65 chars, includes the keyword",
  "hook": "2-3 sentences describing the concrete problem the post opens with",
  "sections": [
    { "heading": "string", "points": ["3-5 specific points, not generic filler"] }
  ],
  "cta": "what the reader should do at the end"
}

Rules:
- 5-8 sections. Every section must earn its place; no "Introduction"
  or "Conclusion" headings.
- Points must be specific enough that a writer could not misinterpret
  them. "Explain the benefits" is banned; "Show the 4-task Zapier cost
  vs flat n8n hosting for 1,000 runs/month" is the standard.
- Write for practitioners, not executives. Assume the reader will
  actually build the thing.

User message, from the Notion properties:

Title idea: {{ $json.properties.Title.title[0].plainText }}
Angle: {{ $json.properties.Angle.richText[0].plainText }}
Target keyword: {{ $json.properties.Keyword.richText[0].plainText }}
Audience: {{ $json.properties.Audience.richText[0].plainText }}

(Property paths vary slightly by n8n version — use the expression editor’s schema browser on a real item rather than typing these blind.)

Step 4: Pass 2 — the draft prompt

Second OpenAI node, temperature 0.7, a capable mid-to-top-tier model — drafting is where model quality shows most. As of mid-2026, check current pricing; a 1,500-word draft pass typically costs a few cents. System message:

You are a staff writer who builds automation workflows and writes
from hands-on experience. Write the full post from the outline the
user provides.

Rules:
- 1,200-1,800 words, Markdown, ## and ### headings from the outline.
- Open with the hook. No throat-clearing, no "In today's world".
- Concrete over abstract everywhere: name the exact node, the exact
  setting, the realistic number.
- Short paragraphs, max 4 sentences. Use numbered lists for any
  procedure.
- Do not invent statistics, customer names, or pricing figures. Where
  a number would help but you don't have one, write [VERIFY: what's
  needed] so the editor can fill it in.
- Return ONLY the Markdown post body. No JSON wrapper, no preamble.

User message:

Outline JSON:
{{ $json.message.content }}

Note the deliberate shape change: passes 1 returns JSON, pass 2 returns raw Markdown. Don’t ask for Markdown inside JSON — escaping multi-paragraph Markdown in JSON strings is where malformed-output errors breed.

Step 5: Pass 3 — the edit prompt

Third OpenAI node, temperature 0.2 — editing should be conservative. System message:

You are a ruthless line editor. Edit the post the user provides.

Your edits:
1. Cut filler: "very", "actually", "in order to", "it's important to
   note", hedging that adds no information.
2. Break any paragraph over 4 sentences.
3. Verify every heading promises something the section delivers;
   rewrite headings that don't.
4. Ensure the keyword "{{ $('Loop Over Items').item.json.properties.Keyword.richText[0].plainText }}"
   appears in the first 100 words and at least one H2, naturally.
5. Flag (don't fix) factual claims that need verification by leaving
   any existing [VERIFY: ...] markers in place.
6. Keep the author's voice. You are editing, not rewriting.

Return ONLY the edited Markdown. No commentary, no change log.

User message: {{ $json.message.content }} (the draft from pass 2).

Step 6: Write back to Notion for review

  1. Code node to convert the Markdown into Notion blocks, or — simpler and what the template does — store the Markdown in a single code-block child and keep the canonical copy for WordPress. Notion’s block API caps children at 100 blocks per request, so long posts need chunked appends if you go the full-blocks route.
  2. Notion node: operation Update on the page — set Status to Ready for Review.
  3. Notion node: operation Append Block with the edited content.

Now the human loop: someone reads the draft in Notion, fixes the [VERIFY] markers, and flips Status to Approved (or Rejected, which simply parks it). This status flip is the entire review interface — no custom UI, no email approvals, just the tool the team already lives in.

Try it yourself

n8n

Three chained LLM passes with different temperatures per step is trivial in n8n and painful almost everywhere else.

Start with n8n

Step 7: Workflow B — publish on approval

  1. Schedule Trigger, every 15 minutes, then Notion → Get Many filtered on Status = Approved, limit 5.
  2. Notion node, operation Get Child Blocks, to pull the reviewed content (a Code node reassembles the Markdown from the code block).
  3. Code node to convert Markdown to HTML (marked is available in n8n’s Code node when NODE_FUNCTION_ALLOW_EXTERNAL permits it; otherwise a small regex-based converter handles headings, lists, links, and bold — the template ships one).
  4. WordPress node: operation Create Post. Authenticate with an application password (WordPress profile → Application Passwords) — not your login password, and the REST API must not be blocked by a security plugin. Map:
    • Title: the working title from Notion
    • Content: the HTML
    • Status: draft for the first two weeks of running this pipeline, then publish once you trust it
  5. HTTP Request node for Buffer: POST https://api.bufferapp.com/1/updates/create.json with your access token, profile_ids[], and text set to a short promo line plus the WordPress URL from the previous node’s response ({{ $json.link }}). Buffer’s classic API still works as of mid-2026, but check current docs — if you’re on a tool with a native n8n node (Typefully, Mixpost), prefer that.
  6. Notion node: Update page — Status Published, Published URL = {{ $json.link }}.

When to pick Zapier vs Make vs n8n for content pipelines

This is the rare task where the answer is lopsided. The pipeline’s value lives in chained LLM passes with different prompts, temperatures, and output shapes, plus Markdown wrangling in code — n8n native territory. Make can do it with a long scenario and its OpenAI modules, and is a reasonable second choice if you’re already there, though the Markdown-to-blocks conversion gets clunky. Zapier fights you: multi-step LLM chains burn tasks fast and Code by Zapier’s limits cramp the conversion logic. If your pipeline is just “idea → one AI draft → Google Doc,” Zapier is fine; for this full version, use n8n. Full comparison: Make vs Zapier vs n8n.

Common errors and fixes

Notion returns empty results despite matching pages. The integration isn’t connected to the database (••• → Connections), or you renamed a Status option and the filter references the old name. Both fail silently.

Notion API 409 conflict or validation_error on append. You’re appending more than 100 blocks in one call, or a block payload has empty rich-text arrays. Chunk appends to 90 blocks and filter out empty paragraphs in the Code node.

Draft pass returns JSON-wrapped Markdown or a chatty “Here’s your post:”. Tighten the “Return ONLY the Markdown” line and strip leading non-heading lines in a Code node: content.replace(/^[\s\S]*?(?=^#)/m, '') as a guard.

WordPress 401 on Create Post. You used the account password instead of an application password, or a security plugin (Wordfence, iThemes) blocks REST API auth. Generate an application password and allowlist the REST route.

Both workflow runs process the same idea twice. The claim step (Status → Outlining immediately after fetch) is missing or placed after the LLM passes. It must run before any slow node.

OpenAI 429 / timeout on the draft pass. Long drafts can take 60+ seconds. Raise the OpenAI node’s timeout to 180000ms, enable Retry on Fail (2 retries), and keep the Loop batch size at 1.

Buffer rejects the post. Profile IDs are stale after reconnecting a social account — re-fetch them from /1/profiles.json. Buffer also rejects updates over the network’s character limit, so truncate promo text in the Code node.

Operating notes

Costs scale with throughput: three passes on a 1,500-word post run a few cents to a few tens of cents depending on model choice — as of mid-2026, check current pricing. The real win is cycle time: ideas that sat for weeks become reviewable drafts within the hour, and the human’s job shrinks to judgment — angle, accuracy, taste — which is the part you actually wanted a human doing.

Pair this with the lead capture workflow and the content you publish starts feeding qualified leads into the same n8n instance that wrote it.