Unsubscribing during a campaign

  • A member who unsubscribes is taken out at once, with only the signed link and no account. A message already queued for them is stopped and marked as skipped, and everybody else's queued messages carry on. (npm run test:caps)
  • In a campaign to 196,019 members on a test copy, a member who unsubscribed before their message was handed to the queue was never handed over or sent. (npm run test:scale-200k)
  • Opening the unsubscribe link, in a browser or by Discord's link preview robot, changes nothing by itself: the member is unsubscribed only when they press the button. (npm run test:unsubscribe-link)

No member messaged twice

  • Two campaigns sending to the same members at the same moment, over many rounds, never both reach one member inside the frequency cap, and every member still gets exactly one message. (npm run test:cap-race)
  • The frequency cap counts across all campaigns, as a rolling window counted back from each message, not a calendar day or week. (npm run test:cap-race)
  • In the campaign to 196,019 members, every member was sent exactly one message, except the one who unsubscribed: 196,018 sent, none twice. (npm run test:scale-200k)

When Discord asks a bot to wait

  • When Discord answers with a rate limit and a Retry-After time, that bot is given no turn until the time has passed, and the other bots carry on. (npm run test:pace, npm run test:worker-rate)
  • Each bot sends at most 12 DMs a minute, one every 5 seconds. With 24 bots sending, no bot sent more than 12 in any minute. (npm run test:worker-rate)

Restarts, outages and backup bots

  • A backup bot never sends alongside the main bot. It takes over only when the main bot is offline, and with no backup left the campaign pauses rather than failing. (npm run test:failover)
  • If a bot's token is rejected in the middle of a campaign, the backup carries on and every member gets exactly one DM. With no backup, messages are held, not failed, until the token is replaced. (npm run test:bot-token)
  • After a two minute outage with no bot online, every held message is sent exactly once when the bot is back, even when the same job was queued twice. After 30 minutes with no bot, the waiting messages are marked failed with that reason, and nothing is sent. (npm run test:no-bot-hold)
  • After a worker restart, no queued job is lost and none is doubled, and a job lost from the queue is put back once. (npm run test:scale-200k)
  • A scheduled campaign whose start time passed while the worker was down starts once when the worker is back, and is never started twice. (npm run test:worker-catch-up)
  • When Discord may have received a message but its answer never came, the message is marked uncertain and is never sent again, by any bot. (npm run test:uncertain-sends)

What the numbers count

  • Sent means Discord accepted the message. Nothing computes a delivery rate or an open rate, and no screen or export calls a message delivered. (npm run test:analytics)
  • Reports are checked against a test campaign with a known mix: three accepted by Discord, two failed, one stopped before sending, six attempted. Every count matches. (npm run test:analytics)
  • A message whose answer from Discord never came is counted on its own, never as sent or failed. (npm run test:uncertain-sends)
  • In the campaign to 196,019 members, the campaign report, analytics over 7 and 30 days and the client report each counted all 196,018 sends. (npm run test:scale-200k)
  • A campaign is marked finished only when none of its messages is still queued or being sent. (npm run test:campaign-finish)

Bot tokens

  • A bot token is stored encrypted, never as it was typed, and no part of it is written to the audit log. Only Owners and Admins can replace one, after confirming two-factor. (npm run test:bot-token)

Your data: export and deletion

  • Export my data asks for your two-factor code or, without two-factor, waits for a link emailed to your verified address that works once, within 24 hours. Exports are limited per hour, and every export and download is in the audit log. (npm run test:account-export)
  • Export files are removed from storage 60 days after they were made, and the record that one was made stays. (npm run test:deletion-tools)
  • An account is deleted only for a request our team has approved, after a typed confirmation and a written reason. Billing records are kept, and no other account is touched. (npm run test:deletion-tools)

Measured on a test copy of 200,000 members

This comes from our test environment, a copy with 200,000 members, not from your server or ours in production.

  • With 24 sending bots the estimate was 11 h 21 min, 196,019 / (24 x 12) minutes, and the send, run in simulated time, finished on the estimate. (npm run test:scale-200k)

What the tests cannot show

The tests prove how BotLunar behaves on our test setup, with stand-ins for Discord. They cannot show what Discord does with a message after it accepts it, or whether anybody reads it.

Our uptime target is 99.5%. It is a target, not a guarantee; written commitments are made only in a Lunar Enterprise agreement. See live status.

Questions about any of this go to the team through the contact page.