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).
<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:
<!-- 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:
<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)
npm install @easyfunnel/sdk
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.
npm install @easyfunnel/sdk @easyfunnel/react
Add the provider to your root layout:
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:
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-trackattribute - Section tracking — any element with a
data-ef-sectionattribute fires asection_viewevent when scrolled into view
<!-- Fires a "signup_cta" event on click --> <button data-ef-track="signup_cta">Sign Up</button>
<!-- 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.
Script Tag
Add data attributes to enable modules:
<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>:
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_vitalsevents with metric name, value, and rating (good / needs-improvement / poor) - Engagement — sends
__engagementon 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_abandonwith form ID and duration - Errors — sends
__js_errorwith 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
claude mcp add easyfunnel -e EASYFUNNEL_API_KEY=efa_your_account_api_key -- npx -y @easyfunnel/mcp@latest
Cursor / Manual 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 projectscreate_projectCreate a new projectsetup_sdkInstall SDK, hardcode API key, and add provider to your codebasescan_for_actionsFind trackable buttons, forms, and linksinstrument_codeAdd tracking attributes or calls to elementscreate_funnelDefine a conversion funnel from event stepsget_funnel_healthGet conversion and drop-off dataquery_eventsQuery event counts, recent events, or breakdownssetup_chat_widgetSet up the AI chat widget for a projectAPI 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 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 AcceptedMax 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
sendBeaconfor non-blocking delivery. Falls back tofetchwithkeepalive. - Retry — Failed deliveries are retried twice with exponential backoff (1s, then 2s).
- Page exit — Listens to
visibilitychange,pagehide, andbeforeunloadto flush queued events before the user leaves. This works reliably on all browsers including mobile Safari.