Mensual
Revisión mensual. 30 minutos. Ajustar rumbo.
Cambio de fase (si aplica)
- Fase anterior:
INPUT[text:fase_anterior] - Nueva fase:
INPUT[text:fase_nueva] - ¿Por qué cambia?
INPUT[text:motivo_cambio_fase]
KPIs del funnel (solo si estás en post-lanzamiento)
const c = dv.current();
const signup = Number(c.signup_capsula_semana || 0);
const completado = Number(c.completado_capsula_pct || 0);
const conversion = Number(c.conversion_capsula_ritual_pct || 0);
const retencion = Number(c.retencion_trimestral_pct || 0);
const kpis = [
{ nombre: "Signup Cápsula", valor: signup, moderadoMin: 40, altoMin: 80, unidad: "/sem" },
{ nombre: "Completado Cápsula", valor: completado, moderadoMin: 55, altoMin: 70, unidad: "%" },
{ nombre: "Conversión Cápsula→Ritual", valor: conversion, moderadoMin: 5, altoMin: 7, unidad: "%" },
{ nombre: "Retención trimestral", valor: retencion, moderadoMin: 68, altoMin: 75, unidad: "%" },
];
function estadoKpi(kpi) {
if (!kpi.valor || kpi.valor <= 0) return "sin_dato";
if (kpi.valor >= kpi.altoMin) return "alto";
if (kpi.valor >= kpi.moderadoMin) return "moderado";
return "conservador";
}
const estadoGlobal = kpis.some(k => estadoKpi(k) === "conservador")
? "conservador"
: kpis.every(k => estadoKpi(k) === "alto")
? "alto"
: "moderado";
const badge = {
alto: "🟢 ALTO",
moderado: "🟡 MODERADO",
conservador: "🔴 CONSERVADOR",
};
dv.paragraph(`### Estado mensual: ${badge[estadoGlobal]}`);
const tabla = kpis.map(k => {
const estado = estadoKpi(k);
const sem = estado === "alto" ? "🟢" : estado === "moderado" ? "🟡" : estado === "conservador" ? "🔴" : "⚪";
const valorFmt = k.valor > 0 ? `${k.valor}${k.unidad}` : "—";
return [k.nombre, valorFmt, sem];
});
dv.table(["KPI", "Valor", "Estado"], tabla);Acciones sugeridas automáticas
const c = dv.current();
const signup = Number(c.signup_capsula_semana || 0);
const completado = Number(c.completado_capsula_pct || 0);
const conversion = Number(c.conversion_capsula_ritual_pct || 0);
const retencion = Number(c.retencion_trimestral_pct || 0);
const engagement = Number(c.engagement_rate_semana || 0);
const acciones = [];
if (signup > 0 && signup < 40) acciones.push(["Signup < 40", "Revisar asunto email + segundo blast a no-abiertos en 48h"]);
if (completado > 0 && completado < 55) acciones.push(["Completado < 55%", "Revisar UX sesión 1 + CTA de final de sesión + email día 1"]);
if (conversion > 0 && conversion < 5) acciones.push(["Conversión < 5%", "Reforzar prueba social en email día 3 + urgencia 72h día 4"]);
if (retencion > 0 && retencion < 65) acciones.push(["Retención < 65%", "Activar secuencia retención semana 8-10 con hitos de progreso"]);
if (engagement > 0 && engagement < 0.15) acciones.push(["Engagement < 0.15%", "Subir frecuencia y priorizar formato rutina/guardados"]);
if (acciones.length === 0) {
dv.paragraph("✅ Sin alertas críticas este mes. Sigue con foco.");
} else {
dv.table(["Trigger", "Acción prioritaria"], acciones);
}Contenido y métricas de Instagram
Top 5 posts del mes por alcance
TABLE
fecha as "Fecha",
tipo as "Tipo",
alcance_total as "Alcance",
guardados as "Guardados",
compartidos as "Compart.",
titulo as "Tema"
FROM "40_Contenido_Redes/Publicado_IG"
WHERE date(fecha) >= date(today) - dur(31 days)
SORT alcance_total DESC
LIMIT 5Pain flags acumulados
const notas = dv.pages('"40_Contenido_Redes/Publicado_IG"');
const contador = {};
for (const nota of notas) {
const flags = nota.pain_flags;
if (!flags) continue;
const lista = Array.isArray(flags) ? flags : [flags];
for (const f of lista) {
const key = f.trim().toLowerCase();
if (!key || key === "") continue;
contador[key] = (contador[key] || 0) + 1;
}
}
const ranking = Object.entries(contador).sort((a, b) => b[1] - a[1]).slice(0, 5);
if (ranking.length === 0) {
dv.paragraph("_(Aún no hay pain flags registrados)_");
} else {
dv.table(["Dolencia", "Menciones"], ranking);
}Posts sin clasificar
TABLE fecha as "Fecha", tipo as "Tipo", alcance_total as "Alcance"
FROM "40_Contenido_Redes/Publicado_IG"
WHERE (categoria = "" OR categoria = null) AND alcance_total > 2000
SORT alcance_total DESC
LIMIT 8Estado del lanzamiento
const hoyMs = Date.now();
const lanzamiento = new Date("2026-09-01").getTime();
const diasRestantes = Math.ceil((lanzamiento - hoyMs) / (1000 * 60 * 60 * 24));
const semanas = Math.floor(diasRestantes / 7);
const notas = dv.pages('"40_Contenido_Redes/Publicado_IG"').filter(p => p.alcance_total > 0).array();
const totalAlcance = notas.reduce((a, p) => a + (p.alcance_total || 0), 0);
const totalCompartidos = notas.reduce((a, p) => a + (p.compartidos || 0), 0);
const totalGuardados = notas.reduce((a, p) => a + (p.guardados || 0), 0);
const urgente = diasRestantes > 0
? `🚀 **${diasRestantes} días** para el lanzamiento (${semanas} semanas)`
: `⚡ **LANZAMIENTO ACTIVO**`;
dv.paragraph(urgente);
dv.paragraph(`
| Métrica acumulada | Valor |
|---|---|
| Posts con métricas | ${notas.length} |
| Alcance histórico | ${totalAlcance.toLocaleString()} |
| Guardados totales | ${totalGuardados.toLocaleString()} |
| Compartidos totales | ${totalCompartidos.toLocaleString()} |
`);Proyección a 30 días
- ¿Qué espero haber conseguido en 30 días?
- ¿Qué necesito para lograrlo?