Integra GoIA
en tus servicios
GoIA es la inteligencia artificial de la UNAM. Súmala a tu sitio en minutos con un widget flotante, un iFrame, la REST API de chat o la JSON API de búsqueda estructurada.
Quickstart — de cero a GoIA en 60 segundos
La forma más rápida de tener GoIA en tu sitio es el widget flotante. Solo pega este tag antes de </body>:
<script src="https://goia.unam.mx/goia.js" defer></script>
¿Usas React, Vue o Next.js? El widget se inyecta en el DOM de forma autónoma. No necesitas hacer nada más.
Añade el script
Copia el tag <script> y pégalo justo antes del cierre de </body> en tu HTML. El widget carga de forma diferida y no bloquea el renderizado.
Confirma que aparece el botón flotante
Recarga la página. Verás el círculo de GoIA en la esquina inferior derecha con su halo animado. Si no aparece, verifica que no haya CSP bloqueando scripts externos.
Personaliza si lo necesitas
Cambia colores, tamaño del botón o el endpoint usando la variante customizada. Consulta la sección Personalización para los detalles.
Elige tu método de integración
GoIA ofrece cuatro formas distintas de integrarse a tu proyecto, desde lo más simple hasta lo más personalizable.
previous_response_id.answer, items, sources y metadatos. Ideal para tarjetas y resultados de búsqueda.Widget flotante
Un Web Component aislado con Shadow DOM que inyecta un botón circular flotante y un panel de chat. No contamina tus estilos, funciona en cualquier framework.
Instalación estándar
Agrega el script antes de </body>. El widget se monta solo.
<!-- GoIA Widget — pega antes de </body> -->
<script src="https://goia.unam.mx/goia.js" defer></script>
Instalación con variante DGTIC
Versión con colores y endpoint ajustado para sitios de la DGTIC.
<script src="https://goia.unam.mx/goia_dgtic.js" defer></script>
Variante DGACO
<script src="https://goia.unam.mx/goia_dgaco.js" defer></script>
El widget crea su propio árbol de estilos dentro de un Shadow Root, por lo que tus reglas CSS no lo afectan y viceversa. Perfecto para sitios con estilos estrictos.
Integración en React / Next.js
// components/GoIAWidget.jsx
import { useEffect } from 'react';
export default function GoIAWidget() {
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://goia.unam.mx/goia.js';
script.defer = true;
document.body.appendChild(script);
return () => document.body.removeChild(script);
}, []);
return null; // el widget se monta solo en el DOM
}
// Uso: importa <GoIAWidget /> en _app.jsx o en el layout root
Características del widget
- Botón circular flotante con halo animado y efecto de flotar (
floatY) - Panel de chat con scroll, historial y contador de mensajes
- Textarea con autoexpansión y envío con Enter o Ctrl+Enter
- Botón de reinicio que limpia el hilo en servidor
- Animación de "pensando" con puntos parpadeantes
- Diseño
prefers-reduced-motionfriendly - Máximo configurable de mensajes por sesión (por defecto 10)
iFrame embed
¿Quieres incrustar GoIA en un portal, LMS, intranet o app móvil sin cargar JavaScript externo? Usa el iframe.php como fuente.
<!-- iFrame GoIA — chat completo embebido -->
<iframe
src="https://goia.unam.mx/iframe.php"
width="100%"
height="600"
frameborder="0"
allow="clipboard-write"
title="GoIA - Asistente IA UNAM"
style="border-radius: 16px; box-shadow: 0 8px 32px rgba(0,0,0,.15);"
></iframe>
Para una experiencia responsiva, usa height: 80vh en lugar de px fijos. El iFrame gestiona su propio scroll interno.
Embed en pantalla completa
Para portales que reservan toda la pantalla al asistente:
<style>
.goia-full {
position: fixed; inset: 0; width: 100%; height: 100%;
border: none; z-index: 9999;
}
</style>
<iframe
class="goia-full"
src="https://goia.unam.mx/iframe.php"
title="GoIA"
allow="clipboard-write"
></iframe>
Comunicación con el iFrame via postMessage
Puedes enviar un prompt inicial a GoIA desde el padre:
const goiaFrame = document.getElementById('goia-frame');
// Esperar a que el iFrame cargue
goiaFrame.addEventListener('load', () => {
goiaFrame.contentWindow.postMessage(
{ type: 'goia:prompt', text: '¿Cuáles son los servicios de la UNAM?' },
'https://goia.unam.mx'
);
});
REST API — Chat conversacional
Endpoint para construir tu propia interfaz de chat. Mantiene un hilo de conversación por sesión usando previous_response_id en el servidor.
Este endpoint solo acepta peticiones desde orígenes autorizados. Contacta al equipo GoIA para registrar tu dominio. En desarrollo usa http://localhost:3000 o http://localhost:8080.
Request Body
| Campo | Tipo | Req. | Descripción |
|---|---|---|---|
| prompt | string | required* | Mensaje del usuario. Alternativo a messages. |
| messages | array | required* | Array de objetos {role, content}. Se toma solo el último mensaje con role: "user". Alternativo a prompt. |
| reset | boolean | optional | Si es true, borra el hilo de conversación en la sesión del servidor. La respuesta es HTTP 204. |
curl -X POST https://goia.unam.mx/ia/ia_chat.php \
-H "Content-Type: application/json" \
-d '{"prompt": "¿Cuáles son los servicios de la UNAM?"}'
curl -X POST https://goia.unam.mx/ia/ia_chat.php \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "user", "content": "Hola GoIA"},
{"role": "assistant", "content": "¡Hola! ¿En qué te puedo ayudar?"},
{"role": "user", "content": "¿Dónde queda la biblioteca central?"}
]
}'
# Borra el hilo de conversación — responde HTTP 204 sin cuerpo
curl -X POST https://goia.unam.mx/ia/ia_chat.php \
-H "Content-Type: application/json" \
-d '{"reset": true}'
async function askGoia(prompt) {
const res = await fetch('https://goia.unam.mx/ia/ia_chat.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include', // necesario para mantener el hilo de sesión
body: JSON.stringify({ prompt })
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
return data.reply ?? data.text ?? data.answer ?? '';
}
// Uso
const respuesta = await askGoia('¿Cuándo inicia el siguiente semestre?');
console.log(respuesta);
Respuesta
La API devuelve JSON con el texto de respuesta de GoIA:
{
"reply": "La Biblioteca Central de la UNAM está ubicada en Ciudad Universitaria, en la Torre de Ingeniería... "
}
Hilos de conversación
GoIA mantiene el contexto entre mensajes usando previous_response_id, almacenado en la sesión PHP del servidor entre peticiones.
Cuando envías un mensaje, el servidor guarda el id de la respuesta en $_SESSION['prev_response_id']. En la siguiente petición, ese ID se adjunta al payload de la API de GoIA para que el modelo recuerde el contexto previo sin reenviar el historial completo.
Importante: Para que el hilo persista debes usar credentials: 'include' en fetch (o configurar cookies si usas otro cliente HTTP), ya que el servidor necesita la cookie de sesión PHP.
class GoIAChat {
constructor(endpoint = 'https://goia.unam.mx/ia/ia_chat.php') {
this.endpoint = endpoint;
}
async send(prompt) {
const res = await fetch(this.endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include', // mantiene la sesión PHP
body: JSON.stringify({ prompt })
});
if (!res.ok) throw new Error(`GoIA error: HTTP ${res.status}`);
const data = await res.json();
return data.reply ?? data.text ?? data.answer ?? '';
}
async reset() {
await fetch(this.endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({ reset: true })
});
}
}
// Uso
const chat = new GoIAChat();
console.log(await chat.send('¿Qué es la UNAM?'));
console.log(await chat.send('¿Y cuándo fue fundada?')); // recuerda el contexto
await chat.reset(); // nuevo hilo
JSON API — Búsqueda estructurada
Ideal para construir interfaces de búsqueda con tarjetas, snippets y fuentes verificadas. La respuesta sigue el esquema goia.reply.v1.
Request Body
| Campo | Tipo | Req. | Descripción |
|---|---|---|---|
| prompt | string | required | La consulta del usuario. |
| rows | integer | optional | Cuántos items incluir en los resultados (1–10000). Default: 10. |
curl -X POST https://goia.unam.mx/ia/ia_iframe.php \
-H "Content-Type: application/json" \
-d '{"prompt": "servicios de salud UNAM", "rows": 5}'
Esquema de respuesta goia.reply.v1
La JSON API devuelve siempre un objeto con esta forma. Todos los campos están presentes aunque algunos sean vacíos.
{
"ok": true,
"schema": "goia.reply.v1",
"query": "servicios de salud UNAM",
"intent": "informacion",
"answer": "La UNAM ofrece servicios médicos gratuitos a toda su comunidad a través de la SSACU ",
"sources": [
{
"title": "SSACU — Servicios de Salud",
"url": "https://ssacu.unam.mx/servicios"
}
],
"items": [
{
"title": "Clínicas universitarias",
"snippet": "Atención médica, dental y psicológica disponible en CU y en los Campus Foráneos…",
"url": "https://ssacu.unam.mx/clinicas",
"source": "UNAM",
"date": "2025-01-15",
"photo": "https://ssacu.unam.mx/img/clinica.jpg"
}
],
"meta": {
"confidence": 0.92,
"needs_followup": false,
"took_ms": 1340
}
}
Descripción de campos
| Campo | Tipo | Descripción |
|---|---|---|
| ok | boolean | true si la petición fue exitosa. |
| schema | string | Siempre "goia.reply.v1". Útil para versionar consumidores. |
| query | string | Eco del prompt recibido. |
| intent | string | informacion | orientacion | evento | desconocido |
| answer | string | Respuesta breve en texto plano. Siempre presente. |
| sources | array | Fuentes verificadas usadas en la respuesta. |
| items | array | Resultados tipo buscador (pueden ser vacíos). Cada item tiene title, snippet, url, source, date y opcionalmente photo. |
| meta.confidence | number | Confianza estimada de 0 a 1. |
| meta.needs_followup | boolean | true si GoIA no está segura y recomienda verificar. |
| meta.took_ms | integer | Tiempo de procesamiento en milisegundos. |
Ejemplo de consumo completo
async function goiaSearch(query, rows = 8) {
const res = await fetch('https://goia.unam.mx/ia/ia_iframe.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({ prompt: query, rows })
});
if (!res.ok) throw new Error(`GoIA HTTP ${res.status}`);
const data = await res.json();
if (!data.ok) throw new Error(data.error?.message ?? 'Error desconocido');
return data; // { answer, items, sources, meta, ... }
}
// Renderizar resultados
async function renderSearch(query) {
const { answer, items, sources } = await goiaSearch(query);
document.getElementById('answer').textContent = answer;
const list = document.getElementById('results');
list.innerHTML = items.map(item => `
<article class="result-card">
${item.photo ? `<img src="${item.photo}" alt="${item.title}">` : ''}
<h3><a href="${item.url}" target="_blank">${item.title}</a></h3>
<p>${item.snippet}</p>
<small>${item.source} · ${item.date}</small>
</article>
`).join('');
}
Resumen de parámetros
Referencia rápida de todos los campos aceptados por ambos endpoints.
Chat API (ia_chat.php)
| Campo | Tipo | Default | Descripción |
|---|---|---|---|
| prompt | string | — |
Pregunta o instrucción del usuario. |
| messages | array | — |
Historial de chat. Solo se procesa el último mensaje user. |
| reset | boolean | false |
Reinicia el hilo de conversación en la sesión. |
JSON API (ia_iframe.php)
| Campo | Tipo | Default | Descripción |
|---|---|---|---|
| prompt | string | — |
Consulta del usuario. Requerido. |
| rows | integer | 10 |
Número sugerido de ítems en la respuesta. Rango 1–10000. |
CORS y seguridad
Los endpoints de GoIA implementan CORS estricto con lista blanca de orígenes. Solo las peticiones desde dominios autorizados reciben cabeceras Access-Control-Allow-Origin.
Para usar la API en producción desde tu dominio, escribe a Alejandro Bosch para añadirlo a la lista de orígenes permitidos. En desarrollo, localhost:3000 y localhost:8080 están habilitados por defecto en algunos endpoints.
Cabeceras de seguridad
| Cabecera | Valor |
|---|---|
| Access-Control-Allow-Origin | El origen exacto del solicitante (si está en la lista blanca) |
| Access-Control-Allow-Methods | POST, OPTIONS |
| Access-Control-Allow-Headers | Content-Type |
| Vary | Origin — el servidor varía la respuesta por origen |
Los endpoints responden a peticiones OPTIONS con HTTP 204 y las cabeceras CORS correspondientes. Los navegadores modernos envían el preflight automáticamente cuando es necesario.
Códigos de error
Cuando algo falla, la API devuelve un objeto con ok: false y un campo error con code y message.
{
"ok": false,
"schema": "goia.reply.v1",
"error": {
"code": "INVALID_QUERY",
"message": "Se requiere \"prompt\" no vacío"
}
}
| HTTP | Código | Descripción |
|---|---|---|
| 400 | INVALID_QUERY | El body JSON está vacío, malformado o falta prompt. |
| 500 | UNAUTHORIZED | La API key de GoIA no está configurada en el servidor. |
| 502 | UPSTREAM_ERROR | Error de conexión con la API de GoIA (cURL). |
| 4xx/5xx | — (crudo) | El servidor pasa directamente el JSON de error de la API de GoIA para facilitar el debug. |
Contexto de página
El widget puede leer el contenido de la página donde está embebido y usarlo como contexto para sus respuestas. Así GoIA responde preguntas sobre ese contenido específico sin que el usuario tenga que copiarlo.
Antes de enviar el prompt, el widget extrae el texto visible de la página (o del selector CSS que definas) y lo inyecta como contexto en el system prompt de la petición. GoIA lo usa para responder preguntas sobre artículos, fichas, catálogos o cualquier contenido dinámico.
Activar contexto de página
Pasa el texto o selector al widget via data- attribute o a través del endpoint con el campo context:
<!-- GoIA lee el contenido del selector #main-content como contexto -->
<script
src="https://goia.unam.mx/goia.js"
data-context-selector="#main-content"
defer
></script>
// Extrae el texto de la página y lo añade al prompt
const pageText = document.querySelector('#main-content')?.innerText ?? '';
const res = await fetch('https://goia.unam.mx/ia/ia_chat.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({
prompt: '¿Qué dice este artículo sobre becas?',
context: pageText.slice(0, 4000) // recorta para no superar el límite
})
});
Páginas de convocatorias, fichas de trámites, artículos de noticias, directorios, documentos PDF renderizados en HTML. GoIA puede resumir, explicar, comparar o responder preguntas sobre cualquiera de ellos.
Búsqueda web y MCPs
Además de responder con su conocimiento base, GoIA puede buscar en la web en tiempo real y conectarse con Model Context Protocol (MCP) servers para ampliar sus capacidades con herramientas externas.
Búsqueda web en tiempo real
Cuando la consulta lo requiere, GoIA activa automáticamente la herramienta de búsqueda web y trae resultados actualizados antes de responder. No necesitas hacer nada extra en tu integración.
GoIA detecta automáticamente si la pregunta necesita información actualizada (noticias, becas vigentes, eventos, trámites) y activa la búsqueda web. Las respuestas incluyen fuentes verificadas con URL completa.
Integración con MCP servers
GoIA soporta el estándar Model Context Protocol (MCP). Puedes conectar tus propios MCP servers para darle a GoIA acceso a bases de datos internas, APIs propietarias, calendarios, sistemas de inventario o cualquier herramienta personalizada.
{
"prompt": "¿Qué eventos hay esta semana en la Facultad de Ciencias?",
"tools": ["web_search", "agenda_unam"],
"context": "El usuario está en la página de la Facultad de Ciencias"
}
Para conectar un MCP server propio o activar capacidades adicionales en tu instancia de GoIA, contacta al equipo de Labsapp. Configuramos el servidor, los permisos y las herramientas disponibles para tu dependencia.
Personaliza el widget
El widget está configurado con constantes editables al inicio del archivo. Si necesitas una versión personalizada, copia el JS y ajusta el bloque CONFIG AJUSTABLE.
// ====== CONFIG AJUSTABLE ======
const ENDPOINT = 'https://goia.unam.mx/ia/ia_chat.php'; // tu endpoint
const MAX_MSGS = 10; // mensajes máximos por sesión
const UI = {
BTN_SIZE: 60, // px — diámetro del botón
BTN_IMAGE: 'https://goia.unam.mx/img/goia-avatar-colores.png', // imagen del botón
PULSE_COLOR: 'rgba(44,163,184,.25)', // color del halo animado
PULSE_MS: 2000, // duración del pulso (ms)
PULSE_SCALE: 3.0, // escala máxima del halo
PANEL_W: 420, // ancho del panel (px)
PANEL_VW: 94, // ancho máximo en vw
PANEL_MIN_H: 360, // alto mínimo del panel
PANEL_MAX_VH:72, // alto máximo en vh
CORNER: 20, // border-radius del panel
GAP: 10 // espaciado interno
};
Variables CSS para el panel
// Paleta oficial GoIA — úsalos en PULSE_COLOR o en CSS
const GOIA_COLORS = {
lime: '#B5D334', // verde lima
green: '#9DCA4F', // verde
teal: '#33B59A', // teal
blue: '#2CA3B8', // azul claro
navy: '#204E96', // azul UNAM oscuro
};
Variantes por entidad
GoIA tiene versiones pre-configuradas para distintas dependencias de la UNAM. Cada variante tiene su propio endpoint, system prompt y estilo visual.
| Variante | Script | Endpoint | Entidad |
|---|---|---|---|
| goia.js | /goia.js |
/ia/ia_chat.php |
DGOAE — versión general UNAM |
| goia_dgtic.js | /goia_dgtic.js |
/ia/ia_dgtic.php |
DGTIC — Dirección General de TIC |
| goia_dgaco.js | /goia_dgaco.js |
/ia/ia_chat.php |
DGACO — Dirección General de Actividades Culturales |
Si tu dependencia necesita un system prompt propio, colores distintos o un endpoint dedicado, usa el formulario de contacto para hablar con el equipo de Labsapp.
Hablar con el equipo
¿Quieres integrar GoIA en tu sitio, necesitas una variante personalizada o tienes preguntas sobre la API? Déjanos tus datos y te contactamos.