Marketing Automation
BusinessDash ships a full marketing-automation suite modeled on Mautic's proven shapes, org-scoped and consent-first. This page maps every piece, where it lives in the dashboard, and what a developer integrating through the SDK or webhooks needs to know.
Segments
Dashboard → CRM → Segments. A segment is a saved filter over contacts
(status is new, tags include vip, points ≥ 50, …). Membership is
materialized: a sweep rebuilds it every 15 minutes, so everything
downstream — broadcasts, campaigns, SMS — reads a member list rather than
re-running filters at send time. Manual adds and removes are tombstoned:
a contact you removed by hand never gets re-added by the rebuild.
Broadcast email campaigns
Dashboard → Marketing → Email Campaigns. Audience = segments
(include/exclude). Sends are drained by a worker at a bounded rate with
eligibility re-checked per recipient at send time (suppression list,
unsubscribes, contact-level do-not-contact). Every marketing email carries
an unsubscribe link automatically — composers that omit the
{{unsubscribe_url}} token get a footer appended rather than the send
going out without one.
Automation campaigns (the engine)
Dashboard → Marketing → Marketing Campaigns. A campaign is a tree of events over contacts, executed every five minutes:
- Actions — send email, send SMS, change tags, change segments, adjust points, change lifecycle stage, notify staff, create a task, send a webhook.
- Decisions — "opened the email?" / "clicked a link?" with a wait window; the no branch fires when the window lapses unanswered.
- Conditions — field values, segment membership, tags, points thresholds, lifecycle stages, do-not-contact status.
Contacts enter through segment sources. Every step executes exactly once per contact per pass — the engine's log carries a uniqueness key that makes restarts and re-sweeps safe.
Scoring, lifecycle stages, do-not-contact
Dashboard → Marketing → Scoring & Stages.
- Point rules score behavior (email opens, clicks) automatically; campaigns branch on the score with the Points threshold? condition. Every change is logged with its cause.
- Lifecycle stages are weight-ordered marketing maturity labels (Subscriber → MQL → SQL). Campaigns can move contacts between stages — and by design nothing in marketing can ever convert a lead into a client; that stays a manual CRM decision.
- Do-not-contact is unified per contact per channel (email / SMS) with Mautic's reason codes: unsubscribed, bounced, manual. It is written by unsubscribe links, bounce/complaint webhooks, SMS STOP replies, and staff — and read by every send path at send time.
Tracked links, UTM, and visitor identity
Outbound emails rewrite their links through a per-org redirect
(/l/{token}), giving real click attribution per contact and per
channel. UTM parameters land on the contact's timeline from both tracked
links and form submissions.
Visitor identity is consent-gated (Dashboard → Settings → Legal → Data collection & visitor consent):
- With marketing data collection enabled, the org's published sites render a consent banner. A visitor who grants marketing gets a stable first-party visitor id cookie; their page views flow into the visitor activity log, and an email click or form submission later binds that anonymous history onto their contact record.
- Privacy-focused orgs (marketing off) never mint a stable identity — analytics stay rotating-anonymous. Do-Not-Track and Global Privacy Control are honoured server-side, and UK/EU visitors are always opt-in.
Consent from SDK-built sites
SDK sites use the same policy through the package API:
import { loadConsent, recordConsent } from "@businessdash/sdk/consent";
const consent = await loadConsent({ client });
if (consent.mustAsk) {
// render your banner, then:
await recordConsent({ client, granted: ["analytics", "marketing"] });
}
if (consent.allows("marketing")) {
// safe to run marketing collection
}
The SDK stores the visitor key in a first-party cookie on your domain and sends it with every consent call — visitors are isolated per org by construction.
SMS campaigns
Dashboard → Marketing → SMS Campaigns. Segment broadcasts over text. Every recipient is gated at send time: promotional opt-in, SMS do-not-contact, the org's own STOP list, and the org's dedicated sending number — texts never leave on a shared number. The campaign engine's Send SMS action goes through the identical gate chain.
Reports
Dashboard → Marketing → Reports. Saved reports over a closed source registry — contacts, segment membership, email recipients, campaign activity, form submissions, the points log — with grouping, counting, and time-series buckets. Reports can email themselves on a schedule (daily / weekly / monthly). Five one-click presets carry the classic dashboard questions: emails over time, best send hours, campaign events triggered, top segments, submissions over time.
The org event bus (webhooks)
Webhook endpoints subscribe to org events and receive signed POSTs
(X-Signature: sha256=… over the raw body) with automatic retry and
backoff. An endpoint that keeps failing for three days is disabled
automatically; any success clears the streak. Current events:
| Event | Fires when |
|---|---|
booking.created / booking.rescheduled / booking.canceled | Scheduling activity |
contact.created | A form submission becomes a contact |
contact.stage_changed | A lifecycle stage moves (campaign or manual) |
email.opened / email.clicked | Engagement lands from the email provider |
campaign.event_executed | The automation engine executes a step |
Saved messages
Dashboard → CRM → Saved Messages. A single org library of reusable message snippets. Every composer — customer messages, campaign email and SMS steps, SMS broadcasts — and the process-pipeline automation editor offers the library from its Saved button, including saving the current draft as a new entry without leaving the composer. Repetitive replies live here instead of a notes app.
Quizzes: hiding the score, and results behind an account
Quiz assessments (interviews especially) can be set to not show the taker their score: the taker completes the quiz — time limits still enforced — and sees only a confirmation. The score, pass verdict, and per-question feedback are withheld server-side from every taker-facing response; your team sees full results in the dashboard.
A second option, require an account to view results, turns the reveal into an onboarding step: the taker finishes freely, then signs in — or creates an account with the invited email — to unlock how they did.
Reading results from your own site
The signed-in customer's quiz results are available to SDK-built sites:
const portal = client.customerPortal();
const { items } = await portal.myQuizResults();
// items[i].result — score, pass verdict, per-question outcomes
// items[i].scoreWithheld — an interview-mode quiz: render "completed" only
This endpoint is deliberately hard to abuse: it answers only to the customer's short-lived signed-in session (a long-lived API key alone reads nothing), and only when the request originates from a domain your organization has verified on file — so a leaked key never exposes assessment data.
Staff notifications
Staff-facing notifications (campaign Notify staff steps and newer surfaces) fan out to the in-app bell and to browser push and native push for staff who enabled them — enable from Dashboard → Account → Notifications in a supported browser.