Cookies
Introducción
Concepto y propósito de las cookies
- Sesiones de usuario persistentes
- Preferencias y configuración personalizada
- Seguimiento del comportamiento del usuario
- Autenticación y autorización
- Carros de compra en tiendas online
A diferencia de localStorage y sessionStorage, que solo son accesibles desde JavaScript en el navegador, las cookies se envían automáticamente al servidor con cada petición HTTP al dominio que las creó.
Creación y lectura de cookies
Crear cookies con JavaScript
Para crear una cookie, asignamos un valor a la propiedad document.cookie
. Esta propiedad tiene un comportamiento especial: escribir en ella no sobrescribe todas las cookies existentes, sino que añade o actualiza una cookie específica.
// Sintaxis básica para crear una cookie
document.cookie = "nombre=valor";
// Ejemplos prácticos
document.cookie = "usuario=Carlos";
document.cookie = "idioma=es";
Cada asignación a document.cookie
añade o actualiza solo la cookie especificada, dejando intactas las demás cookies.
Leer cookies
// Obtener todas las cookies como string
const todasLasCookies = document.cookie;
console.log(todasLasCookies); // "usuario=Carlos; idioma=es"
Para acceder a una cookie específica, necesitamos parsear esta cadena:
// Función para obtener el valor de una cookie específica
function obtenerCookie(nombre) {
const cookieString = document.cookie;
const cookies = cookieString.split('; ');
for (const cookie of cookies) {
const [cookieNombre, cookieValor] = cookie.split('=');
if (cookieNombre === nombre) {
return decodeURIComponent(cookieValor);
}
}
return null; // Cookie no encontrada
}
// Ejemplo de uso
const usuario = obtenerCookie('usuario'); // "Carlos"
const idioma = obtenerCookie('idioma'); // "es"
Codificación de valores
Es importante codificar los valores de las cookies para evitar problemas con caracteres especiales:
// Crear una cookie con un valor que contiene caracteres especiales
const mensaje = "Hola, ¿cómo estás?";
document.cookie = `mensaje=${encodeURIComponent(mensaje)}`;
// Al leerla, decodificamos el valor
const mensajeRecuperado = decodeURIComponent(obtenerCookie('mensaje'));
console.log(mensajeRecuperado); // "Hola, ¿cómo estás?"
Opciones de configuración para cookies
Expiración (expires o max-age)
Define cuándo la cookie debe ser eliminada automáticamente:
// Cookie que expira en una fecha específica
const fechaExpiracion = new Date();
fechaExpiracion.setDate(fechaExpiracion.getDate() + 30); // 30 días
document.cookie = `preferencias=tema:oscuro; expires=${fechaExpiracion.toUTCString()}`;
// Cookie que expira después de un tiempo determinado (en segundos)
document.cookie = "contador=42; max-age=3600"; // Expira en 1 hora
Si no especificamos una fecha de expiración, se crea una "cookie de sesión" que se elimina cuando el usuario cierra el navegador.
Path
Define la ruta en el dominio para la que la cookie es válida:
// Cookie válida solo para la ruta /admin
document.cookie = "panel=configuracion; path=/admin";
// Cookie válida para todo el dominio
document.cookie = "usuario=Ana; path=/";
Si no especificamos una ruta, la cookie solo será válida para la ruta actual y sus subrutas.
Domain
Especifica el dominio al que se aplica la cookie:
// Cookie válida para el dominio actual y sus subdominios
document.cookie = "sesion=abc123; domain=ejemplo.com";
Si no se especifica, la cookie solo es válida para el dominio actual (sin incluir subdominios).
Secure
// Cookie que solo se envía por HTTPS
document.cookie = "token=eyJhbGc...; secure";
HttpOnly
Esta opción hace que la cookie sea inaccesible para JavaScript, añadiendo una capa de seguridad contra ataques XSS. Sin embargo, solo puede ser establecida desde el servidor, no con JavaScript del lado del cliente:
// Esto solo funciona cuando la cookie es establecida por el servidor
Set-Cookie: id=a3fWa; HttpOnly
SameSite
Controla cuándo se envían las cookies en peticiones cross-site:
// Cookie que solo se envía en peticiones al mismo sitio
document.cookie = "analytics=123; SameSite=Strict";
// Cookie que se envía en peticiones al mismo sitio y en navegación desde otros sitios
document.cookie = "session=456; SameSite=Lax";
// Cookie que se envía en cualquier petición (requiere Secure)
document.cookie = "tracking=789; SameSite=None; Secure";
Función para crear cookies con todas las opciones
Para simplificar la creación de cookies con diferentes opciones, podemos usar una función como esta:
/**
* Crea una cookie con las opciones especificadas
* @param {string} nombre - Nombre de la cookie
* @param {string} valor - Valor de la cookie
* @param {Object} opciones - Opciones de configuración
*/
function crearCookie(nombre, valor, opciones = {}) {
// Opciones por defecto
const opcionesCompletas = {
path: '/', // Por defecto, cookie válida para todo el sitio
expires: null, // Por defecto, cookie de sesión
maxAge: null, // Alternativa a expires
domain: null, // Por defecto, solo dominio actual
secure: false, // Por defecto, se envía también por HTTP
sameSite: 'Lax', // Valor predeterminado en navegadores modernos
...opciones
};
// Codificar el valor
const valorCodificado = encodeURIComponent(valor);
// Iniciar la construcción de la cookie
let cookieString = `${nombre}=${valorCodificado}`;
// Añadir path
if (opcionesCompletas.path) {
cookieString += `; path=${opcionesCompletas.path}`;
}
// Añadir expires si existe
if (opcionesCompletas.expires) {
if (opcionesCompletas.expires instanceof Date) {
cookieString += `; expires=${opcionesCompletas.expires.toUTCString()}`;
} else {
throw new Error('La opción expires debe ser un objeto Date');
}
}
// Añadir max-age si existe
if (opcionesCompletas.maxAge !== null) {
cookieString += `; max-age=${opcionesCompletas.maxAge}`;
}
// Añadir domain si existe
if (opcionesCompletas.domain) {
cookieString += `; domain=${opcionesCompletas.domain}`;
}
// Añadir secure si es true
if (opcionesCompletas.secure) {
cookieString += '; secure';
}
// Añadir SameSite
if (opcionesCompletas.sameSite) {
cookieString += `; SameSite=${opcionesCompletas.sameSite}`;
}
// Crear la cookie
document.cookie = cookieString;
return cookieString;
}
// Ejemplos de uso
// Cookie que expira en 7 días
const expiracion = new Date();
expiracion.setDate(expiracion.getDate() + 7);
crearCookie('usuario', 'Maria', {
expires: expiracion,
secure: true,
sameSite: 'Strict'
});
// Cookie temporal que dura 1 hora
crearCookie('tempData', 'abc123', {
maxAge: 3600,
path: '/dashboard'
});
Eliminar cookies
Para eliminar una cookie, debemos establecerla de nuevo con la misma ruta y dominio, pero con una fecha de expiración en el pasado:
/**
* Elimina una cookie específica
* @param {string} nombre - Nombre de la cookie a eliminar
* @param {Object} opciones - Opciones como path y domain (deben coincidir con la cookie original)
*/
function eliminarCookie(nombre, opciones = {}) {
const opcionesEliminar = {
...opciones,
expires: new Date(0), // Fecha en el pasado
maxAge: 0 // Alternativa: expirar inmediatamente
};
crearCookie(nombre, '', opcionesEliminar);
}
// Ejemplo de uso
eliminarCookie('usuario', { path: '/' });
Es crucial especificar el mismo path
y domain
que se usaron al crear la cookie, o el navegador la tratará como una cookie diferente y no eliminará la original.
Cookies vs. almacenamiento web
Es importante entender las diferencias entre cookies y las tecnologías más modernas como localStorage y sessionStorage:
Característica | Cookies | localStorage | sessionStorage |
---|---|---|---|
Capacidad máxima | ~4KB por cookie, ~80KB total | ~5-10MB | ~5-10MB |
Envío al servidor | Automático con cada petición HTTP | No se envían | No se envían |
Expiración | Configurable o al cerrar sesión | No expiran | Al cerrar la pestaña |
Accesibilidad | JavaScript (excepto HttpOnly) y servidor | Solo JavaScript | Solo JavaScript |
Ámbito | Configurable (domain/path) | Origen (dominio+protocolo+puerto) | Pestaña/ventana específica |
API | Complicada (string único) | Simple (clave-valor) | Simple (clave-valor) |
Esta comparación nos ayuda a elegir la tecnología adecuada según el caso de uso:
Limitaciones y tamaño máximo
- Tamaño máximo: Aproximadamente 4KB por cookie.
- Número máximo: La mayoría de los navegadores limitan a 50-150 cookies por dominio.
- Límite total: Entre 4KB y 80KB dependiendo del navegador.
- Overhead: Se envían con cada petición HTTP, consumiendo ancho de banda.
Para manejar objetos más grandes, podemos usar un enfoque similar al de localStorage:
/**
* Guarda un objeto como cookie utilizando JSON
* @param {string} nombre - Nombre de la cookie
* @param {Object} objeto - Objeto a guardar
* @param {Object} opciones - Opciones de la cookie
*/
function guardarObjetoComoCoookie(nombre, objeto, opciones = {}) {
try {
const jsonString = JSON.stringify(objeto);
if (jsonString.length > 4000) {
console.warn('El objeto es demasiado grande para una cookie (>4KB)');
}
crearCookie(nombre, jsonString, opciones);
} catch (error) {
console.error('Error al guardar objeto como cookie:', error);
}
}
/**
* Recupera un objeto almacenado como cookie
* @param {string} nombre - Nombre de la cookie
* @returns {Object|null} El objeto recuperado o null si no existe
*/
function obtenerObjetoDeCookie(nombre) {
const cookieValor = obtenerCookie(nombre);
if (!cookieValor) return null;
try {
return JSON.parse(cookieValor);
} catch (error) {
console.error('Error al parsear objeto desde cookie:', error);
return null;
}
}
// Ejemplo de uso
const preferenciasUsuario = {
tema: 'oscuro',
tamanoFuente: 14,
notificaciones: true,
configuracionPanel: {
modulosVisibles: ['estadisticas', 'mensajes', 'tareas'],
ordenModulos: ['tareas', 'mensajes', 'estadisticas']
}
};
guardarObjetoComoCoookie('preferencias', preferenciasUsuario, {
maxAge: 30 * 24 * 60 * 60, // 30 días en segundos
});
// Más tarde, recuperar el objeto
const preferenciasGuardadas = obtenerObjetoDeCookie('preferencias');
if (preferenciasGuardadas) {
console.log('Tema:', preferenciasGuardadas.tema);
console.log('Módulos visibles:', preferenciasGuardadas.configuracionPanel.modulosVisibles);
}
Cookies de terceros
- Safari bloquea completamente las cookies de terceros.
- Firefox bloquea cookies de terceros de rastreadores conocidos.
- Chrome planea eliminar el soporte para cookies de terceros en el futuro.
Consideraciones de privacidad
Estas normativas generalmente requieren:
- Consentimiento informado: Informar claramente a los usuarios sobre qué cookies se utilizan y para qué.
- Opción de rechazar: Permitir a los usuarios rechazar cookies no esenciales.
- Acceso y control: Dar a los usuarios acceso a sus datos y control sobre ellos.
Ejemplo básico de banner de cookies
function mostrarBannerCookies() {
// Comprobar si el usuario ya ha dado su consentimiento
if (obtenerCookie('consentimientoCookies')) {
// Si ya hay consentimiento, configurar cookies permitidas
configurarCookiesSegunConsentimiento();
return;
}
// Crear elementos del banner
const banner = document.createElement('div');
banner.className = 'banner-cookies';
banner.innerHTML = `
<div class="contenido-banner">
<p>Utilizamos cookies para mejorar tu experiencia en nuestro sitio.
Para saber más, consulta nuestra <a href="/politica-cookies">política de cookies</a>.</p>
<div class="botones-banner">
<button id="aceptar-cookies">Aceptar todas</button>
<button id="rechazar-cookies">Solo esenciales</button>
<button id="personalizar-cookies">Personalizar</button>
</div>
</div>
`;
// Añadir banner al DOM
document.body.appendChild(banner);
// Eventos de los botones
document.getElementById('aceptar-cookies').addEventListener('click', () => {
guardarConsentimiento({
esenciales: true,
preferencias: true,
estadisticas: true,
marketing: true
});
banner.remove();
});
document.getElementById('rechazar-cookies').addEventListener('click', () => {
guardarConsentimiento({
esenciales: true,
preferencias: false,
estadisticas: false,
marketing: false
});
banner.remove();
});
document.getElementById('personalizar-cookies').addEventListener('click', () => {
mostrarOpcionesPersonalizadas(banner);
});
}
function guardarConsentimiento(preferencias) {
// Guardar preferencias como cookie
guardarObjetoComoCoookie('consentimientoCookies', preferencias, {
maxAge: 180 * 24 * 60 * 60, // 180 días
sameSite: 'Strict'
});
// Configurar cookies según consentimiento
configurarCookiesSegunConsentimiento();
}
function configurarCookiesSegunConsentimiento() {
const consentimiento = obtenerObjetoDeCookie('consentimientoCookies');
if (!consentimiento) return;
// Ejemplo: configurar cookies de análisis si están permitidas
if (consentimiento.estadisticas) {
configurarCookiesAnalytics();
}
// Ejemplo: configurar cookies de marketing si están permitidas
if (consentimiento.marketing) {
configurarCookiesMarketing();
}
}
// Funciones de ejemplo para configurar distintos tipos de cookies
function configurarCookiesAnalytics() {
console.log('Configurando cookies de análisis');
// Código para inicializar herramientas de análisis
}
function configurarCookiesMarketing() {
console.log('Configurando cookies de marketing');
// Código para inicializar herramientas de marketing
}
// Mostrar el banner cuando se carga la página
document.addEventListener('DOMContentLoaded', mostrarBannerCookies);
Este es un ejemplo básico que debería adaptarse según las necesidades específicas de cada proyecto y los requisitos legales aplicables.
Normativas y consentimiento
La implementación correcta de un sistema de gestión de consentimiento de cookies va más allá del código JavaScript y debe considerar:
Resumen
Es crucial también entender las implicaciones de privacidad asociadas con el uso de cookies, especialmente en el contexto de las normativas actuales que requieren transparencia y consentimiento informado. Implementar un sistema adecuado de gestión de consentimiento no solo es una obligación legal en muchas jurisdicciones, sino también una buena práctica que respeta la privacidad de los usuarios.