Broadcasts
One composer, every channel.
Send the same campaign to WhatsApp templates, SMS, email, and in-app — with audience uploads, platform rate caps, and audit-grade history baked in. No platform-policy footguns.
One composer, every channel
Author once, dispatch to WhatsApp, SMS, Email, Slack, and 7 more channels. Platform rules are enforced at compose time, not after a failed batch.
Policy-safe by default
Cold-send rules, opt-in checks, template requirements, and rate caps are baked into the composer. The wrong batch is structurally impossible.
Auditable to the row
Every recipient writes a delivery doc with status, provider message ID, and skip reason. Every run writes a parent doc with channel-level stats.
How it works
Audience in. Messages out. Every rule enforced.
Recipients flow through consent checks, cold-send validation, and rate limiting before any channel connector fires. One pipeline diagram, one mental model.
Broadcast dispatch pipeline
audience → validate → dispatch → trackConsent check
opt-in · cold-send
Rate limit
token-bucket
Dispatch
provider API
The composer
Five steps from idea to send — no platform-policy footguns.
The composer encodes platform rules in the same matrix the cron runner enforces. You see the verdict at audience-pick time, not at delivery time. Single source of truth, single mental model.
Composer pipeline
audience → channels → content → schedule → reviewAudience
Channels
Content
Schedule
Review
Audience
Pick where the recipient list comes from. Saved segments from the Audience Hub, an ad-hoc CSV / XLSX / paste upload, or every user who has ever chatted with the bot.
- ›Saved segment with live count from the Audience Hub
- ›CSV + XLSX upload — server-parsed via SheetJS
- ›Paste-list of phones and emails, one per line
- ›All past chatters of this bot (capped at 1,000 recent users)
- ›Optional checkbox: also save uploaded contacts to my audience
Channels
Toggle the bot's enabled deployment channels. Each channel is annotated with the platform rule — incompatible combinations are disabled with a clear reason.
- ›11 channels supported, gated by per-channel rule matrix
- ›Telegram, Web Widget, Discord blocked for cold-sends with explainer
- ›WhatsApp surfaces the approved-template picker for uploaded audiences
- ›SMS requires opt-in; Messenger / Instagram honor the 24h session window
- ›Email + in-app always available, no channel config required
Content
Author the message body with token placeholders for per-recipient personalisation. Optional LLM enrichment rewrites the template using the bot's persona at send time.
- ›{{user.displayName}}, {{user.email}}, {{bot.name}}, {{date}} placeholders
- ›Per-row variables from your upload merge automatically
- ›Toggle LLM enrichment with optional override prompt
- ›Falls back to the literal template if the LLM call errors
Schedule
Send once or recur on a cadence. 'Send now' pins the run to the next 5-minute cron sweep. Per-channel rate caps protect you from tripping platform throttles.
- ›One-time at a specific date/time, or recurring (hourly → monthly)
- ›Send now preset — pinned to +60s for the next cron sweep
- ›Per-broadcast rate-limit override (lower, never higher than platform cap)
- ›Timezone resolved from the operator's browser at create-time
Review
Final preview with recipient counts per channel, effective rate caps, and cost / policy warnings — including the WhatsApp template billing reminder when relevant.
- ›Per-channel recipient count from the resolved audience
- ›Effective rate cap line per selected channel
- ›WhatsApp template reference echoed back for confirmation
- ›Activate one-time or recurring with a single button
Channels
11 channels, one rule matrix — enforced everywhere.
Every channel is annotated with its cold-send verdict and the platform-derived rate cap. UI gating and runner-time enforcement read from the same source so the two can't drift.
| Channel | Identifier | Cold-send | Cap / min | Note |
|---|---|---|---|---|
| Open send | 600 | Resend-backed, generic HTML wrapper | ||
| In-app | user id | Open send | 1,200 | Drops into dashboard inbox |
| phone | Template only | 4,800 | Meta-approved template required for cold-send | |
| SMS (Twilio) | phone | Opt-in required | 60 | Carrier policy: documented consent required |
| Messenger | channel id | 24h window | 120 | Template or 24-hour session window |
| Instagram DM | channel id | 24h window | 120 | Template or 24-hour session window |
| Slack | channel id | Workspace only | 60 | Bot must be in the workspace / channel |
| Microsoft Teams | channel id | Workspace only | 60 | Within the connected tenant |
| Telegram | channel id | No cold-send | 30 | Recipient must /start the bot first |
| Web Widget | session id | No cold-send | 120 | Requires an active in-page session |
| Discord | channel id | No cold-send | 30 | Interaction model in progress |
Safety rails
Designed to fail closed.
The fastest way to get an account suspended is one bad batch. Broadcasts make the wrong batch impossible by surfacing rules at the right step.
Channel-rule guard
Cold-send block-list with platform-derived reasons surfaced at audience selection time, not after a failed dispatch.
Per-channel rate caps
Token-bucket limiter respects the documented platform ceiling. Operators can lower per-broadcast, never raise above it.
Fail-closed semantics
Missing template, missing opt-in, or mismatched identifier kind writes a skipped delivery row — never a half-sent batch.
Consent honoured
Segments inherit consent scope from the Audience Hub; the dispatch endpoint re-validates compatibility per recipient.
Delivery tracking
Auditable down to the wamid.
Every recipient writes a delivery row. Every run writes a parent doc with channel stats. Every lifecycle event lands in the audit log.
Per-recipient rows
Every send writes a botBroadcastDeliveries doc: queued → sent / failed / skipped, with provider message IDs where available.
Run history
Each broadcast firing emits a run doc with per-channel stats (sent / failed / skipped) and a 50-row error sample for triage.
Audit log
broadcast.created, broadcast.scheduled, and broadcast.deleted events land in the org-wide audit log with actor metadata.
Provider IDs
Twilio SIDs and Meta wamid values are stored on delivery rows so you can correlate against provider dashboards.
Lifecycle
Every message, tracked from queue to inbox.
Each recipient progresses through four stages. Failures and skips branch off with a reason code so you can triage without guessing.
Delivery lifecycle
queued → validated → dispatched → deliveredAudience
Get recipients in — your way.
Four ways to pick who gets the broadcast. Uploads stay ephemeral by default, with a one-click opt-in to mirror them into your reusable Audience Hub.
Saved segments
Reusable filters from the Audience Hub. Live-resolved at send time so the count stays fresh.
CSV / XLSX upload
Server-parsed with SheetJS. Auto-detects identifier kind, deduplicates by row.
Paste-list
Drop phones and emails one per line. Comma, semicolon, and pipe separators welcome.
All past chatters
Every user who has ever messaged this bot, capped at the 1,000 most-recent.
Questions
Frequently asked.
What channels can I broadcast on?
11 channels: WhatsApp (approved templates), SMS via Twilio, Telegram, Slack, Discord, Microsoft Teams, Messenger, Instagram DM, Web Widget, Email, and In-app notifications. Each channel is annotated with platform cold-send rules — if a channel can't reach an audience without prior contact, the composer blocks it before you send.
How do I upload a recipient list?
Three ways: CSV, XLSX (parsed server-side via SheetJS), or paste a list of phones and emails one per line. The server classifies each row, deduplicates by identifier, and returns a preview with warnings before you commit.
Do I have to add uploaded recipients to my audience?
No. By default uploads are ephemeral — they live on the broadcast doc. Tick 'Also save these contacts to my audience' to mirror them into endUsers via the same idempotent CSV write path the Audience Hub uses.
How does WhatsApp cold-send work?
Meta requires an approved business template for outbound messages outside the 24-hour session window. Authoring lives in Meta Business Suite; Rylvo pulls the approved-template catalog into the composer's picker via the Meta Graph API and dispatches the chosen template through the WhatsApp Cloud API.
How are rate limits enforced?
Every channel has a platform-derived rate cap encoded as a token bucket in the cron runner. Operators can lower per-broadcast but never raise above the documented ceiling. This prevents a hot run from tripping Twilio QPS limits or Meta per-number throughput throttles.
Can I see per-recipient delivery status?
Yes. Every dispatched recipient writes a row in botBroadcastDeliveries with status (queued / sent / failed / skipped), the provider message ID where available (Twilio SID, Meta wa-id), and a short error or skip reason. The History view groups these by channel and status.
Does the broadcast feature respect consent?
Yes. Channel rules encode regulatory and platform policy — SMS requires opt-in, WhatsApp requires a template, Telegram and Web Widget require prior contact. Audience segments already filter by consent scope, and the dispatch endpoint re-validates compatibility per recipient before calling the connector.
Can I schedule recurring broadcasts?
Yes. Pick a cadence — hourly, daily, weekly, biweekly, or monthly — and the cron runner advances nextRunAt automatically. For one-off blasts pick a date/time, or click 'Send now' for an immediate dispatch (the runner sweeps every 5 minutes).
Ship your first broadcast in minutes.
Sign in, pick a bot, upload a list — Rylvo handles the rest. Platform rules, rate caps, and delivery tracking are on by default.
