Why automate publishing at all

According to Orbit Media's 2025 report, 95% of bloggers already use AI at least occasionally when creating content. This isn't a trend — it's a response to a real problem: creating a single article from idea to publication takes 3–5 hours of manual work.

I've been running a blog for years and I know this firsthand. There were weeks when instead of two planned posts, only one shipped — and sometimes none at all. The chain "come up with the idea → write → format → publish" is just too long.

Automation via n8n solves exactly this. I'm not replacing myself with a robot — I'm removing the drudgery. I still come up with the topic myself, but the draft, structure, and publishing are handled by the workflow.

In March 2025, n8n raised a €55M Series B at a valuation of ~€250M. More than 3,000 enterprise customers (Vodafone, Microsoft) build automations on it. And most importantly — n8n can be deployed for free on your own server.

What we're building

The idea is simple: a Telegram bot receives a topic, and n8n runs a chain of generation and publishing.

💬
Telegram
Trigger
🔐
IF
Chat ID
🤖
OpenAI
Content+SEO
📝
Code
Parse JSON
🎨
DALL-E
Cover
📤
WP Media
Upload
🌐
WordPress
Post+SEO
📨
Telegram
Confirm

What the system does:

  • Receives the article topic from Telegram
  • Verifies chat_id (blocks strangers)
  • Generates the post via OpenAI with a full SEO package: title, slug, meta description, keywords, excerpt, alt description for the image
  • Generates the cover image via DALL-E from a prompt based on the topic
  • Uploads the image to the WordPress Media Library with alt/title attributes
  • Publishes the article with all SEO fields filled (Yoast/RankMath) and the featured image attached
  • Sends a confirmation with the link to Telegram
What you'll need

n8n (self-hosted or cloud), a Telegram account, an OpenAI API key (or Claude/Gemini), a WordPress site with REST API. ~30 minutes total. If you don't have n8n yet — head over to our VPS install guide.

Create the bot via BotFather

Open Telegram, find @BotFather, and run this sequence:

# 1. Create a new bot /newbot # 2. Enter the name (visible to users) → My Autoposting # 3. Enter the username (must end in "bot") → my_autopost_bot # 4. Grab the API Token → 7123456789:AAHdqTcv... # Save the token — you'll need it in n8n
Important: token security

Never expose your bot token publicly. Anyone with your token can control your bot. Keep it only in n8n credentials.

Connect the Telegram Trigger in n8n

Open n8n and create a new workflow. Then:

  • Add a "Telegram Trigger" node and pick the trigger "On Message"
  • In "Credential to connect with" click "Create New" → paste the API Token from BotFather → save
  • Add an "IF" node with a chat_id check — so only you can trigger the generation

IF node configuration for the chat_id check:

Value 1: {{ $json.message.chat.id }} Operation: Equal Value 2: YOUR_CHAT_ID // To find your chat_id: send the bot a message, // look at the Telegram Trigger output → message.chat.id

Now every message to your bot will hand n8n a payload, including the message text and the sender's chat_id.

Content generation with a full SEO package

The AI node is the heart of the whole workflow. We ask OpenAI to return not just the article, but a full SEO package: meta title, meta description, keywords, slug, excerpt, plus a prompt for the cover image generation with an alt description.

Model n8n node Price When to pick it
GPT-4o-mini OpenAI Chat Model $0.15/1M input Best price/quality ratio
GPT-4o OpenAI Chat Model $2.50/1M input Complex topics, heavier reasoning
Claude 3.5 Sonnet Anthropic Chat Model $3/1M input Long context, follows instructions well
Gemini Flash Google Gemini Chat Model Free (with limits) Testing, minimal budget

System Prompt — the instruction that defines style and format:

You are an experienced SEO copywriter and on-page SEO specialist. You write articles for a WordPress blog in English. RULES: - Write in an informative but lively style - Use H2 and H3 subheadings - Avoid clichés ("in today's world", "in the digital era") - Max 3-4 sentences per paragraph - Include practical tips - Generate a full SEO package for every article - Generate a prompt for the cover image (DALL-E) - All SEO fields must be optimized for the focus keyword

User Prompt — extended with SEO field requirements:

