← Back to docs
The Front Desk · Developer Reference

Developer Docs

The chat widget is EasyFunnel’s primary product — see the setup guide for that. This page covers the SDK, auto-tracking, deep analytics modules, identity stitching, the MCP server, and the event ingestion API.

SDK Installation

Your project API key is auto-filled in the setup guide on your project dashboard. These docs use placeholder keys.

Script Tag (recommended)

Works with any framework — React, Next.js, Vue, plain HTML. Add to your root layout or <head>. This one script does both: it boots your AI agent widget and analytics (page views, sources, engagement).

HTML / layout.tsx
<script
  defer
  data-api-key="ef_your_key_here"
  src="https://easyfunnel.co/chat.js"
></script>

Want analytics only, with no chat widget? Use https://easyfunnel.co/sdk.js instead — samedata-api-key, same tracking, no widget.

Track clicks and section views with data attributes — no JavaScript needed:

HTML
<!-- Fires a "signup_cta" event on click -->
<button data-ef-track="signup_cta">Sign Up</button>

<!-- Fires a "section_view" event when scrolled into view -->
<section data-ef-section="pricing">...</section>

For programmatic tracking, use the global window.easyfunnel object:

HTML
<script>
  easyfunnel.track('click_signup', { plan: 'indie' })
  easyfunnel.identify('user_123')
</script>

Auto-updates: The script tag always loads the latest SDK from our CDN. You get new features and bug fixes automatically — no deploys needed.

npm (Vanilla JavaScript)

terminal
npm install @easyfunnel/sdk
app.js
import { EasyFunnel } from '@easyfunnel/sdk'

const ef = EasyFunnel.init({
  apiKey: 'ef_your_key_here',
  debug: true, // logs events to console in development
})

// Track custom events
ef.track('click_signup', { plan: 'indie' })

// Identify users after login
ef.identify('user_123')

Auto-updates: The npm package is a thin loader that fetches the latest SDK from our CDN at runtime. You get new features and fixes automatically — no need to run npm update.

React Hooks (optional)

If you prefer React hooks for programmatic tracking, install the React package. For most apps, the script tag + data-ef-track attributes above are simpler and auto-update.

terminal
npm install @easyfunnel/sdk @easyfunnel/react

Add the provider to your root layout:

layout.tsx
import { EasyFunnelProvider } from '@easyfunnel/react'

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <EasyFunnelProvider apiKey="ef_your_key_here">
          {children}
        </EasyFunnelProvider>
      </body>
    </html>
  )
}

Track events from any component:

component.tsx
import { useTrack } from '@easyfunnel/react'

function PricingButton() {
  const track = useTrack()

  return (
    <button onClick={() => track('click_subscribe', { plan: 'indie' })}>
      Subscribe
    </button>
  )
}

Auto-Tracking

The SDK automatically tracks:

  • Page views — on load and SPA navigation (pushState, popstate)
  • Click tracking — any element with a data-ef-track attribute
  • Section tracking — any element with a data-ef-section attribute fires a section_view event when scrolled into view
click tracking
<!-- Fires a "signup_cta" event on click -->
<button data-ef-track="signup_cta">Sign Up</button>
section tracking
<!-- Fires a "section_view" event when this section scrolls into view -->
<section data-ef-section="pricing">
  ...
</section>

Section tracking powers the Landing Page Health Score on your dashboard. Add data-ef-section to each major section of your page to measure scroll depth and engagement.

Deep Analytics

Enable optional modules for richer insights. Each module is off by default — opt in via script attributes or SDK options.

Web Vitals

Core Web Vitals (LCP, CLS, INP, FCP, TTFB)

Script: data-web-vitals — JS: webVitals: true

Engagement

Scroll depth, time on page, engaged reading time

Script: data-engagement — JS: engagement: true

Frustration Detection

Rage clicks and dead clicks

Script: data-frustration — JS: frustrationDetection: true

Form Tracking

Form starts, abandons, and submissions

Script: data-form-tracking — JS: formTracking: true

Error Tracking

Uncaught JS errors with stack traces

Script: data-error-tracking — JS: errorTracking: true

Script Tag

Add data attributes to enable modules:

HTML
<script
  defer
  data-api-key="ef_your_key_here"
  data-web-vitals
  data-engagement
  data-frustration
  data-form-tracking
  data-error-tracking
  src="https://easyfunnel.co/sdk.js"
></script>

npm / React

Pass options to EasyFunnel.init() or as props on <EasyFunnelProvider>:

app.js
EasyFunnel.init({
  apiKey: 'ef_your_key_here',
  webVitals: true,
  engagement: true,
  frustrationDetection: true,
  formTracking: true,
  errorTracking: true,
})

