Tema
Cookies
document.cookie es una de las APIs más incómodas del navegador: es una sola cadena de texto que hay que partir a mano. Este snippet da funciones claras para leer, crear y borrar cookies, y un aviso de cookies listo para tu sitio.
¿Cookies, localStorage o sessionStorage?
| Cookies | localStorage | sessionStorage | |
|---|---|---|---|
| Se envían al servidor | Sí, en cada petición | No | No |
| Capacidad | ~4 KB | ~5 MB | ~5 MB |
| Caducidad | La que definas | Nunca | Al cerrar la pestaña |
| Accesible desde JS | Sí (salvo HttpOnly) | Sí | Sí |
| Úsalas para | Preferencias que el servidor necesita, consentimiento | Carrito, tema, borradores | Datos temporales de un flujo |
Sesiones y tokens
Las cookies de sesión o autenticación debe crearlas el servidor con HttpOnly, Secure y SameSite. Desde JavaScript nunca podrás (ni deberías) leerlas. Este snippet es para cookies de preferencias.
Helpers
js
/**
* Crea o actualiza una cookie.
* @param {string} nombre
* @param {string|number|object} valor objetos se guardan como JSON
* @param {{ dias?: number, ruta?: string, dominio?: string, sameSite?: 'Lax'|'Strict'|'None', segura?: boolean }} opciones
*/
export function setCookie(nombre, valor, { dias = 365, ruta = '/', dominio, sameSite = 'Lax', segura = location.protocol === 'https:' } = {}) {
const texto = typeof valor === 'object' ? JSON.stringify(valor) : String(valor);
let cookie = `${encodeURIComponent(nombre)}=${encodeURIComponent(texto)}`;
if (dias !== null) {
const expira = new Date(Date.now() + dias * 864e5);
cookie += `; expires=${expira.toUTCString()}`;
}
cookie += `; path=${ruta}; SameSite=${sameSite}`;
if (dominio) cookie += `; domain=${dominio}`;
if (segura || sameSite === 'None') cookie += '; Secure';
document.cookie = cookie;
}
/** Lee una cookie. Devuelve null si no existe. Si contiene JSON, lo convierte */
export function getCookie(nombre) {
const buscado = encodeURIComponent(nombre) + '=';
const par = document.cookie.split('; ').find((c) => c.startsWith(buscado));
if (!par) return null;
const valor = decodeURIComponent(par.slice(buscado.length));
try { return JSON.parse(valor); } catch { return valor; }
}
/** Todas las cookies como objeto */
export function getCookies() {
return Object.fromEntries(
document.cookie.split('; ').filter(Boolean).map((c) => {
const i = c.indexOf('=');
return [decodeURIComponent(c.slice(0, i)), decodeURIComponent(c.slice(i + 1))];
})
);
}
/** Borra una cookie (la ruta y el dominio deben coincidir con los de creación) */
export function deleteCookie(nombre, { ruta = '/', dominio } = {}) {
document.cookie = `${encodeURIComponent(nombre)}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=${ruta}`
+ (dominio ? `; domain=${dominio}` : '');
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
Uso
js
import { setCookie, getCookie, deleteCookie } from './cookies.js';
setCookie('idioma', 'es'); // 1 año
setCookie('ciudad', 'Guadalajara', { dias: 30 });
setCookie('preferencias', { moneda: 'MXN', vista: 'lista' });
setCookie('promo-cerrada', '1', { dias: 7 }); // no volver a mostrar el banner en 7 días
setCookie('temporal', 'x', { dias: null }); // cookie de sesión (muere al cerrar el navegador)
getCookie('idioma'); // "es"
getCookie('preferencias'); // { moneda: "MXN", vista: "lista" }
getCookie('no-existe'); // null
deleteCookie('ciudad');1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
Aviso de cookies (consentimiento)
Si usas Google Analytics, Meta Pixel u otras herramientas de seguimiento, la mayoría de leyes de privacidad (GDPR en Europa, LFPDPPP en México) piden informar y, en muchos casos, pedir consentimiento antes de cargarlas.
html
<div id="aviso-cookies" class="aviso-cookies" hidden role="dialog" aria-live="polite" aria-label="Aviso de cookies">
<p>Usamos cookies propias y de terceros para analizar el tráfico y mejorar tu experiencia.
<a href="/privacidad.html">Más información</a></p>
<div class="acciones">
<button data-consentimiento="rechazar" class="secundario">Sólo necesarias</button>
<button data-consentimiento="aceptar">Aceptar todas</button>
</div>
</div>1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
css
.aviso-cookies {
position: fixed; left: 16px; right: 16px; bottom: 16px; z-index: 1000;
max-width: 560px; margin: auto; padding: 18px 20px;
background: #0f172a; color: #e2e8f0; border-radius: 14px;
box-shadow: 0 10px 40px rgb(0 0 0 / .3); font: 14px/1.5 system-ui, sans-serif;
}
.aviso-cookies a { color: #a5b4fc; }
.aviso-cookies .acciones { display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap; margin-top: 10px; }
.aviso-cookies button { border: 0; border-radius: 8px; padding: 9px 16px; font-weight: 600; cursor: pointer; background: #6366f1; color: #fff; }
.aviso-cookies button.secundario { background: transparent; color: #e2e8f0; border: 1px solid #475569; }1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
js
import { getCookie, setCookie } from './cookies.js';
const aviso = document.getElementById('aviso-cookies');
const consentimiento = getCookie('consentimiento'); // "aceptar" | "rechazar" | null
function cargarAnalitica() {
// Sólo se carga si el usuario aceptó
const s = document.createElement('script');
s.async = true;
s.src = 'https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX';
document.head.appendChild(s);
window.dataLayer = window.dataLayer || [];
window.gtag = function () { dataLayer.push(arguments); };
gtag('js', new Date());
gtag('config', 'G-XXXXXXX', { anonymize_ip: true });
}
if (consentimiento === 'aceptar') cargarAnalitica();
if (!consentimiento) aviso.hidden = false;
aviso.addEventListener('click', (e) => {
const decision = e.target.dataset.consentimiento;
if (!decision) return;
setCookie('consentimiento', decision, { dias: 180 });
aviso.hidden = true;
if (decision === 'aceptar') cargarAnalitica();
});
// Enlace en el footer para cambiar de opinión: <a href="#" id="config-cookies">Configurar cookies</a>
document.getElementById('config-cookies')?.addEventListener('click', (e) => {
e.preventDefault();
aviso.hidden = false;
});1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Error común
Intentar borrar una cookie sin indicar la misma path con la que se creó. Si se creó en /tienda, deleteCookie('x') (que usa /) no la borra. Usa deleteCookie('x', { ruta: '/tienda' }).
Limitaciones de Safari
Safari (ITP) limita a 7 días las cookies creadas con JavaScript. Para preferencias que deban durar más, guárdalas también en localStorage o créalas desde el servidor.