Docs Reference

Testing a funnel

Test mode, the expected-event checklist, verification and the launch checklist.

This is the procedure an AI agent (or a careful human) follows after instrumenting a page, to prove that every event reaches RetaFunnel correctly, without touching live data or firing anything at Meta/Google. MCP tool names are exact. The same checklist is in the dashboard under Sites → Test mode.

Why test mode exists#

Test sessions carry is_test = true on every row (events, session_facts, visitors, persons, outcomes). They are excluded from reports, v_* views, segment refresh, daily rollups and every ad-platform sync, and are purged after 7 days (or on demand). A session is a test session when any of these is true:

  1. the first URL has ?_rf_test=1 (remembered for the whole funnel, also across domains);
  2. the script tag has data-test="true" (staging deployments);
  3. rf.testMode(true) was called;
  4. the site is in site-level test mode (set_test_mode), which flags every event of the site while active;
  5. the batch was produced by simulate_session.

The 7 steps#

1. Turn on test mode#

set_test_mode(site_id, minutes) (default 30). While active nothing you do can leak into live data, and you do not need to edit URLs. Confirm with get_test_mode(site_id). If you cannot change site state, open pages with ?_rf_test=1 instead.

2. Get the expected checklist#

get_test_plan(site_id, url) returns a TestPlan: the list of events this page should produce, derived from the registered page elements and the instrumented HTML:

  • pageview, attribution, scroll 25/50/75/100, session_end
  • one click per data-track element, with the element text quoted in how
  • one view per data-track-view
  • video_play and video_progress 10/25/50/75/90/100 per data-video-id
  • quiz_start, quiz_step 1..N, quiz_complete per data-quiz
  • form_start, form_submit, identify per data-track-form (use test+<timestamp>@retafunnel.test as the email); when the form has the hidden rf_* inputs, how asks you to check they were filled before submitting
  • booking_completed when a Calendly embed or link is present

Each item has an id, the event name, props_match (the props that must be present) and how (what to do). Read notes for page-specific caveats (missing script, no result screen on a quiz, …).

3. Walk the page#

With a browser (Claude in Chrome, Playwright, Puppeteer): open the URL (append ?_rf_test=1 unless site test mode is on), then follow every how instruction: scroll to the bottom slowly, click every CTA (use the browser back button when a CTA navigates away), press play on each video and seek past 10/25/50/75/90% and to the end, answer every quiz step until the result screen, focus and submit the form with test+<timestamp>@retafunnel.test, book a slot in Calendly if present (use a test event type), finally close the tab so session_end fires. Note the time you started.

Without a browser: call simulate_session(site_id, scenario, url) with one of smoke, full_funnel, vsl_50_no_lead, quiz_abandon, lead_and_purchase. This pushes realistic batches through the real ingest path and returns the session_id. Say explicitly in your report that the pipeline was exercised with a simulation, not with the real page, and still run validate_html on the page so the markup is checked statically.

4. Verify#

verify_test_session(site_id, since) (or with the session_id from a simulation) returns a TestVerification:

  • results[]: one entry per expected item with status
    • received — event arrived with the expected props and a valid schema (received_at, props included)
    • missing — no event with that name and props was seen
    • malformed — an event with the right name arrived but its props fail the schema or have the wrong types (problem says what)
  • facts: what session_facts now says (max_scroll_pct, max_video_pct, quiz_last_step, clicked, is_lead, …). Check that the facts agree with the events: 4 scroll milestones → max_scroll_pct = 100; identify → is_lead = true.
  • funnels[]: for every funnel of the site, the max step reached and which steps were hit.
  • summary: { expected, received, missing, malformed, pass }. pass is true only when nothing is missing or malformed.

Wait up to 60 s after the last action before concluding something is missing: batches flush every 5 s and the queue consumer runs asynchronously.

5. Outcomes and syncs#

  • simulate_outcome(site_id, name, email) with the same test email tests the Stripe/Calendly/CRM matching path end to end (is_booked, is_customer, revenue_cents should update on the test session).
  • check_sync_dry_run(segment_id) shows what a segment sync would send to Meta/Google, without sending it. Test rows never appear there; if a test visitor shows up, that is a bug to report.

6. Fix, repeat, clean up#

  • Something missing: usually a missing or misspelled attribute. Re-run instrument_html / edit the HTML, then validate_html until clean, redeploy, and run steps 3–4 again.
  • Something malformed: the props do not match the contract (wrong type, missing key). Check the element (e.g. a data-quiz-step that is not a number) and the tracker version in facts; report it if the markup is correct.
  • When everything is green: set_test_mode(site_id, 0) to disable test mode, remove data-test="true" from the script tag if you added it, and purge_test_data(site_id) if asked.

7. Checklist#

After the verification passes, run get_launch_checklist(funnel_id) (dashboard: funnel → Checklist). It returns a Checklist with ready and one item per requirement:

  • required: tracker_receiving (events in 24h), pages_registered (every URL step has a page), pages_valid (stored HTML passes validate_html, no data-test), test_session_passed (a passing test session in 7 days), steps_reachable (every step reached by a test session), funnel_steps_defined, test_mode_off
  • warnings: meta_connected, segments_syncing, outcome_source; experiment_defined is skipped unless variants were seen

Each failing item carries fix (what to do, with the tool to call) and href (where in the dashboard). Fix the required ones, re-run the checklist, then launch_funnel(funnel_id); it refuses while a required item fails unless force: true. Launching writes an annotation on every chart.

Reading a TestVerification quickly#

pass:      summary.pass === true
coverage:  summary.received / summary.expected
blockers:  results.filter(r => r.status !== 'received')  → fix these first, in page order
sanity:    facts.max_scroll_pct, facts.max_video_pct, facts.quiz_last_step, facts.clicked, facts.is_lead
funnel:    funnels[].max_step_reached vs the step you expected to reach

Report template#

Site: <name> (<site_id>)   Page: <url>   Mode: browser | simulation (<scenario>)
Expected <n> events · received <n> · missing <n> · malformed <n> → PASS / FAIL
Missing: click cta_footer (no data-track on the footer button) …
Fixes applied: …
Facts: scroll 100%, video 75%, quiz 3/3, lead yes
Funnels: "Main funnel" reached step 3/4 (optin)
Test mode: disabled · test data: purged / kept
Checklist: ready / not ready (<failing required items>)

Last updated