VibesOS · Funnel Analytics
Showing last 14 days
Sequence Completed
—
No data
Daily volume per funnel stage
A/B variant breakdown
| Stage |
A (Join Free) |
Rate |
B (Start My Free Plan) |
Rate |
Δ B−A |
| /join Visit | 0 | — | 0 | — | — |
| Email Capture | 0 | — | 0 | — | — |
| Notify-Me | 0 | — | 0 | — | — |
| Email 1 Open | 0 | — | 0 | — | — |
| Email 1 Click | 0 | — | 0 | — | — |
| Exit-Intent | 0 | — | 0 | — | — |
| No A/B traffic yet — capture from /join to see it here. |
Source breakdown
| Source |
Subscribes |
Email 1 Opened |
Email 1 Clicked |
No tagged traffic yet — share an outreach link with ?utm_source=... to see it here. |
function toDayKey(d) {
if (typeof d === 'string') return d;
return d.toISOString().slice(0, 10);
}
function buildDayIndex(byEventType, byDay) {
const daySet = new Set();
const perEventType = {};
for (const r of byEventType) {
const key = toDayKey(r.day);
daySet.add(key);
if (!perEventType[r.event_type]) perEventType[r.event_type] = {};
perEventType[r.event_type][key] = r.count;
}
const perMetric = {};
for (const r of byDay) {
const dayKey = toDayKey(r.day);
daySet.add(dayKey);
perMetric[dayKey] = r;
}
const dates = Array.from(daySet).sort();
return { dates, perEventType, perMetric };
}
function stageValue(stage, day, ctx) {
if (stage.metric && ctx.perMetric[day]) return ctx.perMetric[day][stage.metric] || 0;
if (stage.eventTypes) {
let total = 0;
for (const t of stage.eventTypes) {
if (ctx.perEventType[t] && ctx.perEventType[t][day]) total += ctx.perEventType[t][day];
}
return total;
}
return 0;
}
function renderChart(data) {
const container = document.getElementById('chart-area');
const ctx = buildDayIndex(data.byEventType || [], (data.byDay || []).map(r => ({
...r, day: typeof r.day === 'string' ? r.day : new Date(r.day).toISOString().slice(0, 10)
})));
const dates = ctx.dates;
if (dates.length === 0) { container.innerHTML = '