How to Automate Content Repurposing with n8n
The Problem
A single long article contains enough material for a week of social posts, an email snippet, and a thread, but turning it into those formats is repetitive work that rarely gets done. Teams publish once, share a link, and move on, leaving most of the value unused. Pasting the article into a chat window each time also loses track of which variants were drafted, approved, or posted. This guide builds an n8n workflow that accepts an article URL through a webhook, splits the content by headings, drafts several formats per section through an LLM API, and logs every variant in Airtable with a status you can manage.
What You Will Need
- A self-hosted n8n instance (Community Edition is free) or an n8n Cloud trial
- An Airtable base with a table named Variants (fields sourceUrl, platform, variantText, status, section) and a personal access token stored as an n8n credential
- An LLM API key from any provider with a chat completions style endpoint, stored as an n8n Header Auth credential
- About 60 minutes of setup time
Step-by-Step Workflow Setup
1 Receive the article URL with a Webhook
The Webhook node gives n8n a URL that accepts a POST request. You can call it from a publishing script, a form, or a no code tool each time a new article goes live.
Add a Webhook node to a new n8n workflow and configure:
Node: Webhook
HTTP Method: POST
Path: repurpose
Authentication: Header Auth
Respond: Immediately
Response Code: 200
Options > Response Data: {"status":"queued"}
Responding immediately matters because LLM calls can take a while, and most callers time out after 30 seconds. The body of the request is available under the body key in n8n.
Expression: {{ $json.body.url }}
{
"url": "https://example.com/blog/zero-downtime-deploys",
"tone": "practical",
"platforms": ["social", "email", "thread"]
}
Use the Test URL while building and the Production URL once the workflow is active. The two paths differ in n8n, a common source of confusion.
2 Fetch the full article HTML
An HTTP Request node downloads the article so the n8n workflow can work with the complete text instead of a summary.
Add an HTTP Request node to the n8n canvas and configure:
Node: HTTP Request
Method: GET
URL: {{ $json.body.url }}
Response Format: Text
Put Output in Field: html
Options > Timeout: 20000
Options > Redirects > Follow Redirects: On
Settings > Retry On Fail: On
Settings > Max Tries: 3
{
"html": "<article><h1>Zero Downtime Deploys</h1><h2>Why rolling updates matter</h2><p>...</p></article>"
}
Retry On Fail covers short outages if you trigger the workflow right after publishing and the page is still warming up, and n8n will try again.
3 Strip HTML and split by headings
An n8n Code node cleans the markup and cuts the article at each H2 heading. Splitting on headings gives the LLM a focused chunk with a clear topic, which produces tighter posts than feeding in the whole article at once.
Add a Code node and configure:
Node: Code
Mode: Run Once for All Items
Language: JavaScript
const html = $json.html || '';
const url = $('Webhook').first().json.body.url;
const main = (html.match(/<article[\s\S]*?<\/article>/i) || [html])[0]
.replace(/<script[\s\S]*?<\/script>/gi, ' ')
.replace(/<style[\s\S]*?<\/style>/gi, ' ');
const parts = main.split(/<h2[^>]*>/i).slice(1);
const clean = s => s.replace(/<[^>]+>/g, ' ').replace(/ /g, ' ').replace(/\s+/g, ' ').trim();
const sections = parts.map(p => {
const [head, ...rest] = p.split(/<\/h2>/i);
return { sourceUrl: url, heading: clean(head), body: clean(rest.join(' ')) };
}).filter(s => s.body.split(' ').length >= 40);
return [{ json: { sections } }];
The filter drops sections shorter than 40 words, such as a short conclusion, because there is too little material to repurpose. Adjust the number to taste in the n8n Code node.
{
"sections": [
{
"sourceUrl": "https://example.com/blog/zero-downtime-deploys",
"heading": "Why rolling updates matter",
"body": "Rolling updates replace instances one at a time so traffic keeps flowing..."
}
]
}
4 Process each section with Split Out
The Split Out node converts the sections array into one n8n item per section, so the next nodes run once for each.
Add a Split Out node and configure:
Node: Split Out
Fields To Split Out: sections
Include: No Other Fields
Destination Field Name: (leave empty)
After this node, each item exposes sourceUrl, heading, and body at the top level. If a long article yields ten sections, the following LLM node runs ten times, so watch your API usage on very long posts when n8n loops.
5 Draft variants with an LLM API
Another n8n HTTP Request node sends each section to the LLM API. Asking for strict JSON output lets the next node read the three formats without fragile text parsing.
Add an HTTP Request node and configure:
Node: HTTP Request
Method: POST
URL: https://api.your-llm-provider.com/v1/chat/completions
Authentication: Generic Credential Type > Header Auth
Send Body: On
Body Content Type: JSON
Specify Body: Using JSON
Options > Batching > Items per Batch: 1
Options > Batching > Batch Interval: 1000
Settings > Retry On Fail: On
JSON Body:
{
"model": "your-model-name",
"temperature": 0.7,
"response_format": { "type": "json_object" },
"messages": [
{ "role": "system", "content": "Rewrite in your own words. Return JSON with keys social (max 260 characters), email (2 sentences), thread (array of 4 short posts)." },
{ "role": "user", "content": "Heading: {{ $json.heading }}\nText: {{ $json.body }}" }
]
}
Use the JSON.stringify helper inside the n8n expression if section text contains quotes that break the JSON body.
{
"choices": [
{ "message": { "content": "{\"social\":\"Rolling updates keep traffic flowing while you ship.\",\"email\":\"Rolling updates swap instances one by one. Your users never see downtime.\",\"thread\":[\"1/ Deploys do not need downtime.\",\"2/ Replace instances gradually.\"]}" } }
]
}
6 Collect variants with Aggregate
An n8n Code node first expands each LLM reply into separate platform items. Then the n8n Aggregate node gathers them into one list so a single n8n Airtable operation can store the full set.
Node: Code
Mode: Run Once for Each Item
const v = JSON.parse($json.choices[0].message.content);
const src = $('Split Out').item.json;
return { json: { variants: [
{ sourceUrl: src.sourceUrl, section: src.heading, platform: 'social', variantText: v.social },
{ sourceUrl: src.sourceUrl, section: src.heading, platform: 'email', variantText: v.email },
{ sourceUrl: src.sourceUrl, section: src.heading, platform: 'thread', variantText: v.thread.join('\n') }
] } };
Node: Aggregate
Aggregate: Individual Fields
Input Field Name: variants
Options > Merge Lists: On
In n8n, Merge Lists flattens the nested arrays into a single array of variant objects.
7 Store variants in Airtable
Because the n8n Aggregate node produces one item holding an array, use a Split Out on the variants field again, then an n8n Airtable node to create records. Each record stores the source URL, platform, text, and a status for your review process.
Node: Airtable
Resource: Record
Operation: Create
Base: By ID (your base)
Table: Variants
Columns > Mapping: Define Below
sourceUrl: {{ $json.sourceUrl }}
section: {{ $json.section }}
platform: {{ $json.platform }}
variantText: {{ $json.variantText }}
status: Draft
{
"id": "recAb12Cd34Ef56Gh",
"fields": {
"sourceUrl": "https://example.com/blog/zero-downtime-deploys",
"platform": "social",
"status": "Draft"
}
}
Set up an Airtable view beside your n8n workflow, filtered by status Draft, and your editor can approve or reject variants in one place before anything is published.
Troubleshooting
The n8n webhook works in test mode but nothing happens in production
The workflow must be activated, and callers must use the Production URL, which has no webhook-test segment. Also confirm the Header Auth credential on the Webhook node matches the header your script sends.
The LLM reply fails JSON.parse in the n8n Code node
Models sometimes wrap JSON in code fences. Strip fences with a replace call before parsing, and lower the temperature to 0.3. Enabling Continue On Fail on the HTTP Request node prevents a single bad section from stopping the whole run.
Airtable returns a 422 error to n8n about an unknown field value
Single select fields only accept existing options. Create Draft, Approved, and Posted as options in the status field first, or switch the field type to single line text.
Free n8n Workflow Resources
Get started with the free workflow pack on the LightCube Labs templates page.
Production-Ready Workflow Packs
Get this workflow and more, with setup guides, editable configurations, and a shared failure-alert system.
View the Starter ($29) and Pro ($99) PacksFrequently Asked Questions
Why does n8n split by headings instead of sending the whole article to the LLM?
In n8n, smaller chunks keep each output focused on one idea and reduce the chance the model skips content. Heading based splitting also lets you trace each variant back to the exact section it came from.
How can I add a new output format such as a LinkedIn post to the n8n workflow?
Add a key to the system prompt, then add another object to the variants array in the step 6 Code node with platform set to linkedin. No other n8n node needs to change.
How do I avoid publishing near copies of my own article?
The prompt asks for rewrites in new words, and the Draft status gives a human a review point. Keep the social length limits tight so variants stay short summaries, not pasted paragraphs.
Can I trigger this n8n workflow automatically when I publish?
Yes. Most content management systems can call a webhook on publish. Point that webhook at the n8n Production URL with the article URL in the body.