Skip to content
HomeArticlesWorksContact

Nabeel Nashid © 2026

tutorial3 min read

How to Automate Social Media Posting with Python (Self-Hosted)

Build a free, self-hosted system that generates and publishes content across social platforms using Python, official APIs and scheduled jobs.

N
Nabeel Nashid
Designer & Developer

Posting to social media manually does not scale. If you run a brand, a publication or a side project, the busywork of writing captions, resizing images and posting at the right time quickly becomes a full-time job. The good news: it can be automated almost entirely, and it can run on a cheap machine you control.

This guide walks through the architecture of a self-hosted Python system that generates content, prepares media and publishes to multiple platforms on a schedule — the same approach I use for my own content infrastructure.

Why self-host instead of using a SaaS scheduler

  • Cost. A small VPS or even a home server costs a fraction of most social tools at scale.
  • Control. You own the pipeline, the data and the schedule.
  • Flexibility. You can add any platform, any AI model and any format without waiting for a vendor.
  • No per-post pricing. The marginal cost of publishing one more post is essentially zero.

The architecture

A reliable automated publishing system has five stages:

  1. Topic discovery — find something worth posting about.
  2. Content generation — write the caption, article or script.
  3. Media preparation — images, thumbnails or video.
  4. Publishing — send to each platform's API.
  5. Scheduling and retries — run on time and recover from failures.

1. Discover topics automatically

For many niches, trending topics are the highest-performing content. You can pull signals from public sources such as search trends, RSS feeds or community APIs, then score them by relevance to your niche.

import feedparser

def latest_headlines(feed_url):
    feed = feedparser.parse(feed_url)
    return [entry.title for entry in feed.entries[:10]]

Store candidates in a database with a status column (new, generated, published) so the pipeline is resumable.

2. Generate the content

Use an LLM to turn a topic into a caption, a thread or a short article. Keep prompts strict: specify the platform, the tone, the length and the call to action. Always keep the raw topic so you can regenerate if the output is poor.

prompt = f"Write a 120-word Instagram caption about {topic}. "
         f"Use a friendly tone and end with a question."

Store the generated text, not just the post, so you can review, edit and reuse it.

3. Prepare the media

Images are the most common failure point. Use a library like Pillow to resize to each platform's preferred dimensions and add safe margins so text is never cropped.

from PIL import Image

def square(path, size=1080):
    img = Image.open(path).convert("RGB")
    img.thumbnail((size, size))
    canvas = Image.new("RGB", (size, size), "white")
    canvas.paste(img, ((size - img.width) // 2, (size - img.height) // 2))
    canvas.save("output.jpg", quality=90)

Keeping media generation deterministic makes the whole pipeline easier to debug.

4. Publish through the official APIs

Each platform has its own API and rules. Instagram's Graph API, for example, requires a two-step flow: create a media container, then publish it.

import requests

def publish_instagram(image_url, caption, ig_user_id, token):
    create = requests.post(
        f"https://graph.facebook.com/v20.0/{ig_user_id}/media",
        params={"image_url": image_url, "caption": caption, "access_token": token},
    ).json()

    return requests.post(
        f"https://graph.facebook.com/v20.0/{ig_user_id}/media_publish",
        params={"creation_id": create["id"], "access_token": token},
    ).json()

Wrap every call in a retry with exponential backoff. Networks fail; your pipeline should not.

5. Schedule it reliably

On Linux, systemd timers or cron are enough. A simple pattern is a worker that wakes up every few minutes, checks the queue for due posts, and publishes them.

# crontab -e
*/10 * * * * /usr/bin/python3 /opt/publisher/worker.py >> /var/log/publisher.log 2>&1

Log every action. When something fails silently for a week, logs are the only way to know.

Reliability tips from production

  • Idempotency. Record a post id before publishing so a retry never double-posts.
  • Rate limits. Respect each platform's limits and back off when you hit them.
  • Secrets. Keep tokens in environment variables, never in the code or the database.
  • Human review. For brand accounts, a queue that requires one click to approve prevents embarrassing mistakes.
  • Monitoring. A daily summary message to your phone tells you the system is alive.

Final thoughts

A self-hosted publishing pipeline is one of the highest-leverage automations you can build. It turns a daily chore into a system that runs itself — and once it is stable, it can outperform manual posting simply because it never skips a day. Pair it with a fast site (see the Next.js SEO checklist) and your content starts working for you around the clock.

All articles