Plan · not yet implemented

Guide Me — integration

Status: plan, not implemented. Pick this up when ready. Captured: 2026-05-01.

Goal: ship the Guide Me survey as an embeddable widget that any FundedNext surface (landing pages, dashboard, model-specific pages, third-party partner sites) can drop in with one <script> tag — same pattern as Intercom, Google Tag Manager, Weglot.

Two embed modes:


Architecture: iframe-based

The widget loads inside a sandboxed <iframe>. Total isolation: parent CSS cannot leak in, our CSS cannot leak out, and the React tree is independent so there's no version conflict with whatever the host runs. Updates ship from our side without partners needing to redeploy.


Public JS API

Auto-init via <script> (Intercom-style)

<!-- Drop this once in <head> on any page that needs the survey -->
<script async src="https://guide.fundednext.com/embed.js"
        data-app-id="fundednext_main"
        data-default-product="futures"></script>

<!-- Anywhere on the page: any element with data-guide-me="open" auto-binds -->
<button data-guide-me="open" data-product="cfd">Help me choose</button>

The loader auto-scans for [data-guide-me] elements and wires them up. Re-scans on DOM mutation so dynamically-injected buttons work too.

Programmatic API

// Open as modal
GuideMe.open({ product: "futures", prefill: [/* optional */] });

// Mount inline into a host-allocated div
GuideMe.mount("#my-container", { product: "cfd", mode: "inline" });

// Close the open modal
GuideMe.close();

// Subscribe to events (mirror dataLayer events from the analytics plan)
GuideMe.on("started",          (data) => {});
GuideMe.on("question_answered", (data) => {});
GuideMe.on("completed",        (data) => { /* data: {primary_recommendation, confidence_pct, ...} */ });
GuideMe.on("email_submitted",  (data) => {});
GuideMe.on("cta_clicked",      (data) => { /* data: {cta_type, recommendation_id} */ });
GuideMe.on("closed",           (data) => {});

// One-shot callback alternative
GuideMe.open({ product: "futures", onComplete: (rec) => {} });

// Identify the visitor (optional — for cross-session stitching when we have auth)
GuideMe.identify({ user_id: "u_123", email: "...", traits: { plan: "free" } });

// Update default config after init
GuideMe.config({ defaultProduct: "cfd", theme: "dark" });

Configuration options

OptionSourceTypeDefaultNotes
appIddata-app-idstringrequiredIdentifies the deployment (multi-tenant later)
defaultProductdata-default-product or config({})`'futures' \'cfd' \null`null (show market picker)Skips Q0
prefillopen({prefill})PrefillItem[][]Pre-answers given Q1/Q2
modemount({mode})`'modal' \'inline'`'modal' for open, 'inline' for mount
themedata-theme or config({})`'dark' \'light'`'dark'Light theme is a future deliverable
localedata-locale'en' (only for v1)'en'Hooks for i18n later
containerHeightmount({containerHeight})number / 'auto''auto'Inline mode only
entryPointdata-entry-point or open({entryPoint})stringinferred from pathTagged on every analytics event for funnel attribution

postMessage protocol

All parent ↔ iframe traffic uses window.postMessage with strict origin checking.

Parent → iframe

type ParentMessage =
  | { type: "guide-me:init"; payload: InitConfig }
  | { type: "guide-me:close" }
  | { type: "guide-me:identify"; payload: IdentifyTraits }
  | { type: "guide-me:set-config"; payload: Partial<Config> };

iframe → parent

type IframeMessage =
  | { type: "guide-me:ready" }                    // iframe loaded, ready for init
  | { type: "guide-me:resize"; height: number }   // for inline mode auto-resize
  | { type: "guide-me:event"; name: string; data: object } // funnel events
  | { type: "guide-me:close-requested" }          // user clicked × inside iframe
  | { type: "guide-me:error"; message: string };

Origin validation


Auto-resize for inline mode

