Skip to main content

Outbound capture runbook (Wix Forms → Contacts)

Operator SSOT for wiring Lead ("Leave a note") and Contribute form submits into Wix Contacts with Funnel: Leads, then ATP-gated handoff to Make / lemlist / Instantly.

Related: Outbound sequence SOP, CRM operator SOP, Inbox and outreach.

Repo mirror: docs/OUTBOUND-CAPTURE-RUNBOOK.md.

Capture path (smallest reliable)

  1. Browser submits via Headless Forms SDK (ContactForm.astrosubmitLeadToWixForms).
  2. Form postSubmissionTriggers.upsertContact creates/updates the Wix Contact (email + name mapping).
  3. Upsert applies labels:
    • Lead form: website-note + Funnel: Leads
    • Contribute form: website-contribute + Funnel: Leads
  4. INTERNAL board at /members/crm/ shows the contact under Leads (CRM BFF).
  5. Optional enrich: set AS source channel = web-form (form upsert does not write AS_* extended fields).
  6. Ability to pay: operator judgment in AS outreach notes (and Funnel move to Qualified when cleared). Do not invent ATP from the form.

Canonical form IDs (also in src/config/wix.ts / scripts/wix-site-policy.mjs):

  • Lead: eff382b4-4245-4ce7-aee6-39c9b25db6dc
  • Contribute: e10a9a3e-6ecb-4986-b4ef-dbf3c34fa574

Site forms must stay enabled. Site env: PUBLIC_LEAD_FORM_ENABLED=true (never ship disabled commercial forms without an explicit operator decision). Never put WIX_API_KEY in PUBLIC_*.

Scripts (this repo)

Auth: GitHub / Cursor secret WIX_API_KEY (preferred), or wix login then CLI token. Never put the key in PUBLIC_* or commit it to .env.

# Idempotent: ensure Funnel + website-* labels exist; patch both forms' upsertContact
npm run wix:outbound-capture:ensure

# Dry-run
node scripts/wix-outbound-capture-ensure.mjs --dry-run

# Verify form wiring (enabled + required labels)
npm run wix:outbound-capture:smoke

# After a real test submit, confirm the contact
node scripts/wix-outbound-capture-smoke.mjs --email=you+test@example.com

# Set AS source channel = web-form when empty (dry-run default)
npm run wix:outbound-capture:enrich
node scripts/wix-outbound-capture-enrich.mjs --apply --limit=25

# Pure helper self-test (no Wix auth)
npm run test:outbound-capture

Form create scripts (wix-create-lead-form.mjs, wix-create-opensource-form.mjs) should leave upsertContact labels non-empty after ensure; re-run ensure after recreating a form.

Ivan HITL — when Cursor / agent lacks WIX_API_KEY

Agents without the secret cannot call Forms/Contacts admin APIs. Do not compensate by blasting many production form submits. Prefer the API smoke path below on a machine that has the key (local shell, Actions, or Cursor env secret for site 0b498e2e-d8ea-4bec-9d56-1d4b74845393).

cd /path/to/ambientsystems.ai
export WIX_API_KEY='…' # same secret as CI Deploy Wix / CRM BFF bake
npm run wix:outbound-capture:ensure
npm run wix:outbound-capture:smoke
# Expect both forms: enabled true, ok true, Funnel: Leads label present
# Optional — one controlled UI submit, then:
node scripts/wix-outbound-capture-smoke.mjs --email=you+capture-test@example.com
# Expect hasFunnelLeads: true

Also add WIX_API_KEY to the Cursor Cloud environment secrets for this repo so future agents can run ensure/smoke without HITL.

Smoke checklist (confirm Funnel: Leads)

  1. Confirm home still exposes the form: data-use-wix-forms="true" and a non-empty data-wix-form-id on https://www.ambientsystems.ai/.
  2. Run npm run wix:outbound-capture:smoke — both forms ok: true, enabled: true, labels include custom.funnel-leads (or the live Funnel: Leads key).
  3. Submit a unique test email on home (Leave a note) or product Contribute. Wait until the UI shows success. Do not spam production forms — one controlled submit per verification.
  4. Run node scripts/wix-outbound-capture-smoke.mjs --email=<that-email> — expect hasFunnelLeads: true.
  5. Optional: Dashboard Contacts or INTERNAL /members/crm/ — contact appears under Leads.
  6. Optional: node scripts/wix-outbound-capture-enrich.mjs --email=<that-email> --applyAS source channel becomes web-form.
  7. ATP: leave blank / note "ATP unclear" until an operator clears ability to pay; only then move to Qualified and allow sequencer export.

