Hallazgos y decisiones
Qué encontré en los datos, qué decidí hacer con cada inconsistencia y qué haría con el negocio a partir de lo que muestran. Los números salen de las mismas consultas que alimentan el dashboard: si cambian los CSV, cambian los dos.
Lo importante, en cinco líneas
- Sillones no vende más: vende más caro. Todas las categorías venden cantidades parecidas (~6.400 unidades), pero el ticket de Sillones es $39.795 contra $3.093 de Aromas. El 57% de la facturación sale de ahí, y recibe el 16,7% de la pauta.
- Aromas rinde 2,9× mejor en Meta que en Google (6,82 vs 2,33), y Sillones al revés: 2,4× mejor en Google (4,91 vs 2,05). Hay plata puesta en el canal equivocado en las dos puntas.
- Noviembre y diciembre facturan 1,7× una semana normal, pero la inversión sube solo 1,3×. El pico existe y la pauta llega tarde.
- Los tres sillones se quedan sin stock en menos de una semana. Es el 57% del ingreso corriendo contra un quiebre.
- 10 productos nunca vendieron una unidad: 864 unidades, unos $5,6M inmovilizados.
1 · Qué aporta cada tabla
| Tabla | Grano | Período | Filas | Para qué sirve |
|---|---|---|---|---|
google_ads | semana × campaña | ene-2024 → dic-2026 | 1.099 | Inversión y performance en Google |
meta_ads | semana × campaña | ene-2025 → dic-2026 | 728 | Lo mismo en Meta |
ventas | semana × producto | ene-2025 → dic-2026 | 2.912 | La facturación real. Única fuente de verdad del negocio |
stock | producto | foto, sin fecha | 38 | Inventario actual y catálogo maestro |
Las cuatro se conectan por dos claves: la semana (todas arrancan lunes, lo verifiqué) y la categoría, que es lo que permite unir una campaña con lo que efectivamente se vendió. El producto individual solo existe en ventas y stock: la pauta llega hasta categoría y no más abajo.
2 · Inconsistencias encontradas
2.1 · Mismo dato, distinto nombre
Cada fuente nombra las cosas a su manera. La ingesta las lleva a un vocabulario único:
| Meta | Ventas | → Unificado | |
|---|---|---|---|
week | date_week | week_start | semana |
cost | spend | — | inversion |
clicks | link_clicks | — | clicks |
conv_value | purchase_value | — | valor_conv_plataforma |
views, leads | no existen | — | views, leads (NULL en Meta) |
Decisión. views y leads quedan en NULL
para Meta, no en cero. Un cero dice «lo medimos y dio cero»; un NULL dice «esta plataforma
no lo reporta». Poner cero haría que cualquier promedio entre canales quede mal calculado.
2.2 · Naming de campañas vs categorías
Las campañas vienen capitalizadas y con tilde (Baño, Jardín);
las categorías, en minúscula. Pero no siguen la misma regla:
baño conserva la eñe y jardin pierde la tilde.
Baño → baño (solo minúscula, la ñ se queda)
Jardín → jardin (minúscula Y se le cae la tilde)
Decisión. Un diccionario explícito de 7 entradas, no una regla
automática. «Sacar todos los diacríticos» habría convertido baño en
bano, que no matchea con nada — y el error habría sido silencioso.
Si aparece una campaña que no está en el diccionario, la ingesta se detiene y
avisa en vez de descartar la fila sin que nadie se entere.
2.3 · Ventanas de tiempo desalineadas
Google tiene todo 2024; Meta y ventas arrancan en enero de 2025. Ese año de Google es inversión que no se puede cruzar contra ninguna facturación.
Decisión. Se define un período comparable (2025-01-06 → 2026-12-28, 104 semanas), que es el tramo donde las tres fuentes tienen datos, y el dashboard arranca ahí por defecto. Sin ese recorte, cualquier ratio de «ingreso por peso invertido» quedaría subestimado un 22%, porque el denominador incluiría un año de inversión sin ventas asociadas. Los datos de 2024 no se borran: siguen en la base y se pueden ver corriendo el filtro hacia atrás.
2.4 · Las dos escalas de revenue (la decisión más importante)
En el período comparable, las plataformas declaran $20.500.602 de valor de conversión. La tabla de ventas dice que entraron $445.351.715. Una diferencia de 21,7 veces.
Por qué no es un problema de atribución normal. Lo habitual es lo contrario: Google y Meta se atribuyen la misma venta y la suma de las plataformas termina por encima de las ventas reales. Acá reportan 22 veces menos. El doble conteo infla, no desinfla — así que la explicación no es atribución, es que las dos cifras no están en la misma unidad de medida (moneda distinta, o un valor de conversión que mide otra cosa).
Confirma la lectura que el ROAS interno de cada plataforma sea perfectamente razonable — 4,42 en Google y 3,97 en Meta. Dentro de cada fuente los números son coherentes; el problema aparece solo al cruzarlas.
Decisión. No se mezclan nunca. El dashboard reporta dos bloques:
- Negocio — sale de la tabla de ventas. Es la fuente de verdad de cuánta plata entró.
- Pauta — sale de las plataformas. Su ROAS sirve para comparar Google contra Meta y campaña contra campaña, dentro de esa misma escala.
Dividir la facturación total por la inversión total daría un ROAS de 92×, que no significa nada. Preferí dos números honestos antes que uno cómodo.
Qué haría en un caso real: antes de tocar presupuesto, confirmar con el equipo en qué moneda está cada campo y si el valor de conversión incluye todos los pedidos. Y para saber cuánto de la venta causa realmente cada canal —no cuánto se atribuye— la única respuesta seria es un test de incrementalidad: apagar un canal en una región y comparar contra otra equivalente. Es lo único que distingue «esta venta pasó por acá» de «esta venta ocurrió gracias a acá».
2.5 · Stock es una foto, no una serie
La tabla no tiene fecha: es el inventario de hoy. No se puede reconstruir cuánto stock había en marzo ni detectar quiebres pasados.
Decisión. Se usa solo hacia adelante: stock actual ÷ velocidad de venta de las últimas 8 semanas = semanas de cobertura. Es una proyección, no una medición, y está etiquetada como tal. Guardar un snapshot semanal de stock es la mejora de datos con mayor retorno de todas las que aparecen en este documento: habilita medir ventas perdidas por falta de stock, que hoy es invisible.
2.6 · Lo que estaba bien
Vale decirlo también: no hay nulos, ni duplicados, ni valores negativos, ni fechas fuera de lugar; las 7 campañas mapean 1:1 con las 7 categorías y todos los productos de ventas existen en stock. Las inconsistencias son de forma, no de integridad.
3 · Cómo quedaron estructurados los datos
Cuatro CSV → cuatro tablas + cinco vistas, en SQLite. El modelo es deliberadamente simple: una tabla larga de pauta con los dos canales apilados, en vez de una tabla por plataforma.
pauta (semana, canal, categoria, campana_origen, inversion,
impresiones, clicks, valor_conv_plataforma, views, leads)
ventas (semana, producto, categoria, unidades, ingreso)
stock (producto, sku, stock, categoria)
alertas (generada_en, tipo, severidad, producto, categoria, mensaje, detalle, valor)
Por qué una tabla larga y no una por canal: agregar un tercer canal
(TikTok, mañana) es insertar filas con canal='tiktok', sin tocar una sola
consulta ni un gráfico. Con una tabla por plataforma, cada canal nuevo obliga a reescribir
todos los JOIN.
Se conserva campana_origen con el nombre crudo. Si alguien pregunta «¿de
dónde salió este dato?», se puede rastrear hasta la fila original del CSV.
Las métricas derivadas se calculan en vistas SQL, no en el frontend, para que haya una sola definición de cada métrica:
CPC = inversion / clicks
CPM = inversion / impresiones * 1000
ROAS de plataforma = valor_conv_plataforma / inversion
cobertura = stock / (unidades vendidas en las últimas 8 semanas / 8)
4 · Qué dicen los datos del negocio
4.1 · El negocio son los sillones, y la pauta no se enteró
del ingreso viene de Sillones, que recibe el 16,7% de la inversión.
Lo interesante no es el desbalance, es de dónde sale. Todas las categorías venden prácticamente las mismas unidades:
| Categoría | Unidades | Ticket promedio | Ingreso |
|---|---|---|---|
| Sillones | 6.429 | $39.795 | $255.842.330 |
| Deco | 6.469 | $6.301 | $40.766.465 |
| Jardín | 6.460 | $6.292 | $40.651.918 |
| Baño | 6.107 | $5.871 | $35.857.663 |
| Mesa | 6.578 | $4.000 | $26.313.825 |
| Cocina | 6.355 | $4.080 | $25.933.948 |
| Aromas | 6.460 | $3.093 | $19.985.566 |
Lectura. Sillones no vende más: vende más caro. Vender un sillón equivale a vender trece difusores de bambú. Si la pauta se optimiza por volumen de conversiones —que es el default de casi toda cuenta— trata las dos cosas como equivalentes y termina comprando las conversiones baratas.
Recomendación. Pasar las campañas a optimizar por valor de conversión en lugar de cantidad, y subir el presupuesto de Sillones. Con esta diferencia de ticket, una conversión más de Sillones paga muchas de las otras.
4.2 · Cada categoría tiene su canal, y están cruzados
El ROAS de plataforma por categoría y canal (período comparable):
| Categoría | Meta | Diferencia | Dónde está la plata hoy | |
|---|---|---|---|---|
| Aromas | 2,33× | 6,82× | 2,9× mejor en Meta | $255.383 en el canal peor |
| Jardín | 3,16× | 4,72× | 1,5× mejor en Meta | $359.770 en el canal peor |
| Deco | 3,65× | 3,45× | parejo | — |
| Mesa | 4,27× | 3,94× | parejo | — |
| Cocina | 6,47× | 5,21× | 1,2× mejor en Google | — |
| Baño | 5,54× | 2,81× | 2,0× mejor en Google | $276.353 en el canal peor |
| Sillones | 4,91× | 2,05× | 2,4× mejor en Google | $378.169 en el canal peor |
El costo del tráfico es casi idéntico en los dos canales (CPC $1,90 vs $1,92), así que la diferencia no está en lo que cuesta traer gente: está en qué tan bien convierte cada categoría en cada plataforma. Tiene sentido: un aroma se compra por impulso viendo una foto linda (Meta); un sillón de $50.000 se busca activamente (Google).
Recomendación. Mover presupuesto en las dos puntas: Aromas y Jardín hacia Meta, Sillones y Baño hacia Google. Hoy hay aproximadamente $1,27 millones puestos en el canal que peor rinde para esa categoría.
Cómo, sin romper nada: mover el 20-30% primero y medir cuatro semanas, no todo de una. El ROAS no se sostiene igual al escalar —cuando subís la inversión, llegás a público menos calificado— así que el cálculo lineal de «si muevo todo gano 3×» no se cumple nunca del todo. Se testea y se recalibra.
4.3 · La estacionalidad está identificada, pero no aprovechada
factura una semana de nov-dic contra una semana normal
($6,57M vs $3,80M)
sube la inversión en pauta en esas mismas semanas
($57.346 vs $44.526)
Lectura. La demanda se multiplica por 1,7 y la pauta acompaña con 1,3. Se está dejando pasar el momento del año en que cada peso invertido encuentra más gente con intención de comprar.
Recomendación. Planificar el presupuesto anual con curva estacional en vez de plano, y empezar a levantar inversión en la segunda quincena de octubre, no en noviembre: las campañas necesitan tiempo de aprendizaje antes del pico, y si arrancan cuando el pico ya empezó, lo agarran por la mitad.
4.4 · El riesgo que puede tirar abajo todo lo anterior
Los tres sillones tienen entre 0,5 y 0,9 semanas de cobertura. Son el 57% de la facturación. Cualquier reasignación de presupuesto hacia Sillones —que es lo que recomiendan los puntos 4.1 y 4.2— empeora el problema si no se repone stock primero: sería pagar por tráfico hacia un producto que no se puede entregar.
Orden correcto: primero reponer stock de Sillones, después mover la pauta. Es la única dependencia dura entre las recomendaciones de este documento.
4.5 · Plata dormida
10 productos de 38 nunca vendieron una unidad en 104 semanas: 864 unidades, unos $5,6 millones valorizados al ticket promedio de su categoría. Cuando un producto no vende nunca, rara vez es el producto: suele estar despublicado, sin fotos, mal cargado o con precio equivocado.
Recomendación. Revisar la ficha de esos 10 antes de decidir liquidarlos. Es una hora de trabajo y el piso es recuperar capital inmovilizado.
5 · La automatización
Construí dos, encadenadas, porque una sin la otra no sirve: un dato fresco que nadie mira no cambia nada, y una alerta sobre datos viejos es peor que no tener alerta.
5.1 · Ingesta disparada por cambios, no por reloj
Un proceso vigila la carpeta de CSV. En cuanto un archivo aparece o cambia, corre solo: valida, repara encoding, normaliza nombres, carga a la base y recalcula las alertas. Deliberadamente no es un cron semanal: un ecommerce no puede enterarse el lunes de algo que pasó el martes anterior. Queda un cron diario, pero solo como red de seguridad por si el vigilante se cayó.
Tres detalles que hacen que no moleste:
- Espera 2 segundos a que el archivo deje de cambiar. Sin eso, se dispararía con un CSV copiado por la mitad.
- Compara el contenido, no la fecha. Guardar un archivo sin modificarlo no reprocesa nada.
- Si la validación falla, no carga nada. La base se queda con los datos buenos anteriores y el error queda escrito en el log con el número de fila exacto.
Desde el dashboard se puede arrastrar un CSV y el circuito se cierra completo: subir el archivo y ver los números actualizados, sin entrar al servidor.
5.2 · Alerta de quiebre de stock
Cruza inventario contra velocidad de venta reciente y clasifica: crítico bajo 2 semanas, atención bajo 4. Los umbrales salen del tiempo típico de reposición de un ecommerce de deco (2 a 4 semanas entre pedido y recepción): por debajo de 2 semanas, el producto se agota antes de que llegue la reposición aunque se pida hoy.
Cada alerta dice cuánta plata pone en riesgo por semana, no solo cuántas unidades quedan. «Quedan 12 unidades» no ordena prioridades; «pone en riesgo $1,28M por semana» sí.
Hay un tercer caso que conviene no confundir con los otros dos. Cuando un producto no registra ventas recientes, puede ser que nunca haya vendido —plata dormida, el punto 4.5— o que vendiera bien y se haya frenado. El segundo caso es peor señal y se reporta aparte, con lo que facturaba antes de pararse: un producto que venía haciendo $8M y dejó de vender suele ser un problema de publicación, de precio o un quiebre de stock que ya ocurrió, no una decisión de catálogo.
6 · Lo que estos datos no pueden responder
Para que quede claro dónde termina lo que se puede afirmar:
- Margen. No hay costo de producto. Todo el análisis es sobre facturación, no sobre ganancia. Es posible que Sillones facture el 57% y aporte bastante menos margen.
- Causalidad. Que una categoría tenga buen ROAS no prueba que la pauta haya causado esas ventas. Parte se habría vendido igual. Solo un test de incrementalidad lo separa.
- Atribución real por canal. No hay datos de sesión ni de pedido con origen. No se puede saber qué venta vino de qué campaña, solo correlacionar agregados.
- Ventas perdidas. Sin histórico de stock no se sabe cuánto se dejó de vender por quiebres. Probablemente sea el número más grande que falta.
- Clientes. No hay identificador de comprador: no se puede calcular recompra, frecuencia ni valor de vida.
7 · Próximos pasos
- Snapshot semanal de stock. Una línea en el pipeline. Habilita medir quiebres y ventas perdidas.
- Costo por producto. Convierte todo este análisis de facturación en análisis de rentabilidad, que es lo que realmente importa.
- Agente conversacional sobre los datos. Preguntar en castellano («¿qué campaña bajó más el mes pasado?») y que responda consultando la base. La arquitectura sería: la pregunta más el esquema de tablas van a Claude, que devuelve una consulta SQL de solo lectura; se ejecuta contra una vista restringida y la respuesta se redacta con los datos reales. Lo dejé documentado y no construido: preferí entregar andando lo que el caso pide como obligatorio antes que sumar una pieza más.
- Alertas de performance de pauta, con la misma cañería que las de stock: avisar cuando una campaña cae contra sus 4 semanas previas.
Todos los números de este documento salen de consultas SQL contra la base generada por el pipeline, y se pueden reproducir con los filtros del dashboard.