Collected Data

Each module collects data automatically. The SDK enriches every event with browser, OS, device type, viewport, language, timezone, and country — no configuration needed.

  • Web Vitals — sends __web_vitals events with metric name, value, and rating (good / needs-improvement / poor)
  • Engagement — sends __engagement on page unload with scroll depth %, engaged time, and total time
  • Frustration — sends __rage_click (3+ fast clicks) and __dead_click (click with no DOM change) with element selector
  • Forms — sends __form_start, __form_submit, and __form_abandon with form ID and duration
  • Errors — sends __js_error with error type, message, and source location

Bot Filtering

The SDK automatically detects bots (Googlebot, headless browsers, web scrapers, etc.) and tags every event with an is_bot flag. Bot sessions are excluded from the Active Sessions chart in your dashboard so your metrics reflect real human traffic only.

Identity Stitching

Before a user signs up, they are anonymous (tracked by session ID). When you call ef.identify('user_123'), all their previous anonymous events are retroactively linked to that user ID.

// Call after login/signup
ef.identify('user_123')

// Or with the React hook:
const identify = useIdentify()
identify('user_123')

MCP Setup (Claude / Cursor)

The MCP server lets Claude instrument your code and query your analytics directly from the editor.

Claude Code

terminal
claude mcp add easyfunnel -e EASYFUNNEL_API_KEY=efa_your_account_api_key -- npx -y @easyfunnel/mcp@latest

Cursor / Manual Config

MCP config
{
  "mcpServers": {
    "easyfunnel": {
      "command": "npx",
      "args": ["-y", "@easyfunnel/mcp@latest"],
      "env": {
        "EASYFUNNEL_API_KEY": "efa_your_account_api_key"
      }
    }
  }
}

Find your account API key in Settings.

Available MCP Tools

list_projectsList all your projects
create_projectCreate a new project
setup_sdkInstall SDK, hardcode API key, and add provider to your codebase
scan_for_actionsFind trackable buttons, forms, and links
instrument_codeAdd tracking attributes or calls to elements
create_funnelDefine a conversion funnel from event steps
get_funnel_healthGet conversion and drop-off data
query_eventsQuery event counts, recent events, or breakdowns
setup_chat_widgetSet up the AI chat widget for a project

API key handling: setup_sdk hardcodes your ef_* project API key directly in the layout file. This is safe — the key is public and always visible in the browser bundle. Hardcoding eliminates deployment failures on static hosts (Cloudflare Workers, GitHub Pages, S3) where env vars aren't available. You can still override it via an env var if you prefer.

Event Ingestion API

POST /api/collect
POST https://easyfunnel.co/api/collect
Content-Type: application/json

{
  "api_key": "ef_your_project_key",
  "events": [
    {
      "session_id": "anonymous-uuid",
      "event_name": "page_view",
      "properties": {
        "url": "/pricing",
        "referrer": "https://google.com"
      }
    }
  ]
}

Response: 202 Accepted

Max 20 events per request. Max 4KB per event. Rate limit: 100 req/s per API key.

Tracking Capture Rate

Ad blockers and browser privacy features can prevent JavaScript analytics from capturing every page view. EasyFunnel includes a built-in capture rate validator so you can see exactly how much traffic the SDK is capturing.

How It Works

On every page view, the SDK fires a 1x1 transparent pixel via an <img> tag in addition to the normal JavaScript event. Image beacons are nearly impossible for ad blockers to block, so the pixel count represents your true traffic baseline.

Your project dashboard shows a Capture Rate card that compares pixel pings vs SDK events:

  • 85%+ — Healthy. The gap is normal ad blocker usage.
  • 70–84% — Moderate loss. Check SDK loading order and domain whitelist.
  • Below 70% — Significant loss. The SDK may be loading too late or being blocked.

Validating Against Google Analytics

Compare your pixel ping count (shown on the capture rate card) with Google Analytics page views for the same period. If the numbers are close, both tools are seeing the same traffic. If GA shows significantly more, check that the SDK script is loading early enough (use beforeInteractive in Next.js or place the script in <head>).

Event Delivery

The SDK is designed for reliable event delivery with minimal impact on your page performance:

  • Batching — Events are queued and flushed every 2 seconds or when 5 events accumulate, whichever comes first.
  • Transport — Uses sendBeacon for non-blocking delivery. Falls back to fetch with keepalive.
  • Retry — Failed deliveries are retried twice with exponential backoff (1s, then 2s).
  • Page exit — Listens to visibilitychange, pagehide, and beforeunload to flush queued events before the user leaves. This works reliably on all browsers including mobile Safari.