Decisões sem dados = achismo. Achismo = desperdício de R$ 50-200K em features erradas.
Com analytics estruturado:
- Identifica gargalos (conversão cai 40% no step 3 do onboarding)
- Valida hipóteses (feature X aumentou retenção em 25%)
- Prioriza roadmap (70% dos usuários pedem feature Y)
Este artigo mostra stack completo de analytics, do básico ao avançado, com código e custos.
As 4 camadas de analytics
Camada 1: Web analytics (tráfego e pageviews)
Ferramenta: Google Analytics 4 (GA4) - Grátis.
O que mede:
- Visitantes únicos
- Pageviews
- Taxa de rejeição
- Origem do tráfego (Google, direct, social)
- Dispositivos (desktop 65%, mobile 35%)
Setup (Next.js):
// app/layout.tsx
import Script from 'next/script'
export default function RootLayout({ children }: Props) {
const GA_ID = process.env.NEXT_PUBLIC_GA_ID
return (
<html>
<head>
<Script
src={`https://www.googletagmanager.com/gtag/js?id=${GA_ID}`}
strategy="afterInteractive"
/>
<Script id="google-analytics" strategy="afterInteractive">
{`
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${GA_ID}', {
page_path: window.location.pathname,
});
`}
</Script>
</head>
<body>{children}</body>
</html>
)
}
Eventos customizados:
// lib/analytics/ga.ts
export function trackEvent(
eventName: string,
params?: Record<string, any>
) {
if (typeof window !== 'undefined' && window.gtag) {
window.gtag('event', eventName, params)
}
}
// Uso
trackEvent('purchase', {
transaction_id: 'T12345',
value: 99.90,
currency: 'BRL'
})
trackEvent('sign_up', {
method: 'Google'
})
Limitações do GA4:
- ❌ Não rastreia usuários logados (apenas sessões)
- ❌ Funnels básicos
- ❌ Sem cohort analysis
- ❌ Dados agregados (não permite queries customizadas)
Quando usar: Tráfego de marketing, SEO, conversão de landing pages.
Camada 2: Product analytics (comportamento do usuário)
Ferramenta: Mixpanel ou Amplitude.
O que mede:
- Ações específicas (clicou botão X, completou onboarding)
- Funnels (quantos % passam de step A → B → C)
- Retention (quantos % voltam após 7 dias?)
- Cohorts (usuários que se cadastraram em janeiro vs fevereiro)
Setup (Mixpanel + Next.js):
npm install mixpanel-browser
// lib/analytics/mixpanel.ts
import mixpanel from 'mixpanel-browser'
const MIXPANEL_TOKEN = process.env.NEXT_PUBLIC_MIXPANEL_TOKEN!
export function initMixpanel() {
mixpanel.init(MIXPANEL_TOKEN, {
debug: process.env.NODE_ENV === 'development',
track_pageview: true,
persistence: 'localStorage'
})
}
// Identifica usuário (após login)
export function identifyUser(userId: string, properties?: Record<string, any>) {
mixpanel.identify(userId)
if (properties) {
mixpanel.people.set(properties)
}
}
// Rastreia evento
export function trackEvent(eventName: string, properties?: Record<string, any>) {
mixpanel.track(eventName, properties)
}
// Incrementa contador (ex: "bookings_completed")
export function incrementMetric(metric: string, value: number = 1) {
mixpanel.people.increment(metric, value)
}
Eventos essenciais (marketplace):
// Após cadastro
trackEvent('Sign Up', {
method: 'Email', // ou 'Google', 'Facebook'
role: 'Teacher' // ou 'Student'
})
identifyUser(user.id, {
$email: user.email,
$name: user.name,
plan: 'Free',
createdAt: user.createdAt
})
// Onboarding completado
trackEvent('Onboarding Completed', {
steps_completed: 3,
time_spent_seconds: 127
})
// Primeira transação
trackEvent('First Booking', {
value: 120,
category: 'Math',
payment_method: 'Credit Card'
})
incrementMetric('bookings_completed', 1)
// Feature usage
trackEvent('Feature Used', {
feature: 'Calendar Sync',
context: 'Settings'
})
Funnel de conversão (visualização no Mixpanel):
Sign Up → 1.000 usuários (100%)
↓ -40%
Onboarding Completed → 600 (60%)
↓ -50%
First Booking → 300 (30% total, 50% dos que completaram onboarding)
↓ -20%
Second Booking → 240 (24% total)
Cohort retention (quanto % volta após N dias):
| Cohort | D0 | D1 | D7 | D30 |
|---|---|---|---|---|
| Jan 2026 | 100% | 42% | 28% | 18% |
| Fev 2026 | 100% | 48% | 35% | 25% |
| Mar 2026 | 100% | 52% | 40% | 30% |
Análise: Retenção melhorando mês a mês (onboarding aprimorado funcionou).
Custo:
- Mixpanel: R$ 0 (até 100K eventos/mês) → R$ 600-1.200 (escala)
- Amplitude: R$ 0 (até 10M eventos/mês) → R$ 800-2K (recursos avançados)
Camada 3: Business intelligence (dashboards executivos)
Ferramenta: Metabase (self-hosted) ou Looker.
O que mede:
- MRR (Monthly Recurring Revenue)
- Churn rate
- LTV/CAC
- ARR growth
- Burn rate
Setup (Metabase self-hosted):
# Docker Compose
docker run -d -p 3000:3000 \
-e "MB_DB_TYPE=postgres" \
-e "MB_DB_DBNAME=metabase" \
-e "MB_DB_PORT=5432" \
-e "MB_DB_USER=metabase" \
-e "MB_DB_PASS=secret" \
-e "MB_DB_HOST=db" \
--name metabase \
metabase/metabase
Queries SQL customizadas:
-- MRR (Monthly Recurring Revenue)
SELECT
DATE_TRUNC('month', created_at) AS month,
COUNT(DISTINCT user_id) AS active_subscribers,
SUM(amount) AS mrr
FROM subscriptions
WHERE status = 'active'
GROUP BY month
ORDER BY month DESC;
-- Churn rate mensal
WITH monthly_users AS (
SELECT
DATE_TRUNC('month', created_at) AS month,
user_id
FROM subscriptions
WHERE status = 'active'
)
SELECT
month,
COUNT(DISTINCT user_id) AS users_start,
COUNT(DISTINCT CASE WHEN canceled_at IS NOT NULL THEN user_id END) AS churned,
ROUND(
100.0 * COUNT(DISTINCT CASE WHEN canceled_at IS NOT NULL THEN user_id END) /
COUNT(DISTINCT user_id),
2
) AS churn_rate
FROM monthly_users
GROUP BY month
ORDER BY month DESC;
-- LTV/CAC
SELECT
AVG(lifetime_value) AS avg_ltv,
AVG(acquisition_cost) AS avg_cac,
ROUND(AVG(lifetime_value) / NULLIF(AVG(acquisition_cost), 0), 2) AS ltv_cac_ratio
FROM (
SELECT
user_id,
SUM(amount) AS lifetime_value,
(SELECT spend / new_users FROM marketing_monthly WHERE month = DATE_TRUNC('month', u.created_at)) AS acquisition_cost
FROM payments p
JOIN users u ON p.user_id = u.id
GROUP BY user_id, u.created_at
) AS ltv_calc;
Dashboard exemplo (métricas-chave):
// Componente custom para embed Metabase
export function MetabaseDashboard({ dashboardId }: Props) {
const iframeUrl = `https://metabase.suaempresa.com/embed/dashboard/${dashboardId}?token=${embedToken}`
return (
<div className="dashboard-container">
<iframe
src={iframeUrl}
width="100%"
height="800"
frameBorder="0"
allowTransparency
/>
</div>
)
}
Métricas no dashboard executivo:
- 💰 MRR: R$ 87,4K (+18% vs mês anterior)
- 📉 Churn: 4,2% (meta: menor que 5%)
- 📈 LTV/CAC: 5,8x (meta: maior que 3x)
- 👥 Usuários ativos: 1.247 (+12%)
- 🔄 NPS: 42 (promotores 68%, detratores 15%)
Custo:
- Metabase self-hosted: R$ 60/mês (servidor)
- Metabase cloud: R$ 500-2K/mês
- Looker: R$ 2K-8K/mês (enterprise)
Camada 4: Alertas e anomalias
Ferramenta: Better Stack Monitors ou Datadog.
O que mede:
- Quedas abruptas (conversão caiu 30% hoje)
- Picos anormais (churn subiu 2x)
- Metas não atingidas (MRR menor que R$ 80K)
Setup (Better Stack):
// lib/monitoring/alerts.ts
export async function checkMetrics() {
const today = new Date()
const yesterday = subDays(today, 1)
// Verifica conversão do onboarding
const conversionToday = await getOnboardingConversion(today)
const conversionYesterday = await getOnboardingConversion(yesterday)
if (conversionToday < conversionYesterday * 0.7) {
// Queda de 30%+
await sendAlert({
severity: 'HIGH',
title: 'Onboarding conversion dropped 30%',
message: `Today: ${conversionToday}%, Yesterday: ${conversionYesterday}%`,
channel: 'slack'
})
}
// Verifica churn
const churnRate = await getMonthlyChurn()
if (churnRate > 0.05) {
// maior que 5%
await sendAlert({
severity: 'MEDIUM',
title: 'Churn rate above target',
message: `Current: ${churnRate * 100}%, Target: 5%`,
channel: 'email'
})
}
}
// Roda diariamente (cron)
cron.schedule('0 9 * * *', checkMetrics) // 9h todos os dias
Alertas Slack:
// lib/monitoring/slack.ts
import { WebClient } from '@slack/web-api'
const slack = new WebClient(process.env.SLACK_TOKEN)
export async function sendSlackAlert(message: string) {
await slack.chat.postMessage({
channel: '#alerts',
text: message,
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: `🚨 *Alert*\n${message}`
}
},
{
type: 'actions',
elements: [
{
type: 'button',
text: { type: 'plain_text', text: 'Ver Dashboard' },
url: 'https://metabase.suaempresa.com/dashboard/1'
}
]
}
]
})
}
Stack recomendado por estágio
MVP (0-100 usuários, R$ 0/mês)
- Web: Google Analytics 4 (grátis)
- Product: Mixpanel free tier (grátis)
- BI: SQL queries direto no banco (grátis)
- Alertas: Script custom + email (grátis)
Total: R$ 0
Growth (100-1K usuários, R$ 600-1.2K/mês)
- Web: GA4 (grátis)
- Product: Mixpanel Startup (R$ 600/mês)
- BI: Metabase self-hosted (R$ 60/mês servidor)
- Alertas: Better Stack (R$ 180/mês)
Total: R$ 840/mês
Scale (1K-10K usuários, R$ 1.8-3K/mês)
- Web: GA4 (grátis)
- Product: Amplitude Growth (R$ 1.200/mês)
- BI: Metabase Cloud (R$ 800/mês)
- Alertas: Datadog (R$ 1.000/mês)
Total: R$ 3K/mês
Eventos essenciais por tipo de produto
SaaS B2B
// Lifecycle events
'User Signed Up'
'Trial Started'
'Onboarding Completed'
'First Value Achieved' // Ex: "First report generated"
'Trial Converted'
'Subscription Upgraded'
'Subscription Downgraded'
'Subscription Canceled'
// Feature usage
'Feature Used' { feature: 'Advanced Reports', context: 'Dashboard' }
'Export Completed' { format: 'PDF', rows: 1247 }
'Integration Connected' { integration: 'Slack' }
// Engagement
'Daily Active' // Apenas trackeia 1x/dia
'Weekly Report Viewed'
Marketplace
// Supply side (professores, prestadores)
'Provider Signed Up'
'Profile Completed'
'First Service Listed'
'Booking Accepted'
'Booking Completed'
'Rating Received'
// Demand side (clientes)
'Customer Signed Up'
'Search Performed' { query: 'math tutor' }
'Provider Viewed'
'Booking Requested'
'Payment Completed'
// Platform
'GMV Generated' { amount: 120, commission: 24 }
'Dispute Opened'
E-commerce
'Product Viewed' { product_id, category, price }
'Added to Cart' { product_id, quantity }
'Checkout Started'
'Payment Info Added'
'Order Completed' { order_id, total, items }
'Product Returned'
Análises avançadas
A/B testing (feature flags)
// lib/ab-testing/split.ts
export function getUserVariant(userId: string, experiment: string): 'A' | 'B' {
const hash = createHash('md5').update(userId + experiment).digest('hex')
const num = parseInt(hash.substring(0, 8), 16)
return num % 2 === 0 ? 'A' : 'B'
}
// Uso
const variant = getUserVariant(user.id, 'new-onboarding')
if (variant === 'A') {
return <OnboardingOld />
} else {
return <OnboardingNew />
}
// Trackeia
trackEvent('Experiment Viewed', {
experiment: 'new-onboarding',
variant
})
Análise de resultados:
-- Comparação conversão A vs B
SELECT
properties->>'variant' AS variant,
COUNT(DISTINCT user_id) AS users,
COUNT(DISTINCT CASE WHEN event_name = 'Onboarding Completed' THEN user_id END) AS converted,
ROUND(
100.0 * COUNT(DISTINCT CASE WHEN event_name = 'Onboarding Completed' THEN user_id END) /
COUNT(DISTINCT user_id),
2
) AS conversion_rate
FROM events
WHERE properties->>'experiment' = 'new-onboarding'
GROUP BY variant;
-- Resultado:
-- Variant A: 42% conversão (600 usuários)
-- Variant B: 58% conversão (600 usuários)
-- Winner: B (+38% vs A)
Cohort analysis (retenção por coorte)
-- Retenção por coorte de cadastro
WITH cohorts AS (
SELECT
user_id,
DATE_TRUNC('month', created_at) AS cohort_month
FROM users
),
activity AS (
SELECT
user_id,
DATE_TRUNC('month', event_time) AS activity_month
FROM events
WHERE event_name = 'Daily Active'
)
SELECT
cohorts.cohort_month,
COUNT(DISTINCT cohorts.user_id) AS cohort_size,
COUNT(DISTINCT CASE WHEN activity_month = cohort_month THEN activity.user_id END) AS month_0,
COUNT(DISTINCT CASE WHEN activity_month = cohort_month + INTERVAL '1 month' THEN activity.user_id END) AS month_1,
COUNT(DISTINCT CASE WHEN activity_month = cohort_month + INTERVAL '2 months' THEN activity.user_id END) AS month_2
FROM cohorts
LEFT JOIN activity ON cohorts.user_id = activity.user_id
GROUP BY cohorts.cohort_month
ORDER BY cohorts.cohort_month DESC;
ROI de analytics
Case real: SaaS de gestão para restaurantes.
Antes de analytics estruturado:
- Decisões por “achismo”
- Feature prioritization por “quem grita mais alto”
- Não sabia onde usuários abandonavam
- Churn: 8,5%/mês (não sabia por quê)
Após 3 meses com analytics:
Descoberta 1: 62% abandonavam no step 2 do onboarding (conectar sistema de pagamento).
- Ação: Simplificou onboarding (conexão opcional)
- Resultado: Conversão 42% → 68% (+62%)
Descoberta 2: Usuários que usavam feature “Relatórios” tinham churn 70% menor.
- Ação: Adicionou tutorial in-app para relatórios
- Resultado: Uso da feature 18% → 45%
Descoberta 3: 80% dos churn aconteciam após 2º mês (não viam valor).
- Ação: Email sequence no mês 2 mostrando ROI (“você economizou R$ X”)
- Resultado: Churn 8,5% → 4,2% (-51%)
ROI total:
- Investimento analytics: R$ 12K (setup) + R$ 840/mês
- Ganho anual (redução churn): R$ 180K
- ROI: 420% (ano 1)
Checklist de analytics
Setup inicial:
- GA4 instalado (tráfego web)
- Mixpanel/Amplitude instalado (product analytics)
- Eventos-chave mapeados (sign up, onboarding, conversão)
- Identify de usuários (após login)
- Funnels configurados (sign up → ativação → conversão)
Análises mensais:
- Revisar funnels (onde há drop-off?)
- Analisar retention (cohorts melhorando ou piorando?)
- Feature usage (quais features correlacionam com retenção?)
- Churn analysis (por que usuários cancelam?)
Cultura data-driven:
- Decisões baseadas em dados (não opinião)
- A/B testa features antes de lançar
- Dashboard executivo revisado semanalmente
- Alertas configurados para anomalias
Próximos passos
- Instalar GA4 e Mixpanel
- Mapear 10-15 eventos essenciais
- Implementar tracking no código
- Criar 3 funnels principais
- Configurar cohort analysis
- Setup Metabase (dashboards)
- Revisar dados toda semana
Lembre-se: Analytics não é “nice to have”. É diferença entre crescer rápido e morrer lento.