Write a blog article on the topic: {{ $json.message.text }} Content requirements: - Unique headline (H1), SEO-optimized - 5-7 H2 subheadings - 1500-2000 words - HTML formatting (<h2>, <h3>, <p>, <ul>, <strong>) SEO field requirements: - seo_title: meta title for the <title> tag (50-60 characters) - meta_description: meta description (140-160 characters) - focus_keyword: main focus keyword - keywords: array of 5-8 keywords and phrases - slug: URL slug (lowercase, hyphen-separated, no special characters) - excerpt: short description for the blog feed (2-3 sentences, up to 300 characters) Image requirements: - image_prompt: DALL-E prompt in English (describe style, colors, composition; no text in the image) - image_alt: alt description in English (5-10 words, includes the focus keyword) - image_title: title attribute in English Respond strictly in JSON, no markdown wrapper: { "title": "Article headline (H1)", "seo_title": "SEO Title for <title> (50-60 characters)", "content": "HTML content of the article", "meta_description": "Meta description 140-160 characters", "focus_keyword": "main focus keyword", "keywords": ["kw1", "kw2", "kw3", ...], "slug": "url-slug-example", "excerpt": "Short description for the blog feed", "image_prompt": "DALL-E prompt in English...", "image_alt": "alt description in English", "image_title": "Image title" }
Why all SEO fields in one prompt?

One API call instead of five — cheaper, faster, and more consistent. The AI sees the entire context: the focus keyword lands in the title, the meta_description, and the image alt. Separate requests for each field would produce disconnected results.

Which SEO field does what

Field Where it appears WP plugin SEO impact
seo_title Browser tab, Google results Yoast / RankMath Critical
meta_description Description under the title in Google Yoast / RankMath Critical
focus_keyword SEO analysis in WP admin Yoast / RankMath High
keywords Post tags + meta keywords WordPress tags Medium
slug Article URL: /blog/slug/ WordPress core Critical
excerpt Blog feed, RSS, social media WordPress core Medium
image_alt Image alt text (Google Images) WordPress core Critical
image_title Title on hover + Media Library WordPress core Low

Cover image generation via DALL-E

Once OpenAI returns the JSON with the image_prompt field, we pass it to DALL-E for cover generation. Add an HTTP Request node:

Method: POST URL: https://api.openai.com/v1/images/generations Headers: Authorization: Bearer {{ $credentials.openAiApi.apiKey }} Content-Type: application/json Body (JSON): { "model": "dall-e-3", "prompt": {{ $json.image_prompt }}, "n": 1, "size": "1792x1024", "quality": "standard" }
DALL-E alternatives

Instead of DALL-E, you can wire up Flux (via piapi.ai or Replicate), Stable Diffusion (via Stability AI), or Midjourney (via an unofficial API). The request format will differ, but the logic is the same: prompt → image URL → upload to WP. DALL-E 3 costs ~$0.04 for a 1792×1024 image.

Now add a second HTTP Request node to upload the image to the WordPress Media Library with all attributes. It's a two-step process — first upload the file, then update alt/title/caption:

// Step 1: Upload the file from the URL (DALL-E returns a temporary URL) Method: POST URL: https://your-site.com/wp-json/wp/v2/media Headers: Authorization: Basic {{ base64(user:app_password) }} Content-Disposition: attachment; filename="{{ $json.slug }}.png" Content-Type: image/png // Step 2: Update alt, title, caption via a second request Method: POST URL: https://your-site.com/wp-json/wp/v2/media/{{ $json.media_id }} Body (JSON): { "alt_text": {{ $json.image_alt }}, "title": { "raw": {{ $json.image_title }} }, "caption": { "raw": {{ $json.image_alt }} }, "description": { "raw": {{ $json.image_title }} } }
Important: alt text and image SEO

Google Images is the second-largest source of traffic after regular search. Alt text with a focus keyword is critical: it helps Google understand what's in the image and rank it in image search. Naming the file slug.png instead of image_12345.png is also an SEO signal.

Publishing to WordPress with SEO

Now we bring it all together: parse the extended JSON, upload the image, and create the post with every SEO field filled.

Code Node: parsing the extended JSON

Create a JavaScript node that strips markdown wrappers and parses the JSON into a clean structure:

// Extract the response text const response = items[0].json.message.content; // Strip markdown wrappers const clean = response.replace(/```json\n?|```\n?/g, '').trim(); // Parse JSON const parsed = JSON.parse(clean); return [{ json: { // Content title: parsed.title, content: parsed.content, // SEO fields seo_title: parsed.seo_title, meta_description: parsed.meta_description, focus_keyword: parsed.focus_keyword, keywords: parsed.keywords, slug: parsed.slug, excerpt: parsed.excerpt, // Image image_prompt: parsed.image_prompt, image_alt: parsed.image_alt, image_title: parsed.image_title } }];

WordPress: creating the post with SEO fields

Instead of the built-in WordPress node, we use HTTP Request — it gives access to every REST API field, including meta fields for SEO plugins:

Method: POST URL: https://your-site.com/wp-json/wp/v2/posts Headers: Authorization: Basic {{ base64(user:app_password) }} Content-Type: application/json Body (JSON): { // Standard WordPress fields "title": {{ $json.title }}, "content": {{ $json.content }}, "excerpt": {{ $json.excerpt }}, "slug": {{ $json.slug }}, "status": "draft", "featured_media": {{ $json.media_id }}, "tags": {{ $json.tag_ids }}, // SEO fields for the Yoast SEO plugin "yoast_head_json": { "title": {{ $json.seo_title }}, "description": {{ $json.meta_description }} }, "meta": { "_yoast_wpseo_title": {{ $json.seo_title }}, "_yoast_wpseo_metadesc": {{ $json.meta_description }}, "_yoast_wpseo_focuskw": {{ $json.focus_keyword }} } }
Yoast vs RankMath: which meta keys to use

If you use Yoast SEO: meta keys _yoast_wpseo_title, _yoast_wpseo_metadesc, _yoast_wpseo_focuskw. If you use RankMath: rank_math_title, rank_math_description, rank_math_focus_keyword. If you use SEOPress: _seopress_titles_title, _seopress_titles_desc. Check your plugin and swap the meta keys in the request body accordingly.

Tags: turning keywords into tag_ids

The WordPress REST API accepts tags by ID, not by name. So between JSON parsing and post creation, you need one more Code Node that either creates the tags via the API or finds existing ones:

const keywords = items[0].json.keywords; const baseUrl = 'https://your-site.com/wp-json/wp/v2/tags'; const auth = 'Basic ' + btoa('user:app_password'); const tagIds = []; for (const keyword of keywords) { // Look up existing tag let res = await fetch( `${baseUrl}?search=${encodeURIComponent(keyword)}`, { headers: { Authorization: auth } } ); let tags = await res.json(); if (tags.length > 0) { tagIds.push(tags[0].id); } else { // Create a new tag res = await fetch(baseUrl, { method: 'POST', headers: { Authorization: auth, 'Content-Type': 'application/json' }, body: JSON.stringify({ name: keyword }) }); const newTag = await res.json(); tagIds.push(newTag.id); } } return [{ json: { ...items[0].json, tag_ids: tagIds } }];

The final node — Telegram Send Message — wires up the confirmation:

✅ Article created! 📝 {{ $json.title }} 🔗 {{ $json.link }} 🏷️ {{ $json.focus_keyword }} 🖼️ Cover image: uploaded ✓ SEO: title ✓ | meta ✓ | keywords ✓ | alt ✓ Status: draft — review and hit publish.
Full data map: what gets filled automatically

After the workflow runs, WordPress ends up with all of this auto-filled: title (H1), slug (URL), content (HTML), excerpt, featured image with alt/title/caption, tags, SEO title (Yoast/RankMath), meta description, focus keyword. All you have to do by hand is hit "Publish" — or change status to publish in the request.

Test and ship

Before you launch, test every scenario:

  • /start or a test topic → the bot triggers the workflow
  • OpenAI returns valid JSON with every field: title, seo_title, content, meta_description, focus_keyword, keywords, slug, excerpt, image_prompt, image_alt, image_title
  • The Code Node correctly parses all fields
  • DALL-E generates the image from the prompt (verify the URL in Executions)
  • The image uploads to the WP Media Library with correct alt, title, caption
  • WordPress creates the post with the slug, excerpt, featured_media, tags filled in
  • SEO fields are populated in Yoast/RankMath: seo_title, meta_description, focus_keyword
  • Telegram delivers a notification with the correct link and SEO status
  • The IF node blocks messages from unauthorized chat_ids

If everything works — click "Active" in the top-right corner of the workflow. The bot now runs 24/7.

Common launch issues

Most frequent problems: the webhook won't register (n8n isn't reachable over HTTPS), the AI returns markdown instead of JSON (add .replace in the Code Node), 401 from WordPress (use Application Password). All errors are visible in the "Executions" tab in n8n.

