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.

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.

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:

EventFires when
booking.created / booking.rescheduled / booking.canceledScheduling activity
contact.createdA form submission becomes a contact
contact.stage_changedA lifecycle stage moves (campaign or manual)
email.opened / email.clickedEngagement lands from the email provider
campaign.event_executedThe 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.