📊

FlowDesk × Mixpanel

Guía completa de integración de analítica de producto — SaaS B2B

TypeScript Node.js Python Group Analytics
5
Eventos Clave
4
Módulos de Código
3
Plataformas (FE/BE/Data)
B2B
Group Analytics
🎯

Plan de Eventos — FlowDesk

Nomenclatura estándar de eventos y propiedades
Evento Propiedades Origen Objetivo
Sign Up method (google|email),  referrer Frontend Analizar canales de adquisición
Onboarding Step step_number (1–5),  step_namecompleted Frontend Detectar puntos de abandono
Feature Used feature (crear_flujo|aprobar_tarea|invitar_miembro|conectar_integration),  plan Ambos Medir adopción de features
Purchase plan (starter|pro|enterprise),  amountcurrency Backend Atribución de revenue
Subscription Cancelled reason (precio|funcionalidad|competencia|sin_uso),  days_activeplan Backend Análisis de churn
🔽

Funnel de Onboarding — 5 Pasos

Datos simulados de una cohorte de 1.000 usuarios
Conversión acumulada por paso
1 — Crear cuenta
1.000 usuarios
100%
2 — Verificar email
820 usuarios
82%
-18%
3 — Crear primer flujo
540 usuarios
54%
-34%
4 — Invitar un miembro
380 usuarios
38%
-30%
5 — Conectar integración
220 usuarios
22%
-42%

Frontend — SDK de Browser (TypeScript)

Next.js 14 — App Router
lib/mixpanel.ts TypeScript
Inicialización del SDK de Mixpanel para FlowDesk — configuración de persistencia y modo debug
import mixpanel from 'mixpanel-browser'

export function initMixpanel() {
  mixpanel.init(process.env.NEXT_PUBLIC_MIXPANEL_TOKEN!, {
    debug: process.env.NODE_ENV === 'development',
    track_pageview: 'url-with-path',
    persistence: 'localStorage',
    ignore_dnt: false,
    batch_requests: true,
    batch_size: 50,
    batch_flush_interval_ms: 5000,
  })
}
lib/mixpanel-events.ts TypeScript
Helpers de tracking tipados — eventos específicos de FlowDesk con propiedades estándar
import mixpanel from 'mixpanel-browser'

// Identifica al usuario tras login / signup
export function identifyFlowDeskUser(
  userId: string,
  traits: { email: string; name: string; plan: string; company: string }
) {
  mixpanel.identify(userId)
  mixpanel.people.set({
    $email: traits.email,
    $name: traits.name,
    plan: traits.plan,       // 'starter' | 'pro' | 'enterprise'
    company: traits.company,
    signed_up_at: new Date().toISOString(),
  })
}

// Evento de registro
export function trackSignUp(method: 'google' | 'email', referrer?: string) {
  mixpanel.track('Sign Up', { method, referrer: referrer || 'direct' })
  mixpanel.people.set_once({ 'First Sign Up Date': new Date().toISOString() })
}

// Paso de onboarding (pasos 1–5)
export function trackOnboardingStep(
  step: 1 | 2 | 3 | 4 | 5,
  stepName: 'crear_cuenta' | 'verificar_email' | 'crear_flujo' | 'invitar_miembro' | 'conectar_integration',
  completed: boolean
) {
  mixpanel.track('Onboarding Step', {
    step_number: step,
    step_name: stepName,
    completed,
  })
}

// Uso de feature
type FlowDeskFeature = 'crear_flujo' | 'aprobar_tarea' | 'invitar_miembro' | 'conectar_integration'

export function trackFeatureUsed(feature: FlowDeskFeature, plan: string) {
  mixpanel.track('Feature Used', { feature, plan })
  mixpanel.people.increment('total_feature_uses')
}
🖥️

Backend — Server-Side (Node.js)

Eventos de pagos, suscripciones y churn desde la API de Next.js
lib/mixpanel-server.ts TypeScript / Node.js
Tracking server-side para eventos de negocio críticos — pagos y cancelaciones de FlowDesk
import Mixpanel from 'mixpanel'

