How to Build an Autonomous Social Media Manager with n8n & Claude
A full workflow tutorial for an end-to-end autonomous social media content engine using n8n, the Claude API, and LinkedIn/X platform APIs, with JSON workflow structures included.
AgenticMedia Team
Content Creator

TL;DR / Key Takeaways
An autonomous social media manager isn’t a single AI call — it’s a pipeline: trigger → content generation → visual asset generation → human review gate → multi-platform publish → performance logging. Here’s the shape of a production-grade version:
- n8n is the orchestration layer, not the intelligence layer. It handles scheduling, branching, retries, and API calls; Claude handles the actual writing and reasoning.
- Never skip the human-in-the-loop gate for anything client-facing or brand-sensitive — the highest-ROI version of this workflow routes drafts to Slack/Telegram for a one-tap approve/reject before anything goes live.
- Platform-specific prompt templates matter more than a single generic prompt — a LinkedIn post and an X/Twitter post have different structural constraints (character limits, tone, hashtag conventions), and a single “write a social post” prompt underperforms platform-tuned versions.
- Image generation should be a separate node, not baked into the same Claude call — use a dedicated image model call, feeding it a visual brief that Claude generates alongside the copy.
- Log everything to a database (Airtable/Postgres) node — post text, image URL, publish status, and later engagement metrics — so the pipeline can eventually inform its own prompt tuning based on what performed well.
Core Architecture: The Five-Node Pipeline
The workflow breaks into five logical stages, each mapped to an n8n node group:
- Trigger — a Cron node (e.g., “every weekday at 9am”) or a Webhook node (triggered by a content calendar entry, an RSS feed of new blog posts, or a manual Slack command).
- Content Generation — an HTTP Request node calling the Claude API with a platform-specific prompt template, returning structured JSON (post copy + an image brief).
- Image Generation — a second HTTP Request node, passing the image brief from step 2 to an image generation API, returning an image URL or base64 asset.
- Human Approval Gate — a Slack/Telegram node posting the draft (text + image) with interactive buttons, pausing the workflow (via a Wait node or n8n’s Human-in-the-Loop pattern) until a human responds.
- Publish + Log — on approval, HTTP Request nodes to each platform’s API (LinkedIn, X/Twitter), followed by an Airtable/Postgres node logging the final published post and metadata.
Practical Tutorial: Building the Workflow
Step 1 — The Trigger Node
For a content-calendar-driven system, use a Cron trigger combined with a Google Sheets or Airtable node that reads the day’s planned topic:
{
"nodes": [
{
"name": "Daily Trigger",
"type": "n8n-nodes-base.cron",
"parameters": {
"triggerTimes": {
"item": [{ "hour": 9, "minute": 0 }]
}
}
},
{
"name": "Get Today's Topic",
"type": "n8n-nodes-base.airtable",
"parameters": {
"operation": "list",
"application": "={{$env.CONTENT_CALENDAR_BASE_ID}}",
"table": "PostQueue",
"filterByFormula": "AND({Status}='Pending', {ScheduledDate}=TODAY())"
}
}
]
}
Step 2 — Claude API Node for Content Generation
The core generation call uses an HTTP Request node hitting the Claude API’s /v1/messages endpoint. Structure the system prompt to return structured JSON, not freeform text — this is what makes the downstream image and publish nodes reliable.
{
"name": "Generate Post Copy",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"method": "POST",
"url": "https://api.anthropic.com/v1/messages",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "anthropicApi",
"jsonBody": {
"model": "claude-sonnet-4-6",
"max_tokens": 1024,
"system": "You are a social media copywriter. Always respond with valid JSON only, no markdown fences, matching this schema: {\"linkedin_post\": string, \"x_post\": string, \"image_brief\": string, \"hashtags\": string[]}",
"messages": [
{
"role": "user",
"content": "Topic: {{$json.Topic}}\nKey points: {{$json.KeyPoints}}\n\nWrite a LinkedIn post (150-250 words, professional but conversational tone, one clear takeaway, no more than 3 hashtags) and a separate X/Twitter post (under 280 characters, punchy, 1-2 hashtags max). Also write a one-sentence visual brief describing an image that would accompany this post."
}
]
}
}
}
Platform-specific prompt template breakdown:
| Platform | Length Constraint | Tone Directive | Hashtag Guidance |
|---|---|---|---|
| 150-250 words | Professional, conversational, one clear takeaway | Max 3, placed at the end | |
| X / Twitter | Under 280 characters | Punchy, direct, no corporate voice | Max 1-2, inline or end |
Step 3 — Parse the Response and Route to Image Generation
Add a Code node (or Set node) to parse the Claude response JSON, then pass image_brief to your image generation node:
// Code node: parse Claude's structured response
const raw = $input.first().json.content[0].text;
const parsed = JSON.parse(raw);
return [{
json: {
linkedin_post: parsed.linkedin_post,
x_post: parsed.x_post,
image_brief: parsed.image_brief,
hashtags: parsed.hashtags
}
}];
{
"name": "Generate Visual",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"method": "POST",
"url": "https://api.your-image-provider.com/v1/generate",
"jsonBody": {
"prompt": "={{$json.image_brief}}, clean modern flat illustration style, brand colors: navy and white",
"aspect_ratio": "1:1"
}
}
}
Keeping image generation as a separate API call — rather than asking Claude to “generate an image” — lets you swap image providers independently and keeps each node’s failure modes isolated and easy to retry.
Step 4 — Human Approval Gate (Slack)
{
"name": "Send for Approval",
"type": "n8n-nodes-base.slack",
"parameters": {
"operation": "post",
"channel": "#content-approvals",
"text": "New post ready for review:\n\n*LinkedIn:*\n{{$json.linkedin_post}}\n\n*X:*\n{{$json.x_post}}",
"attachments": [
{
"image_url": "={{$json.image_url}}",
"fallback": "Generated visual preview"
}
],
"blocks": [
{
"type": "actions",
"elements": [
{ "type": "button", "text": "✅ Approve", "action_id": "approve_post" },
{ "type": "button", "text": "❌ Reject", "action_id": "reject_post" }
]
}
]
}
}
Pair this with an n8n Webhook node listening for the Slack button interaction, which resumes the paused workflow — this is the single highest-leverage node in the entire pipeline, since it’s the difference between “automated drafting” and “fully autonomous publishing without oversight,” which most brands are not yet comfortable with for anything beyond low-stakes content.
Step 5 — Publish and Log
{
"name": "Publish to LinkedIn",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"method": "POST",
"url": "https://api.linkedin.com/v2/ugcPosts",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "linkedInOAuth2Api",
"jsonBody": {
"author": "urn:li:organization:{{$env.LINKEDIN_ORG_ID}}",
"lifecycleState": "PUBLISHED",
"specificContent": {
"com.linkedin.ugc.ShareContent": {
"shareCommentary": { "text": "={{$json.linkedin_post}}" },
"shareMediaCategory": "IMAGE"
}
},
"visibility": { "com.linkedin.ugc.MemberNetworkVisibility": "PUBLIC" }
}
}
}
Follow with an Airtable “Update Record” node writing back the published status, post URL, and timestamp — this log becomes the dataset you’ll eventually use to correlate post structure with engagement, closing the loop for prompt refinement.
Tool / Solution Comparison Table
| Component | Recommended Tool | Alternative | Why |
|---|---|---|---|
| Orchestration | n8n (self-hosted or cloud) | Make.com, Zapier | n8n’s native Code nodes and self-hosting give more control over complex branching logic |
| Content generation | Claude API | GPT-4o, Gemini | Strong instruction-following for structured JSON output and platform-tuned tone |
| Image generation | Dedicated image API (Nano Banana Pro, Midjourney API, DALL-E) | Stable Diffusion (self-hosted) | Keep image generation decoupled from text generation for easier provider swaps |
| Approval interface | Slack interactive buttons | Telegram bot, custom dashboard | Slack integrates natively with n8n’s webhook resume pattern |
| Logging / data store | Airtable | Postgres, Google Sheets | Airtable’s UI doubles as a lightweight content calendar for non-technical team members |
Actionable Checklist / Next Steps
- Map your five pipeline stages (trigger, generate copy, generate visual, approve, publish+log) before building a single n8n node.
- Force Claude to return structured JSON via an explicit schema in the system prompt — never parse freeform text in production.
- Build platform-specific prompt templates for each network you publish to — don’t reuse one generic prompt.
- Wire a human approval gate before any publish step for at least the first several weeks of operation.
- Log every generated post (approved and rejected) to build a dataset for future prompt tuning.
- Set up retry logic (n8n’s built-in error workflow) on every external API node — social platform APIs rate-limit and fail intermittently.
Next in this series: Best Serverless GPU Hosts for AI Agents (RunPod vs. Lambda Labs) — Day 05 covers the infrastructure layer for running your own models behind workflows like this one.
AgenticMedia Team
Content Creator • @agenticmedia
Writer and technology enthusiast sharing engineering playbooks and digital optimization guides.
