⏱️ Lectura: 12 min
Simon Willison anunció el 18 de junio de 2026 el lanzamiento de Datasette Apps, un plugin que permite alojar aplicaciones HTML y JavaScript autocontenidas dentro de una instancia de Datasette. La promesa es tan llamativa como contraintuitiva: ejecutar código no confiable sobre datos sensibles sin que ese código pueda robarlos.
📑 En este artículo
- TL;DR
- Qué pasó con Datasette Apps
- Cómo funciona el aislamiento en Datasette Apps
- Contexto e historia: de un chiste de ingeniería a una funcionalidad central
- Datos y detalles técnicos: el protocolo entre la app y el padre
- Impacto y análisis para desarrolladores en LATAM
- Qué sigue
- Preguntas frecuentes
- Referencias
La pieza clave es un <iframe> con un sandbox estricto, reforzado con una cabecera CSP que resulta ser inmutable. El resultado se parece a los Artifacts de Claude, pero con algo que estos no tienen: una base de datos relacional persistente detrás.
TL;DR
- Datasette Apps son aplicaciones HTML+JS que corren en un iframe con sandbox dentro de Datasette, anunciadas el 18 de junio de 2026.
- El aislamiento combina un iframe con sandbox restrictivo y una cabecera CSP inyectada que bloquea peticiones a dominios externos.
- Las apps ejecutan SQL de solo lectura; con stored queries pueden hacer escrituras controladas y validadas por el servidor.
- La comunicación con la ventana padre pasó de postMessage a MessageChannel, que cierra el canal al navegar y reduce el riesgo.
- Willison verificó que la política CSP, una vez fijada por meta http-equiv, es inmutable para el frame incluso ante JavaScript malicioso.
- Nació como un mecanismo tipo Claude Artifacts para Datasette Agent y se promovió a concepto propio del ecosistema.
Qué pasó con Datasette Apps
El 18 de junio de 2026, Simon Willison —creador de Django y de Datasette— publicó el lanzamiento de datasette-apps, acompañado de un anuncio en el blog oficial del proyecto. Datasette es una herramienta de código abierto para explorar y publicar datos guardados en SQLite: tomás una base de datos, la servís por HTTP y obtenés una interfaz web más una API JSON para consultarla. Lo nuevo es que ahora podés alojar aplicaciones HTML completas dentro de esa instancia.
Cada app es un documento HTML+JavaScript autocontenido. Corre en un <iframe> fuertemente restringido y puede lanzar consultas SQL de solo lectura contra los datos de Datasette. Si el administrador configura stored queries (consultas guardadas y parametrizadas), la app también puede ejecutar escrituras controladas. Willison ofrece varios ejemplos, desde uno muy simple hasta una línea de tiempo personalizada, y cualquiera puede probarlo iniciando sesión con GitHub en la instancia de demostración agent.datasette.io.
Datasette Apps une dos mundos que rara vez conviven con tan poca fricción: la potencia de un backend relacional persistente y la inmediatez de un frontend HTML que cualquiera puede escribir —o pedirle a un modelo de lenguaje que escriba—. La comparación que el propio autor hace es directa: imaginá los Artifacts de Claude, pero con una base de datos detrás.
Cómo funciona el aislamiento en Datasette Apps
El problema central que resuelve Datasette Apps es delicado: hay que ejecutar HTML y JavaScript no confiable en un dominio altamente sensible. Una instancia de Datasette autenticada puede contener todo tipo de datos privados, así que un script malicioso o simplemente con errores no debería poder leer el DOM del padre, acceder a las cookies ni robar secretos de localStorage.
El primer ladrillo es el atributo sandbox del iframe. Con sandbox="allow-scripts allow-forms", el navegador permite que el código corra y procese formularios, pero lo aísla del documento contenedor. El problema es que un iframe con scripts todavía puede usar fetch() para cargar —o exfiltrar— contenido hacia otros dominios. Ahí entra el segundo ladrillo.
<iframe
sandbox="allow-scripts allow-forms"
srcdoc="<!doctype html>...la app...">
</iframe>
La app, en su propio HTML, arranca con una cabecera de Content Security Policy declarada como meta http-equiv. Esa política reduce default-src a 'none' y solo vuelve a habilitar lo justo: scripts y estilos inline, e imágenes desde data: y blob:. Sin orígenes externos permitidos, no hay a dónde mandar los datos.
<meta http-equiv="Content-Security-Policy"
content="default-src 'none';
script-src 'unsafe-inline';
style-src 'unsafe-inline';
img-src data: blob:;">
💭 Clave: Willison temía que un script malicioso pudiera modificar o eliminar esa cabecera CSP. Comprobó que no se puede: una vez fijada por el documento, la política es inmutable para el contenido de ese frame. Ese detalle es lo que hace viable todo el modelo.
Contexto e historia: de un chiste de ingeniería a una funcionalidad central
La idea no surgió de la nada. Desde su primera versión, Datasette siempre ofreció un backend flexible para crear apps HTML a medida mediante su API JSON. Uno de los primeros proyectos del propio Willison fue un buscador interno de documentación cuando trabajaba en Eventbrite: importaba documentos de distintos sistemas a SQLite con un cron y los servía a través de Datasette con una interfaz HTML+JavaScript que consultaba la API directamente.
En ese proyecto, el JavaScript del navegador construía las consultas SQL del lado del cliente. Empezó casi como un chiste de ingeniería, pero resultó ser una forma muy productiva de iterar sobre la aplicación. Esa experiencia, combinada con su colección de herramientas HTML y sus experimentos con Claude Artifacts, lo convenció de que sumar un backend estilo Datasette a un frontend HTML autocontenido es una combinación sorprendentemente poderosa.
Datasette Apps nació, de hecho, como su intento de construir un mecanismo tipo Claude Artifacts para Datasette Agent. Pero rápidamente se dio cuenta de que el patrón del sandbox era interesante para mucho más que añadir apps a la interfaz, así que lo promovió a concepto de primer nivel dentro del ecosistema. También es, en sus palabras, una forma divertida de convertir años de experimentos con herramientas HTML hechas con “vibe coding” en una funcionalidad central de su proyecto principal.
Datos y detalles técnicos: el protocolo entre la app y el padre
Una vez que el iframe quedó tan blindado que no podía hacer nada interesante, el reto fue volver a abrirlo de forma controlada, exponiendo una lista blanca de operaciones que empieza por las consultas SQL de solo lectura contra bases específicas.
La primera versión usó postMessage(), que permite que un iframe hijo envíe mensajes a la ventana padre. Willison creó un protocolo simple para pedir que el padre ejecutara una consulta; el padre verificaba que la consulta apuntara a una base de datos de la lista blanca antes de ejecutarla. Según relata, una de las herramientas LLM que usó —cree que fue GPT-5.5— señaló que postMessage() por sí solo puede ser explotado si el iframe carga código adicional desde un dominio no confiable. Aunque no creía que aplicara a su caso, por defensa en profundidad migró a un transporte basado en MessageChannel().
La ventaja de MessageChannel() es concreta: si la página navega a otro sitio, el canal se cierra automáticamente, eliminando cualquier posibilidad de ejecutar comandos enviados desde una página externa no confiable. Así se ve el lado de la app que pide datos:
// Dentro de la app (hijo): abrir un canal y pedir una consulta
const channel = new MessageChannel();
window.parent.postMessage({ type: "init" }, "*", [channel.port2]);
channel.port1.onmessage = (event) => {
const { rows, error } = event.data;
if (error) return console.error("SQL rechazado:", error);
render(rows);
};
channel.port1.postMessage({
sql: "select id, titulo, creado from eventos order by creado desc limit 50"
});
Y el lado del padre, que valida contra la lista blanca antes de tocar la base:
// En el padre (Datasette): validar antes de ejecutar
port.onmessage = async ({ data }) => {
if (!esConsultaPermitida(data.sql, BASES_PERMITIDAS)) {
return port.postMessage({ error: "base de datos no permitida" });
}
const rows = await ejecutarSoloLectura(data.sql);
port.postMessage({ rows });
};
El sistema además expone logs visibles de consultas y errores. Si en la demo de la línea de tiempo buscás la cadena usercontent, traés resultados que intentan incrustar imágenes desde user-images.githubusercontent.com; como ese dominio no está en la lista blanca de la CSP, se dispara un error que se captura y se transmite de vuelta al frame padre, donde queda registrado de forma legible para depurar.
graph LR
A["App HTML (iframe sandbox + CSP)"] -->|"MessageChannel: sql"| B["Datasette (ventana padre)"]
B -->|"valida allow-list"| C["SQLite (solo lectura)"]
C -->|"rows"| B
B -->|"rows / error"| A
Impacto y análisis para desarrolladores en LATAM
Para quienes construyen herramientas internas en la región, Datasette Apps resuelve un dolor recurrente. Muchos equipos pequeños necesitan dashboards, exploradores de datos o pequeñas utilidades sobre una base existente, pero montar un backend completo —con autenticación, despliegue y mantenimiento— es desproporcionado para un panel que usarán cinco personas. Con Datasette, el backend ya existe; con Datasette Apps, la capa visual se vuelve un único archivo HTML que vive junto a los datos.
El segundo punto interesante es el encaje con la IA generativa. Pedirle a un modelo que genere un panel HTML+JavaScript es hoy trivial, pero ejecutar ese código generado contra datos reales daba miedo con razón. El patrón de Willison ofrece una respuesta práctica: el código generado corre encerrado, sin acceso a la red externa ni a las credenciales, y solo puede hablar con la base mediante un canal auditado. Es un molde reutilizable más allá de Datasette para cualquiera que quiera ejecutar artefactos de un LLM sobre datos sensibles.
⚠️ Ojo: el sandbox protege los datos, pero no convierte una consulta mal escrita en una buena. Una app puede seguir pidiendo SQL costoso; la lista blanca y los límites del lado del servidor (timeouts, solo lectura) siguen siendo tu responsabilidad como administrador.
Si querés probarlo localmente, la instalación sigue el patrón habitual de plugins de Datasette sobre Python en cualquier sistema operativo:
# Windows (PowerShell o CMD)
py -m pip install datasette datasette-apps
# macOS / Linux
pip install datasette datasette-apps
# en los tres casos, servir una base existente
datasette serve datos.db
💡 Tip: antes de exponer una instancia con datos reales, revisá qué bases entran en la lista blanca de cada app y confirmá que las stored queries de escritura estén bien parametrizadas. El aislamiento del frontend no sustituye a una buena política de permisos en el backend.
Qué sigue
El propio Willison señala que varias de las ideas detrás de Datasette Apps tienen “staying power” —vocación de quedarse— más allá de este plugin concreto: la combinación de iframe con sandbox y CSP inmutable, las APIs acotadas vía MessageChannel y los logs visibles de consultas y errores son patrones que cualquier aplicación web puede adoptar para ejecutar contenido de terceros con seguridad.
En el corto plazo, lo lógico es ver crecer la galería de apps de ejemplo, más tipos de operaciones en la lista blanca y una integración más estrecha con Datasette Agent, el componente que originó todo el experimento. Para el ecosistema más amplio, el mensaje es claro: alojar un frontend HTML autocontenido sobre un backend relacional persistente ya no es un truco artesanal, sino una pieza de primer nivel con un modelo de seguridad explícito.
📖 Resumen en Telegram: Ver resumen
Preguntas frecuentes
¿Qué es exactamente una Datasette App?
Es una aplicación HTML+JavaScript autocontenida que se aloja dentro de una instancia de Datasette y corre en un iframe con sandbox. Puede ejecutar consultas SQL de solo lectura contra los datos y, si se configuran stored queries, también escrituras controladas.
¿Cómo evita que una app robe datos privados?
Mediante dos capas: el atributo sandbox del iframe la aísla del padre (sin cookies, sin DOM, sin localStorage) y una cabecera CSP, inmutable una vez fijada, bloquea cualquier petición de red a dominios externos. Sin destino al que enviar datos, no hay exfiltración posible.
¿Por qué se pasó de postMessage a MessageChannel?
Por defensa en profundidad. MessageChannel cierra el canal automáticamente cuando la página navega a otro sitio, lo que elimina la posibilidad de que una página externa ejecute comandos en el padre. Es un endurecimiento sobre el protocolo inicial basado en postMessage.
¿En qué se parece a los Artifacts de Claude?
En que ambos ejecutan HTML+JS generado o escrito por el usuario en un entorno aislado. La diferencia central es que Datasette Apps tiene detrás una base de datos relacional persistente, mientras que un Artifact tradicional no conserva estado entre sesiones.
¿Puedo usarlo en producción con datos sensibles?
Sí, ese es justamente el caso de uso para el que se diseñó. Aun así, la responsabilidad del backend sigue siendo tuya: definir bien la lista blanca de bases, los límites de consulta y las stored queries de escritura. El aislamiento del frontend complementa, no reemplaza, una buena política de permisos.
¿Cómo lo instalo?
Es un plugin de Datasette. En Windows usás py -m pip install datasette datasette-apps; en macOS y Linux, pip install datasette datasette-apps. Luego servís tu base con datasette serve datos.db.
Referencias
- Simon Willison — Datasette Apps: Host custom HTML applications inside Datasette — anuncio original con el porqué del diseño.
- Datasette — sitio oficial del proyecto y documentación.
- github.com/simonw/datasette — repositorio de código abierto.
- MDN — atributo sandbox de iframe — referencia del mecanismo de aislamiento.
- MDN — Content Security Policy — cómo funcionan las políticas CSP en el navegador.
📱 ¿Te gusta este contenido? Únete a nuestro canal de Telegram @programacion donde publicamos a diario lo más relevante de tecnología, IA y desarrollo. Resúmenes rápidos, contenido fresco todos los días.
0 Comentarios