const mp = Mixpanel.init(process.env.MIXPANEL_TOKEN!, {
  host: 'api-eu.mixpanel.com',  // residencia de datos EU (RGPD)
})

type FlowPlan = 'starter' | 'pro' | 'enterprise'
type ChurnReason = 'precio' | 'funcionalidad' | 'competencia' | 'sin_uso'

// Suscripción nueva — se llama desde el webhook de Stripe
export function trackSubscription(userId: string, plan: FlowPlan, mrr: number) {
  mp.track('Purchase', {
    distinct_id: userId,
    plan,
    amount: mrr,
    currency: 'eur',
  })
  mp.people.set(userId, {
    plan,
    mrr,
    subscription_date: new Date().toISOString(),
  })
  mp.people.track_charge(userId, mrr)
}

// Cancelación — webhook de Stripe customer.subscription.deleted
export function trackChurn(
  userId: string,
  reason: ChurnReason,
  daysActive: number,
  plan: FlowPlan
) {
  mp.track('Subscription Cancelled', {
    distinct_id: userId,
    reason,
    days_active: daysActive,
    plan,
  })
  mp.people.set(userId, { plan: 'free', churned: true, churn_reason: reason })
}
🏢

Group Analytics — Nivel Empresa

Tracking B2B: eventos vinculados a la cuenta/empresa, no solo al usuario
lib/mixpanel-groups.ts TypeScript
Asocia cada usuario a su empresa y trackea eventos a nivel de workspace para análisis B2B
import mixpanel from 'mixpanel-browser'

// Vincula usuario a su empresa (en login o signup)
export function setUserWorkspace(
  companyId: string,
  companyName: string,
  plan: 'starter' | 'pro' | 'enterprise',
  seats: number
) {
  mixpanel.set_group('company', companyId)
  mixpanel.get_group('company', companyId).set({
    $name: companyName,
    plan,
    seats,
    product: 'FlowDesk',
  })
}

// Trackea un evento a nivel de empresa (no solo del usuario individual)
export function trackWorkspaceEvent(
  companyId: string,
  event: 'Flujo Creado' | 'Miembro Invitado' | 'Integración Conectada',
  props: Record<string, any> = {}
) {
  mixpanel.track_with_groups(event, props, { company: companyId })
}
🐍

Query API — Exportación de Datos (Python)

Pipeline de datos para reportes BI y análisis de cohortes
scripts/mixpanel_export.py Python 3.10+
Exporta eventos crudos y resultados de funnels de FlowDesk para análisis en pandas / BI
import requests
from datetime import date, timedelta
import json

# ─── Credenciales del Service Account de Mixpanel ───────────────────
PROJECT_ID = "flowdesk_prod_project_id"
SA_USERNAME = "service-account@flowdesk.mixpanel.com"
SA_SECRET  = "sa_secret_key_here"
AUTH = (SA_USERNAME, SA_SECRET)

def export_raw_events(from_date: date, to_date: date) -> list:
    """Exporta eventos crudos (NDJSON) para un rango de fechas."""
    r = requests.get(
        'https://data.mixpanel.com/api/2.0/export',
        auth=AUTH,
        params={
            'from_date': from_date.isoformat(),
            'to_date': to_date.isoformat(),
            'project_id': PROJECT_ID,
            'event': '["Sign Up","Feature Used","Purchase","Subscription Cancelled"]',
        },
        stream=True
    )
    return [json.loads(line) for line in r.iter_lines() if line]

def import_historical_batch(events: list[dict]) -> None:
    """Importa eventos históricos (migración desde sistema legacy)."""
    import base64
    credentials = base64.b64encode(SA_SECRET.encode() + b':').decode()
    requests.post(
        'https://api-eu.mixpanel.com/import',
        params={'strict': 1, 'project_id': PROJECT_ID},
        headers={
            'Content-Type': 'application/json',
            'Authorization': f'Basic {credentials}',
        },
        json=events
    )

# ─── Uso rápido ─────────────────────────────────────────────────────
if __name__ == '__main__':
    today     = date.today()
    last_week = today - timedelta(days=7)
    events    = export_raw_events(last_week, today)
    print(f"Exportados {len(events)} eventos de la última semana")