Inline mode needs the iframe to grow as content grows (questions vary in height; recommendation card is taller than the question form).


Modal overlay behaviour


Google Tag Manager integration

The loader pushes every survey event to window.dataLayer. Marketing teams configure GTM with standard "Custom Event" triggers — no extra code needed.

Events pushed to dataLayer

Every event lands in dataLayer with a consistent event name, prefixed guide_me_:

dataLayer eventWhen it firesPayload
guide_me_loadedLoader bootstrapped on the page{ app_id, entry_point }
guide_me_openedModal opens or inline mounts{ product, entry_point, source }
guide_me_startedFirst answer submitted{ product, session_id }
guide_me_question_answeredAfter every answer{ session_id, question_idx, target, header, answer_value }
guide_me_completedRecommendation rendered{ session_id, primary_recommendation, confidence_pct, product, alt_count }
guide_me_cta_clickedStart Challenge / Discover button click{ session_id, recommendation_id, cta_type, dest_url }
guide_me_email_submittedLead captured{ session_id, email_hash, opt_in }
guide_me_closedModal dismissed{ session_id, completed: bool, last_step }
guide_me_errorStream / API error{ session_id?, message }

Field rules:

Triggering Guide Me from GTM

Add a Custom HTML tag, fire it on any GTM trigger:

<script>
  window.GuideMe && window.GuideMe.open({
    product: {{Product From Page Var}}, // or hardcode 'futures' / 'cfd'
    entryPoint: 'gtm_scroll_75'
  });
</script>

Common GTM triggers paired with this tag:

Receiving Guide Me events in GTM

Set up one Custom Event trigger per dataLayer event you care about:

  1. Triggers → New → Custom Event.
  2. Event name: guide_me_completed (or any from the table above).
  3. Add Data Layer Variables for any field you want in tags: DLV - primary_recommendation, DLV - confidence_pct, DLV - product, DLV - session_id, DLV - cta_type.
  4. Wire those variables into your downstream tags (GA4, Meta CAPI, LinkedIn Insight, etc.).

GA4 mapping

GoalGA4 event nameGTM triggerSuggested params
Funnel startsurvey_startguide_me_startedproduct, entry_point
Question depthsurvey_progressguide_me_question_answeredquestion_idx, target
Funnel completesurvey_completeguide_me_completedrecommendation_id, confidence_pct, product
Lead generatedgenerate_leadguide_me_email_submittedopt_in
Checkout intentcta_clickguide_me_cta_clickedcta_type, dest_url, recommendation_id
Drop-offsurvey_abandonguide_me_closed (where completed = false)last_step

Mark survey_complete and cta_click as Conversions in GA4 → Admin → Events for funnel reporting.

Meta / LinkedIn / Reddit pixels

The same guide_me_completed Custom Event trigger can fire pixel "Lead" or "CompleteRegistration" events in parallel. Use Data Layer Variables (recommendation_id, product) as event parameters for ROAS attribution by recommendation class.

GTM custom template

We'll publish a .tpl template marketing imports once. Exposes friendly UI fields (product dropdown, optional prefill JSON, entry-point label) instead of asking marketers to hand-edit JavaScript.

Import path: GTM Templates → Tag Templates → Import. Once imported, marketers create new tags via the UI, with FundedNext-specific parameters pre-validated.

Cookie consent gating

Most GTM users gate analytics behind a cookie-consent CMP (OneTrust, Cookiebot). The loader honours window.OptanonActiveGroups / equivalent globals automatically — the iframe is only created once the visitor consents to the "functional" or "marketing" category. No extra GTM config needed; events stop firing in dataLayer until consent is granted.

Debugging in GTM Preview

  1. Open GTM Preview mode on the page that hosts the widget.
  2. Open the survey.
  3. The Tag Assistant tab lists every guide_me_* event as it fires, with the full payload visible under Variables.
  4. If an event isn't appearing: check the iframe origin matches the expected one and the loader has finished bootstrapping (guide_me_loaded should always be the first event).