Skip to main content

Signal-Led Targeting

Audience selection reuses the Signals v2 filter builder — the same signal fields, feedback metadata, custom person and company properties, nested rules, and generated goal-to-filter path you use on the Signals page. There is no survey-only targeting language to learn. The flow:
1

Describe who you want

State the goal next to the action that generates filters. BuildBetter turns it into real, editable Signals v2 filters — including nested rules — rather than hidden filter state or a count-only badge. You can inspect and adjust every rule before running it.
2

Review matched people

People are the primary result. Matching signals appear as why-matched evidence beneath each person, so you can audit inclusion. Each person is inspectable through the standard profile and company components.
3

Approve before adding

Nobody becomes a recipient until you approve them. Matched signal rows are deduped by canonical person email first, so one person with five matching signals is one row, not five.
Recipient metadata records the person’s canonical id, matched signal count, matched signal ids, and the latest signal summary where available — so months later you can still answer “why was this person surveyed?”
Manual email entry is available for one-off recipients. It’s a supplement, not the main model — workspace-contact search is deliberately not the primary targeting path.

Delivery Channels

A survey’s channel determines how it reaches people: For both surveys, email delivery problems — failed, suppressed, billing_blocked — do not close the in-app path. Only completion, or the survey/intercept activation rules, close it.

In-app delivery

Widget delivery requires your app to identify the current user by passing person.email and person.identitySignature through BuildBetterFeedback.create(...) or the equivalent script data attributes. identitySignature is a hex HMAC-SHA256 of the normalized lowercase email, using the widget config’s identityVerificationSecret. The public widget config endpoint strips that secret, so it is never exposed client-side. When the widget opens, it asks for an active survey recipient matching that verified email. If one exists, the widget renders the survey questions in place of the normal feedback form.
Without a valid identitySignature, the widget cannot match a recipient and will show the normal feedback form instead of your survey. This is the most common reason an in-app survey appears not to fire.

Recipient States

The recipients table distinguishes these states, and they are worth reading literally: For intercept recipients, the first widget display marks them sent. For both recipients, they stay pending_send so the queued email still goes out.

Send Limits

Throttles apply even when you have credits available, to protect sender reputation:
  • 1,000 invitations per hour per organization
  • 500 invitations per hour per survey
Recipients beyond current capacity stay pending_send. A once-per-minute cron asks the survey worker to drain eligible pending_send and billing_blocked recipients through the same bounded path as capacity frees up — you do not need to retry manually. Queue publication uses an atomic PostgreSQL reservation at both organization and survey scope. The organization lock also serializes the billing allowance check and counts pending reservations that haven’t hit the usage ledger yet, so concurrent bulk imports cannot over-reserve invitation credits.

Sender Identity and Deliverability

Invitations send from BuildBetter Surveys <noreply@surveys.buildbetter.ai>, or your configured survey display name at that verified domain. Reply-to is configurable; the From domain is not — arbitrary unverified customer domains are deliberately not supported. Respondent links use the environment’s verified survey domain:
Custom DKIM and customer sender domains are follow-up scope, not part of the current release.

Token security

Recipient rows store only invite token hashes, never raw tokens. Raw tokens exist only while an invitation is being queued or sent. Tokens do not encode recipient email or metadata. When a response link is rotated, prior hashes stay valid only for one-click unsubscribe — not for opening a new session.

Suppression

Bounces, spam complaints, and unsubscribes are recorded as organization-wide suppressions. A complaint on one survey suppresses future sends to that address across every survey in the organization.
  • Unsubscribe — invitations carry RFC 8058 one-click unsubscribe headers. Unsubscribing records the suppression and marks an incomplete recipient suppressed, including when the link came from an earlier invitation.
  • Bounce and complaint — Resend sends signed events, verified against the exact raw body with APP_RESEND_WEBHOOK_SECRET before anything is recorded.

Test Sends

Delivery setup can send an out-of-band test email. It uses the same renderer and organization sender settings, but it does not create recipients, enqueue jobs, or affect delivery counts — and preview sends are never billable. Preview emails link to a fillable saved survey using survey-specific sender identity, so what you check is what respondents get.

Next

Responses & Signals

What happens after someone answers.

Settings & Billing

Credit rates, allowance checks, and organization settings.