Capture methods lab.

Every integration method the collector supports, side by side and labeled. Each card fires the same events a real customer integration would; events carry widget_mode (headless / widget / declarative) so the paths can be compared row for row in the warehouse. One capture path per form — never wire two to the same form.

Address check — three integrations

A · Headless JS API

The site keeps its own form and its own serviceability checker; page JS calls trackAddressCheck with the address and the result. Fires address_check with widget_mode: headless.

B · Widget

LeadSmart renders its own form in a shadow root — zero page code beyond the mount. Fires address_check with widget_mode: widget. The empty-looking container below is the shadow root working, not a bug.

C · Declarative attributes

A plain HTML form with data-ls-* attributes and no JavaScript at all — the tag reads only the marked fields on submit. Fires address_check with widget_mode: declarative and demo_card: C. The phone field below is deliberately unmarked: it must never appear in any event.

Email capture — two integrations

D · Declarative lead form

Attributes only: data-ls-form="lead" + data-ls-email. The tag hashes the email in the browser (the mailbox never leaves the page) and fires lead_submit with form: methods_declarative.

F · GTM dataLayer bridge

The site pushes commerce state into window.dataLayer with ls.* event names; the tag forwards only those — GA4 and gtm.* pushes stay invisible. Values are real numbers end to end. Fires with widget_mode: datalayer.

E · Headless lead capture

Page JS calls identifyEmail (hash-only) and lead_submit with form: methods_headless — the checkout pattern.

Compare in ClickHouse: SELECT JSONExtractString(...) — see dumbfiber-site/README.md for the queries.