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:
- the first URL has
?_rf_test=1(remembered for the whole funnel, also across domains); - the script tag has
data-test="true"(staging deployments); rf.testMode(true)was called;- the site is in site-level test mode (
set_test_mode), which flags every event of the site while active; - 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,scroll25/50/75/100,session_end- one
clickperdata-trackelement, with the element text quoted inhow - one
viewperdata-track-view video_playandvideo_progress10/25/50/75/90/100 perdata-video-idquiz_start,quiz_step1..N,quiz_completeperdata-quizform_start,form_submit,identifyperdata-track-form(usetest+<timestamp>@retafunnel.testas the email); when the form has the hiddenrf_*inputs,howasks you to check they were filled before submittingbooking_completedwhen 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 withstatusreceived— event arrived with the expected props and a valid schema (received_at,propsincluded)missing— no event with that name and props was seenmalformed— an event with the right name arrived but its props fail the schema or have the wrong types (problemsays what)
facts: whatsession_factsnow 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 }.passis 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_centsshould 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-runinstrument_html/ edit the HTML, thenvalidate_htmluntil 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. adata-quiz-stepthat is not a number) and the tracker version infacts; report it if the markup is correct. - When everything is green:
set_test_mode(site_id, 0)to disable test mode, removedata-test="true"from the script tag if you added it, andpurge_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 passesvalidate_html, nodata-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_definedis 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