X3 asks one business question instead of analytics modelling: how do people reach you? It proposes a definition from a scan of your site, the last 30 days of events and your template; you confirm it with one click.
Roles
- Counts as an inquiry (role
lead, in the app „Anfrage“): forms, bookings, thank-you pages, contact data. A visit that reached such a goal counts as a lead once per person, also without contact data (fromGoals). A lead row (identify, POST /leads) wins. - Counts as a contact attempt (role
contact, „Kontaktversuch“): clicks on WhatsApp, phone, e-mail and external booking pages such as Doctolib. Counted separately, never part of the cost per lead and never sent to ad platforms by itself. - Not counted (role
step): funnel steps and micro goals.
Only a role a person chose counts as lead (roleConfirmed: „So übernehmen“, the goal wizard, or role in the API or MCP goal body). A role filled in by default (older goals, a template) shows as a proposal until it is confirmed, so a newsletter form never becomes a lead by itself.
Projects count with settings.leadCounting = rows_and_goals. Existing projects were switched once, automatically, with a timeline note; the switch changes no number of the past (leadCountingSince = the switch). Confirming in „Lead festlegen“ counts 30 days back and writes a timeline note that says by how much the number of the last 30 days changed. „Rückgängig“ before the switch keeps the project on rows. Conversions sent to Meta, Google, LinkedIn and TikTok do not change: they come from conversion definitions, never from roles, and no lead row is written or rewritten.
Every lead number counts the same leads: the Pulse, its sources, the ads report, breakdowns by channel and the Search Console pages add the inquiries without contact data by their visit; they are never qualified (nobody judged them). Lead rows marked as spam never come back through a goal. Limit: a lead row without a visit (server-side POST /leads, CRM webhook) cannot be matched to the visit that sent the form; on such sites make the form goal a step, or send session_id with the lead. Experiments and journeys keep counting lead rows (people with contact data).
Hand-off
Everything X3 cannot see by itself becomes an open point with a recipe. The owner shares a link to the technician page /setup-brief/<token> (status and recipes of one project, no visitor data, no keys, valid 30 days, revocable) or copies a task for an AI. X3 checks every point itself: it turns green with the first matching signal; test visits (?x3_test=1) count for the check, never for the numbers. A point that stays silent for 14 days while the site has visits becomes a problem again.
MCP: lead_setup_get, lead_setup_apply (dry_run first) and lead_setup_verify, prompt lead_setup. The technician page and its routes: Technician page and hand-off.
Recipes
install
The X3 code does not run on example.com yet. Without it X3 cannot count anything. About 10 minutes. Check: First visit.
Add the install code:
- Add the install code from X3 to the <head> of every page. X3 shows the code with your public key under Settings › Installation & status. It is public and may go into the page source.
- Test: open https://example.com/?x3_test=1.
iframe_form_redirect
The form on /callback is a Jotform window. X3 cannot see inside it when someone sends it. When the visitor lands on a thank-you page of your own afterwards, X3 counts that by itself. About 5 minutes. Check: View of /callback-thanks.
Way 1 · recommended, no code:
- Add a page /callback-thanks (e.g. callback-thanks/index.html). Add the X3 code from the <head> of the other pages there too.
- In Jotform, set the thank-you page of the form “Callback form” to a redirect. In the form settings, look for “Thank You Page” and “Redirect to an external link”. Address: https://example.com/callback-thanks
- Test: open https://example.com/callback?x3_test=1 and send the form once. The status turns green, usually within a minute. Tests never count in the numbers.
Way 2 · with code:
- Add this code below the embedded form on /callback. It reports the submission to X3. Without X3 on the page nothing happens.
<script> window.addEventListener("message", function (event) { if (!/(^|\.)jotform\.(com|eu)$/.test(new URL(event.origin).hostname)) return; var data = typeof event.data === "string" ? event.data : (event.data && event.data.action) || ""; if (data.indexOf("submission-completed") === 0) window.x3 && window.x3.track("form_submit", { form: "callback", via: "jotform" }); }); </script> - Test: open https://example.com/callback?x3_test=1 and send the form once. The status turns green, usually within a minute. Tests never count in the numbers.
iframe_form_postmessage
The form on /callback is a Jotform window without a thank-you page of your own. A small snippet reports the submission to X3. About 10 minutes, needs code. Check: Submission of “callback”.
With code:
- Add this code below the embedded form on /callback. It reports the submission to X3. Without X3 on the page nothing happens.
<script> window.addEventListener("message", function (event) { if (!/(^|\.)jotform\.(com|eu)$/.test(new URL(event.origin).hostname)) return; var data = typeof event.data === "string" ? event.data : (event.data && event.data.action) || ""; if (data.indexOf("submission-completed") === 0) window.x3 && window.x3.track("form_submit", { form: "callback", via: "jotform" }); }); </script> - Test: open https://example.com/callback?x3_test=1 and send the form once. The status turns green, usually within a minute. Tests never count in the numbers.
booking_adapter
Bookings through Jotform report to X3 as soon as X3 switches it on. Nothing changes on the website. About 0 minutes, only X3 configuration. Check: Booking via Jotform.
X3 switches it on:
- X3 listens for the booking message of Jotform. That happens when you confirm.
- Test: open https://example.com/callback?x3_test=1 and book a test appointment and cancel it afterwards. The status turns green, usually within a minute. Tests never count in the numbers.
booking_postmessage
The booking happens in an embedded calendar. A small snippet reports every booking to X3. About 10 minutes, needs code. Check: Booking via the calendar.
With code:
- Add this code after the calendar's embed code on /callback. It uses the calendar's “bookingSuccessful” message.
<script> if (window.Cal) window.Cal("on", { action: "bookingSuccessful", callback: function () { window.x3 && window.x3.track("booking", { via: "calendly" }); } }); </script> - Test: open https://example.com/callback?x3_test=1 and book a test appointment and cancel it afterwards. The status turns green, usually within a minute. Tests never count in the numbers.
booking_external
The booking happens at Jotform. X3 counts the click as a contact attempt. About 0 minutes, only X3 configuration. Check: Click on calendly.
Runs automatically:
- X3 counts clicks on links to calendly. It cannot count on that site itself.
name_forms
The forms on /callback have no name. With names X3 can tell them apart. About 5 minutes, needs code. Check: Submission of “callback”.
With one attribute:
- Give the <form> on /callback a data-x3-form attribute.
<form data-x3-form="callback" …> - Test: open https://example.com/callback?x3_test=1 and send the form once. The status turns green, usually within a minute. Tests never count in the numbers.
identify_after_success
Then you see in X3 who inquired and can judge inquiries. X3 respects consent by itself. About 15 minutes, needs code. Check: Inquiry with contact data.
After a successful submission:
- Call it only after the server answered successfully, never on the click on send.
window.x3 && window.x3.identify({ email: email, phone: phone }, { source: "callback" }); - Test: open https://example.com/callback?x3_test=1 and send the form with a test address. The status turns green, usually within a minute. Tests never count in the numbers.
inline_thankyou
The form on /callback shows its thank-you on the same page. X3 therefore also counts rejected submissions. About 10 minutes, needs code. Check: Confirmed submission.
After a successful submission:
- Add this call where the thank-you text appears.
window.x3 && window.x3.track("form_submit", { form: "callback", confirmed: true }); - Test: open https://example.com/callback?x3_test=1 and send the form once. The status turns green, usually within a minute. Tests never count in the numbers.
purchase
For X3 to show revenue and ROAS, the shop has to report every purchase. About 15 minutes, needs code. Check: Purchase reported.
Report the purchase:
- Report the purchase on the order confirmation (once per order).
window.x3 && window.x3.track("purchase", { order_id: orderId, value: total, currency: "EUR" }); - Test: open https://example.com/callback?x3_test=1 and make a test purchase. The status turns green, usually within a minute. Tests never count in the numbers.
quiz_events
The quiz does not report its submission yet. One call at the end is enough. About 10 minutes, needs code. Check: Quiz submitted.
With code:
- Call it after the last step of the quiz.
window.x3 && window.x3.track("quiz_submit", { variant: "callback" }); - Test: open https://example.com/callback?x3_test=1 and click through the quiz once. The status turns green, usually within a minute. Tests never count in the numbers.
Stacks
Every recipe has variants for WordPress, Webflow, Wix, Shopify, Next.js, React, Astro, HTML, Google Tag Manager. Menus of other tools are described as „look for …“ – they change.