Automatizar hojas de cálculo con Claude Code: CSV, Google Sheets API y Apps Script
Automatiza CSV, Google Sheets API y Apps Script con Claude Code usando scripts copiables y revisión segura.
La automatización de hojas de cálculo parece una tarea pequeña, pero suele tocar ventas, formularios de contacto, publicidad, facturas y métricas de contenido. Cuando una importación falla, el problema no es solo una fila perdida: el equipo puede tomar decisiones con ingresos, prioridades o costes equivocados.
Claude Code ayuda porque puede trabajar dentro del repositorio, no solo dentro de una celda. Puede crear un script de resumen CSV, un script que añada filas con Google Sheets API, una automatización de Apps Script y una nota de verificación con los comandos ejecutados. Esa evidencia es lo que convierte una automatización rápida en una automatización revisable.
En esta guía vamos de lo más simple a lo más operativo: primero un resumen local de CSV, luego una escritura en Google Sheets y por último una clasificación de leads con Apps Script. Para la base de trabajo, consulta también consejos de productividad con Claude Code y el flujo de verification receipt. Las referencias oficiales que conviene revisar son Claude Code docs, Claude Code CLI usage, Google Sheets API Node.js quickstart, Apps Script Sheets guide y SheetJS docs.
Define primero la frontera de datos
La primera decisión no es la librería. Es decidir qué tabla es la fuente de verdad. Si el mismo importe puede cambiarse en un CSV, una hoja de Google, un CRM y una herramienta contable, la automatización solo hará que el desorden viaje más rápido. Antes de pedir código a Claude Code, separa entrada, datos normalizados y reporte.
| Capa | Propósito | Ejemplo | Qué pedir a Claude Code |
|---|---|---|---|
| Raw | Entrada sin edición manual | formularios, CSV de pagos, exportaciones de anuncios | importación, validación, filas con error |
| Clean | Datos tipados y normalizados | fechas, importes, estados | normalización, deduplicación, columnas obligatorias |
| Report | Salida para humanos | ingresos mensuales, prioridad de leads, KPI | resúmenes, CSV para gráficos, alertas |
El error más común es escribir directamente en la pestaña de reporte. Esa pestaña suele tener colores, fórmulas, notas, columnas congeladas y formato para lectura humana. Las máquinas necesitan encabezados estables y filas append-only. Es mejor escribir en Raw o Clean y dejar que fórmulas, tablas dinámicas, Looker Studio o otro script generen el reporte.
Ejemplo 1: resumir ventas CSV por mes
Empieza con algo que no requiera credenciales de Google. Así Claude Code puede generar una pieza reproducible y el revisor puede ejecutarla sin permisos externos.
Crea data/sales.csv.
date,channel,product,amount,status
2026-05-01,organic,Claude Code Cheatsheet,0,won
2026-05-02,gumroad,Prompt Template Pack,2980,won
2026-05-08,consultation,Team Workshop,120000,won
2026-05-11,gumroad,Prompt Template Pack,2980,refunded
2026-06-01,organic,Claude Code Cheatsheet,0,won
2026-06-02,consultation,Implementation Review,80000,won
Guarda esto como scripts/summarize-sales.mjs.
import { mkdir, readFile, writeFile } from "node:fs/promises";
import path from "node:path";
const inputPath = process.argv[2] ?? "data/sales.csv";
const outputPath = process.argv[3] ?? "out/monthly-summary.csv";
function parseCsvLine(line) {
const cells = [];
let current = "";
let inQuotes = false;
for (let index = 0; index < line.length; index += 1) {
const char = line[index];
const next = line[index + 1];
if (char === '"' && inQuotes && next === '"') {
current += '"';
index += 1;
continue;
}
if (char === '"') {
inQuotes = !inQuotes;
continue;
}
if (char === "," && !inQuotes) {
cells.push(current.trim());
current = "";
continue;
}
current += char;
}
cells.push(current.trim());
return cells;
}
function parseCsv(source) {
const lines = source.trim().split(/\r?\n/).filter(Boolean);
const headers = parseCsvLine(lines[0]);
return lines.slice(1).map((line) => {
const cells = parseCsvLine(line);
return Object.fromEntries(headers.map((header, index) => [header, cells[index] ?? ""]));
});
}
function toMonth(dateValue) {
const date = new Date(`${dateValue}T00:00:00Z`);
if (Number.isNaN(date.getTime())) {
throw new Error(`Invalid date: ${dateValue}`);
}
return dateValue.slice(0, 7);
}
const rows = parseCsv(await readFile(inputPath, "utf8"));
const summary = new Map();
for (const row of rows) {
if (row.status !== "won") continue;
const amount = Number(row.amount);
if (!Number.isFinite(amount)) {
throw new Error(`Invalid amount: ${JSON.stringify(row)}`);
}
const key = `${toMonth(row.date)},${row.channel}`;
const current = summary.get(key) ?? { month: toMonth(row.date), channel: row.channel, deals: 0, revenue: 0 };
current.deals += 1;
current.revenue += amount;
summary.set(key, current);
}
const output = [
"month,channel,deals,revenue",
...[...summary.values()]
.sort((a, b) => `${a.month}:${a.channel}`.localeCompare(`${b.month}:${b.channel}`))
.map((row) => `${row.month},${row.channel},${row.deals},${row.revenue}`),
].join("\n");
await mkdir(path.dirname(outputPath), { recursive: true });
await writeFile(outputPath, `${output}\n`, "utf8");
console.log(`Wrote ${outputPath} (${summary.size} groups)`);
Ejecútalo.
mkdir -p data out scripts
node scripts/summarize-sales.mjs data/sales.csv out/monthly-summary.csv
cat out/monthly-summary.csv
La parte importante es fallar de forma visible. Un importe vacío, una fecha inválida o un estado inesperado no deben convertirse en cero sin avisar. Después puedes pedir a Claude Code que añada números de línea, un archivo de filas rechazadas y pruebas para reembolsos.
Ejemplo 2: añadir leads con Google Sheets API
Para equipos, una cuenta de servicio suele ser más auditable que un OAuth personal. Activa Sheets API en Google Cloud, crea una clave JSON, comparte la hoja con el correo de la cuenta de servicio y crea una pestaña Raw con createdAt,source,subject,amount,status.
npm install googleapis
export GOOGLE_APPLICATION_CREDENTIALS="$PWD/service-account.json"
export SHEET_ID="your-google-sheet-id"
Crea scripts/append-lead-to-sheet.mjs.
import { google } from "googleapis";
const { GOOGLE_APPLICATION_CREDENTIALS, SHEET_ID } = process.env;
if (!GOOGLE_APPLICATION_CREDENTIALS) {
throw new Error("GOOGLE_APPLICATION_CREDENTIALS is required");
}
if (!SHEET_ID) {
throw new Error("SHEET_ID is required");
}
const auth = new google.auth.GoogleAuth({
keyFile: GOOGLE_APPLICATION_CREDENTIALS,
scopes: ["https://www.googleapis.com/auth/spreadsheets"],
});
const sheets = google.sheets({ version: "v4", auth });
const source = process.argv[2] ?? "web";
const subject = process.argv[3] ?? "Claude Code consultation";
const amount = Number(process.argv[4] ?? 0);
if (!Number.isFinite(amount)) {
throw new Error(`Invalid amount: ${process.argv[4]}`);
}
await sheets.spreadsheets.values.append({
spreadsheetId: SHEET_ID,
range: "Raw!A:E",
valueInputOption: "USER_ENTERED",
insertDataOption: "INSERT_ROWS",
requestBody: {
values: [[new Date().toISOString(), source, subject, amount, "new"]],
},
});
console.log("Appended lead row");
Ejemplo de ejecución:
node scripts/append-lead-to-sheet.mjs newsletter "Spreadsheet automation review" 50000
Cuando Claude Code toque este archivo, pídele que respete nombres de variables, rango de escritura, orden de columnas y regla de no guardar credenciales. El JSON de la cuenta de servicio no debe aparecer en Git, issues, documentación ni prompts.
Ejemplo 3: clasificar ventas y consultas con Apps Script
Apps Script es práctico cuando el flujo vive en Google Workspace. Puede reaccionar a formularios, escribir en Sheets y enviar correos sin servidor propio. Aun así, tiene cuotas, triggers y permisos. Antes de usarlo en un embudo grande, revisa Apps Script quotas.
Pega este código en el editor de Apps Script y configura un trigger instalable de envío de formulario para onFormSubmit.
const SETTINGS = {
sheetName: "Leads",
notifyTo: "sales@example.com",
minAmountForHighPriority: 100000,
};
function onOpen() {
SpreadsheetApp.getUi()
.createMenu("Lead Ops")
.addItem("Rebuild lead status", "rebuildLeadStatus")
.addToUi();
}
function onFormSubmit(event) {
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const sheet = spreadsheet.getSheetByName(SETTINGS.sheetName) || spreadsheet.insertSheet(SETTINGS.sheetName);
ensureHeader_(sheet);
const values = event && event.namedValues ? event.namedValues : {};
const company = first_(values, "Company");
const email = first_(values, "Email");
const plan = first_(values, "Plan");
const budget = Number(first_(values, "Budget") || 0);
const priority = classifyLead_(plan, budget);
sheet.appendRow([new Date(), company, email, plan, budget, priority, "new"]);
if (priority === "high") {
MailApp.sendEmail({
to: SETTINGS.notifyTo,
subject: `High priority lead: ${company}`,
body: `Company: ${company}\nEmail: ${email}\nPlan: ${plan}\nBudget: ${budget}`,
});
}
}
function rebuildLeadStatus() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SETTINGS.sheetName);
if (!sheet) throw new Error(`Sheet not found: ${SETTINGS.sheetName}`);
ensureHeader_(sheet);
const values = sheet.getDataRange().getValues();
for (let rowIndex = 1; rowIndex < values.length; rowIndex += 1) {
const row = values[rowIndex];
const plan = String(row[3] || "");
const budget = Number(row[4] || 0);
const priority = classifyLead_(plan, budget);
sheet.getRange(rowIndex + 1, 6).setValue(priority);
}
}
function ensureHeader_(sheet) {
const header = ["createdAt", "company", "email", "plan", "budget", "priority", "status"];
const current = sheet.getRange(1, 1, 1, header.length).getValues()[0];
if (current.join("") === "") {
sheet.getRange(1, 1, 1, header.length).setValues([header]);
sheet.setFrozenRows(1);
}
}
function classifyLead_(plan, budget) {
const normalizedPlan = String(plan).toLowerCase();
if (budget >= SETTINGS.minAmountForHighPriority || normalizedPlan.includes("team")) {
return "high";
}
if (budget >= 30000) {
return "medium";
}
return "low";
}
function first_(namedValues, key) {
const value = namedValues[key];
return Array.isArray(value) ? value[0] || "" : "";
}
Si tu formulario usa campos en español, cambia Company, Plan y Budget por los nombres reales. Indica a Claude Code esos nombres exactos y pide que no escriba datos personales en logs.
Plantilla para pedirlo a Claude Code
Una buena petición limita el trabajo y define cómo se verificará.
You are working on spreadsheet automation for this repository.
Goal:
- Import sales CSV rows from data/sales.csv.
- Write a monthly summary to out/monthly-summary.csv.
- Add a Google Sheets append script for the Raw tab.
Scope:
- You may edit scripts/summarize-sales.mjs and scripts/append-lead-to-sheet.mjs.
- You may add small tests or sample CSV files if needed.
- Do not edit content files, product links, analytics, or deployment settings.
Rules:
- Do not commit credentials.
- Use environment variables for SHEET_ID and GOOGLE_APPLICATION_CREDENTIALS.
- Fail loudly on invalid dates, invalid amounts, and missing required columns.
- Keep the code copy-paste runnable with Node.js 20 or later.
Verification:
- Run node --check on every script you edit.
- Run the CSV summary against data/sales.csv.
- For Google Sheets API, verify syntax locally and list the manual credential checks.
- Return changed files, commands run, output summary, and remaining risks.
Usa estos comandos como evidencia mínima.
node --check scripts/summarize-sales.mjs
node scripts/summarize-sales.mjs data/sales.csv out/monthly-summary.csv
node --check scripts/append-lead-to-sheet.mjs
git diff -- scripts/summarize-sales.mjs scripts/append-lead-to-sheet.mjs
En un equipo, mueve la parte estable a CLAUDE.md y combínala con la guía de permisos de Claude Code.
Casos de uso reales
El primer caso es el reporte mensual de ingresos. Puedes combinar exportaciones de Gumroad, Stripe, facturas manuales y registros de PDF gratuito. Los reembolsos se excluyen, los leads gratuitos se cuentan como volumen y los nombres de producto se normalizan.
El segundo caso es la priorización de consultas. Presupuesto, tamaño del equipo, plan elegido y dominio de cliente existente pueden convertirse en reglas. Las reglas deben ser explicables: “presupuesto superior a 100000 yenes o plan team” es revisable; “parece interesante” no lo es.
El tercer caso es el seguimiento de artículos y anuncios. En una hoja puedes guardar slug, fecha de publicación, clics de búsqueda, clics de CTA, clics de producto y llegadas al formulario. Para nombres de eventos y CTAs, conecta esto con la guía de analítica con Claude Code.
El cuarto caso es la revisión previa a facturación. Compara logs de entrega con CSV de facturas y escribe solo las diferencias en una hoja de revisión. No automatices el envío de facturas en la primera versión; primero haz visibles las discrepancias.
Errores y trampas
El primer fallo es no fijar encabezados. Si aparecen Amount, amount e Ingresos, el script puede terminar sin error y saltarse filas. Pide a Claude Code una lista de columnas obligatorias y una salida con error cuando falten.
El segundo fallo es tratar Google Sheets como base de datos. Sheets es excelente para colaborar y revisar, pero no para transacciones, bloqueos, permisos canónicos o escrituras masivas. Pagos y permisos deben vivir en la base de datos de la aplicación.
El tercer fallo es filtrar credenciales. El JSON de una cuenta de servicio nunca debe entrar en prompts, issues, documentos ni commits. La petición debe decir que Claude Code no lea, imprima ni confirme secretos.
El cuarto fallo es olvidar triggers de Apps Script. Pegar el código no basta. Revisa trigger instalable, usuario de ejecución, autorización inicial, cuota de correo y ruta de errores.
El quinto fallo es mirar solo el total final. Todo reporte necesita filas leídas, filas excluidas, errores y hora de actualización. Sin esos datos no sabrás cuándo dejó de funcionar la automatización.
CTA: convertir scripts en operación
La automatización de hojas de cálculo se vuelve fiable cuando prompts, permisos y verificación son repetibles. Empieza con la chuleta gratuita de Claude Code para comandos y hábitos de revisión. Para prompts reutilizables y plantillas CLAUDE.md, revisa los productos de ClaudeCodeLab.
Si tu equipo usa hojas para ventas, leads, anuncios o facturación, define límites de credenciales y aprobación humana antes de añadir más scripts. Para diseñarlo con acompañamiento, usa formación y consultoría de Claude Code.
Resultado al probarlo
En el flujo de Masa, la mayor mejora no llegó al conectar la API de Sheets, sino al fijar primero encabezados CSV, reglas de exclusión y comportamiento ante errores. Apps Script funcionó bien para clasificar leads, pero las reglas vagas de notificación generaron demasiados correos. La forma más estable fue tratar la integración como un diseño Raw, Clean y Report, y luego pedir a Claude Code implementaciones pequeñas con verificación.
PDF gratis: cheatsheet de Claude Code
Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.
Cuidamos tus datos y no enviamos spam.
Sobre el autor
Masa
Ingeniero enfocado en workflows prácticos con Claude Code.
Artículos relacionados
Workflow de Obsidian a CLAUDE.md con Claude Code
Convierte notas de trabajo de Obsidian en notas operativas de CLAUDE.md para no repetir contexto.
Claude Code Revenue CTA Routing: de artículos a PDF, Gumroad y consulta
Un flujo con Claude Code para dirigir lectores a PDF gratis, Gumroad o consulta según intención.
Reglas de handoff para equipos con Claude Code: evidencia, permisos, rollback e ingresos
Formato práctico para entregar trabajo de Claude Code con pruebas, permisos, rollback, PDF gratis, Gumroad y consulta.