Skip to the content.

Auto-post Skool event reminders to the feed

Skool sends an email when you create an event, and another email at the start. Email open rates being what they are, that’s not enough to keep attendance up. The feed is where the active members live — a timely reminder post 24h + 1h before an event is the lever that consistently doubles attendance.

This recipe is the cron-driven flow used in production to announce events for Cágala, Aprende, Repite’s weekly Cafecito, Workshops, and Posting Party. Same pattern works for any recurring event.

Quick reference (TL;DR for agents)

   
Goal Auto-post timed reminders to the feed for upcoming Skool events
Stack n8n / Python + cron (hourly trigger)
Actions used events:upcomingposts:create
Setup time ~15 min (workflow + first event)
Ongoing cost $0.02 per reminder (2 reminders per event = ~$0.04/event)
Cadence 24h + 1h before each event
Key gotcha Idempotency — don’t double-post if the cron runs twice in the same window

Prerequisites

How the timing logic works

The action events:upcoming returns events with their startsAt timestamp. Your cron runs hourly, and for each event you compute the delta:

now ≤ startsAt − 24h ≤ now + 1h  →  post the "tomorrow" reminder
now ≤ startsAt − 1h ≤ now + 1h   →  post the "in 1 hour" reminder

The 1-hour bucket size matches the cron cadence — each event hits each reminder slot exactly once. To prevent double-posting if the cron is re-triggered (network retry, manual run), de-dupe by event_id + reminder_type in a small state store (NocoDB row, a flat JSON file, anything).

Step 1 — List upcoming events

{
  "action": "events:upcoming",
  "cookies": "...",
  "groupSlug": "your-community",
  "params": { "limit": 20 }
}

Returns events sorted by startsAt ascending. Each event includes id, title, startsAt, endsAt, description, joinUrl (Zoom/Meet/etc), and attendeeCount.

Step 2 — Compute reminder timing

For each event, check if it falls in the 24h or 1h window relative to now:

from datetime import datetime, timedelta, timezone

now = datetime.now(timezone.utc)
for event in events:
    starts_at = datetime.fromisoformat(event["startsAt"].replace("Z", "+00:00"))
    delta = starts_at - now
    if timedelta(hours=23) < delta <= timedelta(hours=24):
        post_reminder(event, kind="24h")
    elif timedelta(minutes=0) < delta <= timedelta(hours=1):
        post_reminder(event, kind="1h")

The window edges (< 24h, ≤ 24h) match a 1-hour cron precisely. If your cron is 30-minute, narrow the windows.

Step 3 — Post the reminder to the feed

{
  "action": "posts:create",
  "cookies": "...",
  "groupSlug": "your-community",
  "params": {
    "title": "📅 Mañana: Cafecito Startup — 12:00 hrs",
    "content": "Mañana nos juntamos a hablar de... Trae tu pregunta, tu update, lo que estés trabajando. Link de Zoom en el evento: https://www.skool.com/your-community/calendar",
    "labelId": "announcements_label_id"
  }
}
Field Notes
title Short, time-stamped. “📅 Mañana: …” for 24h, “🔴 EN 1 HORA: …” for the 1h.
content Plain text. Include a link to the Skool calendar so members 1-click into the event detail page.
labelId Tag the post with your “Anuncios” / “Announcements” category so it doesn’t get lost in the feed. See Categories of CAR feed.

Step 4 — De-dupe via your state store

After posting, write to your state store:

# pseudo: prevent double-post
state[f"{event['id']}-{kind}"] = {"posted_at": now.isoformat(), "post_id": response["post"]["id"]}

On the next cron tick, skip if the key exists. The whole de-dupe layer is ~10 lines — don’t over-engineer.

Full workflow JSON (n8n)

The production version uses n8n with a Cron trigger every hour → HTTP Request to the actor (events:upcoming) → Function node to compute deltas → Switch (24h / 1h) → HTTP Request to actor (posts:create) → NocoDB upsert to de-dupe store.

The JSON is in the repo at n8n-templates/skool-events-to-whatsapp.json — it’s the same logic adapted for WhatsApp/Telegram, swap the final node for posts:create to post to the Skool feed instead.

Production gotchas

See also


Use this in production — no setup

The hardest part of building Skool automation isn’t the API logic — it’s the auth (cookies expire every ~3.5 days, WAF token rotation, weekly Skool buildId changes). The Skool All-in-One API actor on Apify handles all of that.

→ Open the actor on Apify

New to Skool? Launch your community here — 14-day free trial. Need an n8n instance? Get started free — the workflow tool we use throughout these recipes.