Automating Social Media Posts with Trello
I wanted a way to queue up social media posts from my phone or the web and have them go out on a schedule without paying for anything. Trello is free and has an API, so I used a Trello board as a post queue. No need to build a front end.
What It Does
You create Trello cards on a designated list. The card title becomes your post text. Attach an image and the card description becomes its alt text. Run it as a daemon and it pulls cards off the list and posts them to Twitter/X, Bluesky, and Mastodon.
No web interface or database needed.
How It Works
The core loop is straightforward — grab a card, turn it into a post, send it everywhere, delete the card:
def post_job(trello: TrelloClient, posters: list) -> None:
cards = trello.get_cards(limit=1)
if not cards:
log.info("no cards available to post")
return
card = cards[0]
post = trello.card_to_post(card)
log.info("posting card: %s", card.name)
results = post_to_all_platforms(post, posters)
if any(r.success for r in results):
trello.delete_card(card)
A card gets converted into a CardPost dataclass that each platform poster knows how to handle. If a card has an image attachment, the image is downloaded and bundled with the post:
@dataclass
class CardPost:
text: str
image_bytes: bytes | None = None
image_mime: str | None = None
alt_text: str | None = None
Failures on one platform don't block others — if Bluesky is down but Twitter works, the card still gets posted and deleted. Posting to at least one platform is good enough for my use case.
Scheduling
Post times and randomization are configured in TOML:
[schedule]
post_times = ["09:00", "13:00", "18:30"]
post_time_randomization = 600 # +/- seconds
Under the hood it uses APScheduler with cron triggers. The randomization offsets each job's trigger time and adds jitter so posts don't land at the exact same second every day:
for time_str in cfg.schedule.post_times:
hour, minute = time_str.split(":")
base = datetime(2000, 1, 1, int(hour), int(minute))
shifted = base - timedelta(seconds=r)
job_kwargs = dict(
func=post_job,
trigger=CronTrigger(
hour=shifted.hour, minute=shifted.minute, second=shifted.second,
),
args=[trello, posters],
)
if r > 0:
job_kwargs["jitter"] = r * 2
scheduler.add_job(**job_kwargs)
Setup
Install with pipx, copy the example config to ~/.config/trello-post-scheduler/config.toml, and fill in your API keys. You can run it as a daemon via the included systemd user service:
[Service]
Type=simple
ExecStart=%h/.local/bin/trello-post-scheduler --config %h/.config/trello-post-scheduler/config.toml
Restart=on-failure
RestartSec=30
Or trigger it with your own cron scheduler using --once to post a single card and exit.
The Repo
Source code and setup instructions: github.com/tylerhenthorn/trello-post-scheduler