Local browser submit (forms only, not label check): npm run test:contact-form against a running astro / astro dev.

Wix Automations HITL — thank-you + Make webhook

No wix:outbound-capture:ensure for thank-you mail. Automations V2 REST exists (/automations-service/v2/automations), but wiring a send-email thank-you needs verified sender, email template/body mapping, SCOPE.CRM.SETUP-AUTOMATIONS, and Validate-before-activate — none of that is in the existing form/label scripts. Do not add a half-baked ensure script here. Author thank-you + Make in the Wix Dashboard (Automations) until an operator deliberately scopes an Automations ensure. Keep scenario URLs and secrets in hub local notes (commercial/local/) / 1Password, never in PUBLIC_* or marketing copy.

Form schema automationId (printed by smoke) is the Forms app association — it is not proof a thank-you email automation exists.

Dashboard: https://manage.wix.com/dashboard/0b498e2e-d8ea-4bec-9d56-1d4b74845393/triggers

A — Thank-you email (submitter confirmation)

Do this first. It does not require ATP and must not enroll sequencers.

  1. Wix Dashboard → Automations (link above) → create or edit automation for Wix Forms submission on Lead and/or Contribute (form IDs above). Prefer one automation per form if the UI forces a single form trigger.
  2. Trigger: Form submitted / wix_form_app-form_submitted filtered to the Lead or Contribute form id.
  3. Action: Send email (Wix Emails / verified sender domain) to the submitter.
  4. Copy: short confirmation only (received + next step is human review). No pricing, no pilot claims, no "we will enroll you in outreach."
  5. From: company verified sender (Settings → Emails). Confirm domain authentication before relying on deliverability.
  6. Test: one disposable submit → inbox receive. Check spam once. Confirm no second automation also sends a duplicate thank-you.
  7. Record: automation name + ID in hub local notes.

B — Form submission → Make (capture fan-out, HITL)

  1. Create Make scenario in the company workspace (not a personal throwaway). Webhook module first; store URL in 1Password / hub local.
  2. Wix Automations → trigger on the same form submit (or sibling automation).
  3. Action: Webhook POST to Make. Map payload: email, form id / name, submission id, contact id if present, label keys, timestamp.
  4. Make filter (required): continue only if contact has Funnel: Leads (or website-note / website-contribute). Drop honeypot / empty email / obvious spam.
  5. Downstream (default off): log to a sheet or notify Slack/email for INTERNAL review. Do not auto-create lemlist/Instantly leads from Stub B until ATP is cleared.
  6. HITL gate: operator reviews Make (or CRM board) before any sequencer action. Document who owns the review in hub local.
  7. Test: one disposable email; confirm Make receives payload; confirm sequencer remains empty.

C — ATP gate → lemlist or Instantly

  • Trigger: Make schedule or Wix contact label change to Funnel: Qualified (ATP cleared), not raw form submit.
  • Filter: AS source / STP bucket acceptable; AS outreach notes show ATP cleared; cooldown empty or past.
  • Action: Create/update lead in lemlist or Instantly campaign (company account only). Sequencer is not the funnel SSOT — mirror stage on Wix Funnel labels.
  • Do not: auto-push every website-note into cold sequences.

D — Stage change fan-out (optional)

  • Trigger: Contact label updated (Funnel:*).
  • Action: Make webhook → update sequencer status / pause on Parked / Closed.

Operator checklist (thank-you + Make)

Use this as the close-out list after form capture smoke is green:

  1. Thank-you automation exists for Lead form; verified sender; one test receive OK
  2. Thank-you automation exists for Contribute form (or shared rule covers both); no duplicate sends
  3. Make scenario created in company workspace; webhook URL stored in hub local / 1Password (not git)
  4. Wix Automations webhook attached to form submit; payload maps email + form id + labels
  5. Make filter requires Funnel: Leads (or website-* labels); spam path drops
  6. Default Make path stops at notify / log — no lemlist/Instantly enroll until Qualified + ATP note
  7. Qualified → sequencer path (Stub C) documented separately; ATP still operator judgment
  8. Concrete automation + Make scenario IDs recorded only in hub local notes
  9. Forms remain enabled on production home / product after testing

Anti-patterns

  • Cloudflare Workers CRM path (retired)
  • WIX_API_KEY in PUBLIC_* or browser bundles
  • Auto-enrolling form leads into lemlist/Instantly without ATP
  • Disabling home Lead / Contribute forms without an explicit operator decision
  • Inventing weekly reply metrics or throwaway demo accounts
  • Shipping thank-you copy that promises outreach enrollment or pricing