Extensions: advanced tricks

Open Graph and Twitter Cards

Add _yoast_wpseo_opengraph-title, _yoast_wpseo_opengraph-description, and _yoast_wpseo_twitter-title to your meta fields. When someone shares the article on social media, your optimized title and description show up — instead of a random text snippet.

Automatic internal linking

Add another OpenAI node after content generation: pass it a list of existing blog posts (via the WordPress REST API /wp-json/wp/v2/posts?per_page=50) and ask it to insert 2–3 relevant internal links into the text. This improves internal linking — one of the key SEO factors.

Moderation via Telegram

Instead of publishing automatically — send a preview with inline buttons "Publish" / "Reject". A separate workflow flips the status to publish. Control without extra clicks.

Autonomous mode

Swap the Telegram Trigger for a Schedule Trigger (cron) and pull topics from Google Sheets or Airtable. The system will publish on schedule — completely hands-off.

Multi-channel

The same content → parallel publishing to WordPress + a Telegram channel + social media. Use excerpt as the Telegram channel post, and meta_description for social media.

Extension Additional nodes Difficulty
Open Graph / Twitter Cards Extra meta fields in HTTP Request Easy
Internal linking HTTP Request (WP posts) + OpenAI Medium
Moderation (inline buttons) Telegram Wait + IF + WordPress Update Medium
Autonomous schedule Schedule Trigger + Google Sheets Easy
Multi-channel (TG + social) Telegram Send + HTTP Request Medium

Common errors and fixes

Problem Symptom Fix
Markdown instead of JSON Code Node: SyntaxError .replace(/```json\n?|```\n?/g, '') before parsing
401 from WordPress rest_cannot_create Use Application Password, not the main one
Bot open to everyone Strangers generate posts IF node with chat_id check
No formatting Text in one block Require HTML in the prompt (<h2>, <p>)
Workflow won't run Trigger inactive "Active" button in the top-right corner
Truncated JSON Incomplete AI response Increase max_tokens to 4000+
Cloudflare blocks 403 from WordPress Whitelist the n8n server IP in Cloudflare
DALL-E returns an error content_policy_violation Add to prompt: "no text, no logos, no copyrighted content"
SEO fields empty Yoast/RankMath shows nothing Check meta keys: _yoast_wpseo_* or rank_math_*
Alt not saved Image with no alt in Media Library Update media with a separate POST after upload
Tags not created 403 on POST /wp/v2/tags User role must be Editor or higher

Frequently asked questions

Can I use n8n for free for autoposting?

Yes, n8n is a fair-code platform. Self-hosted via Docker — free. A VPS at $15–25/mo replaces Zapier at $500+/mo. The only paid part is the OpenAI API (~$0.001 per article on gpt-4o-mini). The n8n.io cloud version also has a free tier.

Which AI model should I pick for article generation?

For typical blog posts — gpt-4o-mini (~$0.001/article, stable quality). For more complex ones — gpt-4o or Claude. n8n has built-in nodes for OpenAI, Anthropic, Gemini, and DeepSeek. 75% of n8n users actively use AI integrations.

Is publishing via the WordPress REST API safe?

Yes, with the right setup: Application Password (not the main one), HTTPS, IP restriction. WordPress validates permissions on every request. As of 2026, it supports 19 operations via AI agents with auto-saving to drafts.

How many articles per day can I generate?

There's no limit on the n8n side. Limits come from the API provider (OpenAI rate limits). In practice, 5–10 articles/day is comfortable. But remember: posts of 2000+ words get 77% more backlinks. Quality > quantity.

How is n8n different from Zapier?

The main thing is billing. n8n: 1 workflow = 1 execution (no matter how many nodes). Zapier: each step = a separate task. A 7-step workflow: n8n = 1, Zapier = 7. Plus self-hosting and full control. 183,000+ stars on GitHub.