Configuration

Everything Signal asks and offers comes from your project's configuration: a JSON document you edit in the dashboard (Configuration), publish with the Server API, or let the setup wizard write. Every change becomes a new version; you can restore an older one at any time.

Keys (ids) start with a letter and use letters, digits, _ or -. Texts may use the placeholders {firstName} and {company}.

{
  "project": "acme",
  "language": "en",
  "mode": "live",
  "pages": [{ "match": "/pricing", "category": "pricing", "important": true }],
  "signals": { "...": {} },
  "questions": { "...": {} },
  "routes": { "...": {} },
  "offers": { "...": {} }
}

Signals

What Signal estimates about each visitor, each with a confidence between 0 and 1.

"signals": {
  "lookingFor": {
    "type": "choice", "label": "Looking for", "important": true,
    "instructions": "What is this visitor most likely looking for?",
    "options": { "website": "A new website", "app": "A web app", "other": "None of these" }
  },
  "timing": {
    "type": "score", "label": "Timing",
    "instructions": "How soon does this visitor want to start?",
    "levels": ["Just looking", "This year", "This quarter", "Now"]
  }
}
Type Fields
choice instructions, options (2 or more)
score instructions, levels (2–10, low to high)
proposition question (a yes/no question), optional criteria: { true, false }

All types take label, important (shown in alerts and Insights) and bands: { ignoreBelow: 0.3, askBelow: 0.8 }: below askBelow, Signal may ask a question to be sure.

Pages

"pages": [
  { "match": "/pricing", "category": "pricing", "important": true },
  { "match": "/services/*", "category": "service" },
  { "match": "/blog/**", "category": "blog" }
]

* matches one path segment, /** at the end any depth. The first view of an important page makes Signal re-estimate the visitor.

Questions

"questions": {
  "whatKind": {
    "text": "What kind of business do you run?",
    "learns": ["businessType"],
    "priority": 5,
    "input": {
      "type": "choice",
      "options": [
        { "id": "agency", "label": "Agency or services", "sets": { "traits": { "segment": "agency" } } },
        { "id": "shop", "label": "Online shop" }
      ],
      "other": { "label": "Something else…", "trait": "businessOther" }
    }
  }
}
Field Meaning
text The question.
learns Signals the answer settles; Signal asks when one of them is unsure.
priority Higher is asked first.
when A condition that must hold.
repeatable Ask again after it was answered (default false).
input choice (options, optional other for a typed answer), text (writes: identity.name, identity.company or trait), or email (consentText).

Choice options can set traits and, for shops, filters (productType, tags, vendor, collection, priceMin, priceMax) used by product recommendations.

Routes

The ways a visitor can take the next step. Common fields: label, effort (low, medium, high), description, needs (contact fields to ask for).

Type Extra fields Notes
book eventUrl, display (panel or tab) A booking page, e.g. Calendly, shown in the popup or a new tab.
callback timeOptions, confirmation Always asks for a phone number.
message channel (whatsapp, sms, telegram), number, prefill Opens a chat app with a prefilled message.
send_resource resourceUrl, emailTemplate { subject, body, button }, allowDirectOpen, confirmation Emails a guide; always asks for an email address.
lead_form needs, confirmation A short contact form.
link url, target (_blank or _self) Any link, e.g. a trial sign-up.
subscribe list, confirmation Newsletter sign-up with marketing consent.
chat greeting Opens a live chat with your team.
products intro, mode (answers, similar, both), count (1–3) Matching products from your Shopify catalog.

Offers

"offers": {
  "readyToTalk": {
    "when": { "type": "signal_equals", "key": "leadTemperature", "value": "hot", "minConfidence": 0.75 },
    "text": "Want to talk it through with our lead developer?",
    "routes": ["call", "guide"],
    "priority": 10
  }
}

show (1 or 2 routes at once), priority, and pressure (low offers only low-effort routes). reach.maxOffersPerVisit (default 2) limits offers per visit.

Conditions

Used by offers, questions, follow-ups and rules.

Type Fields
signal_equals key, value (an option), minConfidence?
signal_score_gte key, value (a level number, 0 = the first level), minConfidence?
proposition_gte key, value (0–1)
trait_equals key, value
identity_known field: name, email or company
answered question
products_viewed_gte value (number of product pages)
all, any conditions: [...]

Forms

"forms": {
  "earlyAccess": {
    "title": "Get early access",
    "questions": ["whatKind", "whenStart"],
    "goal": ["businessType", "timing"],
    "contact": { "needs": ["name", "email"], "message": true },
    "confirmation": "Thanks {firstName}, we'll be in touch."
  }
}

Embed with <div data-signal-form="earlyAccess"></div>. The form skips questions that are already answered and stops asking once its goal signals are settled (or after maxQuestions, default 5).

Follow-ups

A short email a few days later, only to visitors who agreed to be contacted.

"followUps": {
  "afterGuide": {
    "after": "delivered", "waitDays": 3,
    "subject": "Did the guide help, {firstName}?",
    "body": "Hi {firstName},\n\nAny questions about the guide? Happy to help.",
    "button": "Book a call", "link": { "route": "call" }
  }
}

after: contact_given, delivered, form_submitted, callback_requested, booked or clicked. stopIf (default booked, won, unsubscribed, declined) cancels it.

Rules and actions

Rules run actions when a condition becomes true, for example a webhook:

"actions": { "toCrm": { "type": "webhook", "integration": "crm", "maxPerVisitor": 1 } },
"rules": [{ "id": "hot-lead", "when": { "type": "signal_equals", "key": "leadTemperature", "value": "hot", "minConfidence": 0.8 }, "then": ["toCrm"] }]

Other action types: show_message, show_resource, show_cta, open_url, open_calendar and emit_event. Every action has a cooldown (default 1d) and an optional maxPerVisitor.

Notifications

"notifications": { "to": ["sales@example.com"], "events": ["lead_reachable", "callback_requested", "booked", "form_submitted", "chat_message"] }

Team alerts by email, with the whole visit.

Privacy, brand and language

"privacy": {
  "region": "eu",
  "texts": { "followUpConsent": "You may contact me about my request.", "privacyUrl": "https://example.com/privacy" },
  "retention": { "contactMonths": 24, "eventMonths": 3, "outcomeMonths": 24 }
},
"brand": { "siteUrl": "https://example.com", "senderName": "Acme", "accentColor": "#2f5bea", "popupTheme": "light" },
"language": "en"
  • privacy.region (eu, uk, us, other) sets consent defaults and the storage default.
  • language is en or nl; ui overrides any built-in word (e.g. { "noThanks": "Not now" }).
  • mode: "shadow" records what Signal would do without showing or sending anything.