How to read and write cookies in JavaScript
How to Read and Write Cookies in JavaScript
Table of Contents
1. [Introduction](#introduction)
2. [Prerequisites](#prerequisites)
3. [Understanding Cookies](#understanding-cookies)
4. [Writing Cookies in JavaScript](#writing-cookies-in-javascript)
5. [Reading Cookies in JavaScript](#reading-cookies-in-javascript)
6. [Advanced Cookie Operations](#advanced-cookie-operations)
7. [Practical Examples and Use Cases](#practical-examples-and-use-cases)
8. [Best Practices](#best-practices)
9. [Common Issues and Troubleshooting](#common-issues-and-troubleshooting)
10. [Security Considerations](#security-considerations)
11. [Conclusion](#conclusion)
Introduction
Cookies are small pieces of data stored in a user's web browser that allow websites to remember information about visitors across different sessions. JavaScript provides powerful capabilities for creating, reading, modifying, and deleting cookies, making them essential tools for web developers who need to maintain user preferences, authentication states, shopping cart contents, and other persistent data.
In this comprehensive guide, you'll learn everything you need to know about working with cookies in JavaScript, from basic operations to advanced techniques. Whether you're a beginner looking to understand cookie fundamentals or an experienced developer seeking to implement sophisticated cookie management strategies, this article will provide you with the knowledge and practical examples you need to succeed.
Prerequisites
Before diving into cookie manipulation with JavaScript, ensure you have:
- Basic understanding of HTML, CSS, and JavaScript
- Familiarity with web browser developer tools
- Knowledge of client-server communication concepts
- A text editor or integrated development environment (IDE)
- A modern web browser for testing
- Basic understanding of HTTP protocols
Understanding Cookies
What Are Cookies?
Cookies are small text files stored by web browsers on behalf of websites. They consist of name-value pairs along with optional attributes that control their behavior, such as expiration dates, domains, paths, and security settings. The HTTP protocol is stateless, meaning each request is independent, but cookies provide a mechanism to maintain state across multiple requests.
Cookie Structure
A typical cookie contains the following components:
- Name: The identifier for the cookie
- Value: The data stored in the cookie
- Expires/Max-Age: When the cookie should be deleted
- Domain: Which domain can access the cookie
- Path: Which paths within the domain can access the cookie
- Secure: Whether the cookie should only be sent over HTTPS
- HttpOnly: Whether the cookie should be accessible only via HTTP (not JavaScript)
- SameSite: Controls cross-site request behavior
Cookie Limitations
Understanding cookie limitations is crucial for effective implementation:
- Maximum size: 4KB per cookie
- Maximum number: Typically 300 total cookies, 20 per domain
- Automatic transmission: Cookies are sent with every HTTP request to the domain
- Browser dependency: Different browsers may handle cookies slightly differently
Writing Cookies in JavaScript
Basic Cookie Creation
The simplest way to create a cookie in JavaScript is by assigning a string to `document.cookie`. Here's the basic syntax:
```javascript
document.cookie = "cookieName=cookieValue";
```
Simple Cookie Example
```javascript
// Create a simple cookie
document.cookie = "username=johnsmith";
// Create a cookie with a value containing spaces (URL encoded)
document.cookie = "fullname=John%20Smith";
// Create multiple cookies
document.cookie = "theme=dark";
document.cookie = "language=english";
document.cookie = "fontSize=16";
```
Setting Cookie Expiration
By default, cookies are session cookies that expire when the browser closes. To create persistent cookies, you need to set an expiration date:
```javascript
// Set expiration using a date string
document.cookie = "username=johnsmith; expires=Thu, 18 Dec 2024 12:00:00 UTC";
// Set expiration using Max-Age (in seconds)
document.cookie = "username=johnsmith; max-age=3600"; // Expires in 1 hour
// Create a cookie that expires in 30 days
const thirtyDaysFromNow = new Date();
thirtyDaysFromNow.setTime(thirtyDaysFromNow.getTime() + (30 24 60 60 1000));
document.cookie = `username=johnsmith; expires=${thirtyDaysFromNow.toUTCString()}`;
```
Advanced Cookie Attributes
```javascript
// Cookie with multiple attributes
document.cookie = "sessionId=abc123; expires=Thu, 18 Dec 2024 12:00:00 UTC; path=/; domain=.example.com; secure; samesite=strict";
// Breaking down the attributes:
// - expires: Cookie expiration date
// - path: Cookie is available for all paths on the domain
// - domain: Cookie is available for all subdomains of example.com
// - secure: Cookie only sent over HTTPS connections
// - samesite: Prevents cross-site request forgery attacks
```
Helper Function for Writing Cookies
Creating a reusable function makes cookie management more efficient:
```javascript
function setCookie(name, value, options = {}) {
let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
// Handle expiration
if (options.expires) {
if (options.expires instanceof Date) {
cookieString += `; expires=${options.expires.toUTCString()}`;
} else if (typeof options.expires === 'number') {
const date = new Date();
date.setTime(date.getTime() + (options.expires 24 60 60 1000));
cookieString += `; expires=${date.toUTCString()}`;
}
}
// Handle max-age
if (options.maxAge) {
cookieString += `; max-age=${options.maxAge}`;
}
// Handle path
if (options.path) {
cookieString += `; path=${options.path}`;
}
// Handle domain
if (options.domain) {
cookieString += `; domain=${options.domain}`;
}
// Handle secure flag
if (options.secure) {
cookieString += '; secure';
}
// Handle httpOnly flag (Note: Cannot be set via JavaScript)
// Handle sameSite
if (options.sameSite) {
cookieString += `; samesite=${options.sameSite}`;
}
document.cookie = cookieString;
}
// Usage examples
setCookie('username', 'johnsmith', { expires: 7 }); // Expires in 7 days
setCookie('theme', 'dark', { path: '/', secure: true });
setCookie('language', 'en-US', { maxAge: 3600, sameSite: 'strict' });
```
Reading Cookies in JavaScript
Basic Cookie Reading
Reading cookies requires parsing the `document.cookie` string, which contains all cookies for the current domain:
```javascript
// Display all cookies
console.log(document.cookie);
// Output: "username=johnsmith; theme=dark; language=english; fontSize=16"
```
Parsing Individual Cookies
Since `document.cookie` returns a string containing all cookies, you need to parse it to extract specific values:
```javascript
function getCookie(name) {
const nameEQ = encodeURIComponent(name) + "=";
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
let cookie = cookies[i];
while (cookie.charAt(0) === ' ') {
cookie = cookie.substring(1, cookie.length);
}
if (cookie.indexOf(nameEQ) === 0) {
return decodeURIComponent(cookie.substring(nameEQ.length, cookie.length));
}
}
return null;
}
// Usage examples
const username = getCookie('username');
const theme = getCookie('theme');
const language = getCookie('language');
console.log('Username:', username); // Output: Username: johnsmith
console.log('Theme:', theme); // Output: Theme: dark
console.log('Language:', language); // Output: Language: english
```
Alternative Cookie Reading Method
Using regular expressions for cookie parsing:
```javascript
function getCookieRegex(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) {
return decodeURIComponent(parts.pop().split(';').shift());
}
return null;
}
// Usage
const userPreference = getCookieRegex('theme');
console.log('User theme preference:', userPreference);
```
Getting All Cookies as an Object
Converting the cookie string into a more manageable object format:
```javascript
function getAllCookies() {
const cookies = {};
const cookieArray = document.cookie.split(';');
cookieArray.forEach(cookie => {
const [name, value] = cookie.trim().split('=');
if (name && value) {
cookies[decodeURIComponent(name)] = decodeURIComponent(value);
}
});
return cookies;
}
// Usage
const allCookies = getAllCookies();
console.log('All cookies:', allCookies);
// Output: { username: "johnsmith", theme: "dark", language: "english", fontSize: "16" }
```
Advanced Cookie Operations
Updating Cookies
To update a cookie, simply set it again with the same name:
```javascript
// Original cookie
setCookie('username', 'johnsmith');
// Update the cookie
setCookie('username', 'johnDoe');
// The username cookie now contains 'johnDoe'
```
Deleting Cookies
To delete a cookie, set its expiration date to a past date:
```javascript
function deleteCookie(name, path = '/', domain = '') {
let cookieString = `${encodeURIComponent(name)}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${path}`;
if (domain) {
cookieString += `; domain=${domain}`;
}
document.cookie = cookieString;
}
// Usage examples
deleteCookie('username');
deleteCookie('sessionId', '/', '.example.com');
```
Cookie Existence Check
```javascript
function cookieExists(name) {
return getCookie(name) !== null;
}
// Usage
if (cookieExists('username')) {
console.log('User is logged in');
} else {
console.log('User is not logged in');
}
```
Complete Cookie Management Class
Here's a comprehensive cookie management class that combines all operations:
```javascript
class CookieManager {
static set(name, value, options = {}) {
let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
if (options.expires) {
if (options.expires instanceof Date) {
cookieString += `; expires=${options.expires.toUTCString()}`;
} else if (typeof options.expires === 'number') {
const date = new Date();
date.setTime(date.getTime() + (options.expires 24 60 60 1000));
cookieString += `; expires=${date.toUTCString()}`;
}
}
if (options.maxAge) cookieString += `; max-age=${options.maxAge}`;
if (options.path) cookieString += `; path=${options.path}`;
if (options.domain) cookieString += `; domain=${options.domain}`;
if (options.secure) cookieString += '; secure';
if (options.sameSite) cookieString += `; samesite=${options.sameSite}`;
document.cookie = cookieString;
}
static get(name) {
const nameEQ = encodeURIComponent(name) + "=";
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
let cookie = cookies[i].trim();
if (cookie.indexOf(nameEQ) === 0) {
return decodeURIComponent(cookie.substring(nameEQ.length));
}
}
return null;
}
static delete(name, path = '/', domain = '') {
let cookieString = `${encodeURIComponent(name)}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${path}`;
if (domain) cookieString += `; domain=${domain}`;
document.cookie = cookieString;
}
static exists(name) {
return this.get(name) !== null;
}
static getAll() {
const cookies = {};
const cookieArray = document.cookie.split(';');
cookieArray.forEach(cookie => {
const [name, value] = cookie.trim().split('=');
if (name && value) {
cookies[decodeURIComponent(name)] = decodeURIComponent(value);
}
});
return cookies;
}
static clear(path = '/', domain = '') {
const cookies = this.getAll();
Object.keys(cookies).forEach(name => {
this.delete(name, path, domain);
});
}
}
// Usage examples
CookieManager.set('user', 'johnsmith', { expires: 7, path: '/', secure: true });
const user = CookieManager.get('user');
console.log('Current user:', user);
CookieManager.delete('user');
```
Practical Examples and Use Cases
User Preferences Storage
```javascript
class UserPreferences {
static saveTheme(theme) {
CookieManager.set('userTheme', theme, { expires: 365 });
this.applyTheme(theme);
}
static loadTheme() {
const theme = CookieManager.get('userTheme') || 'light';
this.applyTheme(theme);
return theme;
}
static applyTheme(theme) {
document.body.className = `theme-${theme}`;
}
static saveFontSize(size) {
CookieManager.set('fontSize', size, { expires: 365 });
this.applyFontSize(size);
}
static loadFontSize() {
const size = CookieManager.get('fontSize') || '16';
this.applyFontSize(size);
return size;
}
static applyFontSize(size) {
document.documentElement.style.fontSize = `${size}px`;
}
}
// Initialize user preferences on page load
document.addEventListener('DOMContentLoaded', () => {
UserPreferences.loadTheme();
UserPreferences.loadFontSize();
});
```
Shopping Cart Implementation
```javascript
class ShoppingCart {
static addItem(productId, quantity = 1) {
const cart = this.getCart();
if (cart[productId]) {
cart[productId] += quantity;
} else {
cart[productId] = quantity;
}
this.saveCart(cart);
}
static removeItem(productId) {
const cart = this.getCart();
delete cart[productId];
this.saveCart(cart);
}
static updateQuantity(productId, quantity) {
const cart = this.getCart();
if (quantity <= 0) {
delete cart[productId];
} else {
cart[productId] = quantity;
}
this.saveCart(cart);
}
static getCart() {
const cartData = CookieManager.get('shoppingCart');
return cartData ? JSON.parse(cartData) : {};
}
static saveCart(cart) {
CookieManager.set('shoppingCart', JSON.stringify(cart), { expires: 30 });
}
static getItemCount() {
const cart = this.getCart();
return Object.values(cart).reduce((total, quantity) => total + quantity, 0);
}
static clearCart() {
CookieManager.delete('shoppingCart');
}
}
// Usage examples
ShoppingCart.addItem('product-123', 2);
ShoppingCart.addItem('product-456', 1);
console.log('Cart contents:', ShoppingCart.getCart());
console.log('Total items:', ShoppingCart.getItemCount());
```
Session Management
```javascript
class SessionManager {
static login(userId, rememberMe = false) {
const sessionData = {
userId: userId,
loginTime: new Date().toISOString(),
lastActivity: new Date().toISOString()
};
const options = rememberMe ? { expires: 30 } : {}; // 30 days if remember me
CookieManager.set('userSession', JSON.stringify(sessionData), options);
}
static updateActivity() {
const session = this.getSession();
if (session) {
session.lastActivity = new Date().toISOString();
CookieManager.set('userSession', JSON.stringify(session));
}
}
static getSession() {
const sessionData = CookieManager.get('userSession');
return sessionData ? JSON.parse(sessionData) : null;
}
static isLoggedIn() {
return this.getSession() !== null;
}
static logout() {
CookieManager.delete('userSession');
}
static getUserId() {
const session = this.getSession();
return session ? session.userId : null;
}
}
// Auto-update activity on user interaction
document.addEventListener('click', () => {
if (SessionManager.isLoggedIn()) {
SessionManager.updateActivity();
}
});
```
Language and Localization
```javascript
class LocalizationManager {
static setLanguage(languageCode) {
CookieManager.set('preferredLanguage', languageCode, { expires: 365 });
this.loadLanguage(languageCode);
}
static getLanguage() {
return CookieManager.get('preferredLanguage') ||
navigator.language.substring(0, 2) || 'en';
}
static loadLanguage(languageCode) {
// This would typically load language resources
document.documentElement.lang = languageCode;
// Update text content based on language
const elements = document.querySelectorAll('[data-i18n]');
elements.forEach(element => {
const key = element.getAttribute('data-i18n');
element.textContent = this.getTranslation(key, languageCode);
});
}
static getTranslation(key, languageCode) {
// This would typically fetch from a translation service or file
const translations = {
'en': { 'welcome': 'Welcome', 'goodbye': 'Goodbye' },
'es': { 'welcome': 'Bienvenido', 'goodbye': 'Adiós' },
'fr': { 'welcome': 'Bienvenue', 'goodbye': 'Au revoir' }
};
return translations[languageCode]?.[key] || key;
}
}
// Initialize language on page load
document.addEventListener('DOMContentLoaded', () => {
const language = LocalizationManager.getLanguage();
LocalizationManager.loadLanguage(language);
});
```
Best Practices
1. Always Encode Cookie Values
```javascript
// Good: Properly encoded
CookieManager.set('userInfo', encodeURIComponent('John Doe & Associates'));
// Bad: Not encoded (may cause issues with special characters)
document.cookie = 'userInfo=John Doe & Associates';
```
2. Set Appropriate Expiration Times
```javascript
// Session data - no expiration (session cookie)
CookieManager.set('sessionToken', token);
// User preferences - long expiration
CookieManager.set('theme', 'dark', { expires: 365 });
// Temporary data - short expiration
CookieManager.set('flashMessage', 'Success!', { maxAge: 60 });
```
3. Use Secure Cookies for Sensitive Data
```javascript
// For HTTPS sites, always use secure flag for sensitive data
CookieManager.set('authToken', token, {
secure: true,
sameSite: 'strict',
expires: 1
});
```
4. Minimize Cookie Size and Quantity
```javascript
// Good: Store minimal data
CookieManager.set('userId', '12345');
// Bad: Store large objects (use localStorage instead)
// CookieManager.set('userProfile', JSON.stringify(largeUserObject));
```
5. Validate Cookie Data
```javascript
function getValidatedCookie(name, validator) {
const value = CookieManager.get(name);
if (value && validator(value)) {
return value;
}
return null;
}
// Usage
const userId = getValidatedCookie('userId', value => /^\d+$/.test(value));
const email = getValidatedCookie('email', value => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value));
```
6. Handle Cookie Failures Gracefully
```javascript
function safeCookieOperation(operation) {
try {
return operation();
} catch (error) {
console.warn('Cookie operation failed:', error);
return null;
}
}
// Usage
const theme = safeCookieOperation(() => CookieManager.get('theme')) || 'light';
```
Common Issues and Troubleshooting
1. Cookies Not Being Set
Problem: Cookies are not being created or saved.
Possible Causes and Solutions:
```javascript
// Issue: Incorrect syntax
// Wrong:
document.cookie = "name:value";
// Correct:
document.cookie = "name=value";
// Issue: Special characters not encoded
// Wrong:
document.cookie = "message=Hello, World!";
// Correct:
document.cookie = "message=" + encodeURIComponent("Hello, World!");
```
2. Cookies Not Being Read
Problem: `getCookie()` function returns null for existing cookies.
Solution: Check for common parsing issues:
```javascript
function debugCookies() {
console.log('Raw cookie string:', document.cookie);
console.log('All cookies:', CookieManager.getAll());
// Check for encoding issues
const cookies = document.cookie.split(';');
cookies.forEach(cookie => {
const [name, value] = cookie.trim().split('=');
console.log(`Cookie: ${name} = ${value}`);
console.log(`Decoded: ${decodeURIComponent(name)} = ${decodeURIComponent(value || '')}`);
});
}
```
3. Cookies Not Persisting
Problem: Cookies disappear after browser restart.
Solution: Ensure proper expiration is set:
```javascript
// Wrong: Session cookie (expires when browser closes)
CookieManager.set('preference', 'value');
// Correct: Persistent cookie
CookieManager.set('preference', 'value', { expires: 30 });
```
4. Cross-Domain Cookie Issues
Problem: Cookies not accessible across subdomains.
Solution: Set appropriate domain attribute:
```javascript
// For subdomain access
CookieManager.set('sharedData', 'value', { domain: '.example.com' });
```
5. HTTPS/Security Issues
Problem: Cookies not working on HTTPS sites.
Solution: Use appropriate security flags:
```javascript
// For HTTPS sites
CookieManager.set('secureData', 'value', {
secure: true,
sameSite: 'strict'
});
```
6. Cookie Size Limitations
Problem: Large cookies being truncated or rejected.
Solution: Monitor and limit cookie size:
```javascript
function setCookieWithSizeCheck(name, value, options = {}) {
const testCookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
if (testCookie.length > 4000) {
console.warn(`Cookie ${name} is too large (${testCookie.length} bytes). Consider using localStorage.`);
return false;
}
CookieManager.set(name, value, options);
return true;
}
```
7. Browser Compatibility Issues
Problem: Different behavior across browsers.
Solution: Use feature detection and fallbacks:
```javascript
function cookiesEnabled() {
try {
document.cookie = 'test=1';
const enabled = document.cookie.indexOf('test=') !== -1;
document.cookie = 'test=; expires=Thu, 01 Jan 1970 00:00:00 UTC';
return enabled;
} catch (e) {
return false;
}
}
if (!cookiesEnabled()) {
console.warn('Cookies are disabled. Using alternative storage.');
// Implement localStorage fallback
}
```
Security Considerations
1. Protect Sensitive Data
Never store sensitive information like passwords, credit card numbers, or personal identification numbers in cookies:
```javascript
// Never do this:
// CookieManager.set('password', userPassword);
// CookieManager.set('creditCard', cardNumber);
// Instead, store tokens or identifiers:
CookieManager.set('sessionToken', secureToken, {
secure: true,
sameSite: 'strict'
});
```
2. Use HTTPS and Secure Flag
Always use the secure flag for sensitive cookies on HTTPS sites:
```javascript
if (location.protocol === 'https:') {
CookieManager.set('authToken', token, {
secure: true,
sameSite: 'strict',
expires: 1
});
}
```
3. Implement SameSite Protection
Use SameSite attribute to prevent CSRF attacks:
```javascript
// Strict: Only sent with same-site requests
CookieManager.set('csrfToken', token, { sameSite: 'strict' });
// Lax: Sent with same-site requests and top-level navigation
CookieManager.set('sessionId', id, { sameSite: 'lax' });
// None: Sent with all requests (requires Secure flag)
CookieManager.set('tracking', id, { sameSite: 'none', secure: true });
```
4. Validate and Sanitize Cookie Data
Always validate cookie data before using it:
```javascript
function sanitizeCookieValue(value) {
if (typeof value !== 'string') return '';
// Remove potentially dangerous characters
return value.replace(/[<>\"'&]/g, '');
}
function getSecureCookie(name) {
const value = CookieManager.get(name);
return value ? sanitizeCookieValue(value) : null;
}
```
5. Implement Cookie Consent
Comply with privacy regulations by implementing cookie consent:
```javascript
class CookieConsent {
static hasConsent() {
return CookieManager.get('cookieConsent') === 'true';
}
static grantConsent() {
CookieManager.set('cookieConsent', 'true', { expires: 365 });
}
static revokeConsent() {
// Clear all non-essential cookies
const essentialCookies = ['cookieConsent', 'sessionId'];
const allCookies = CookieManager.getAll();
Object.keys(allCookies).forEach(name => {
if (!essentialCookies.includes(name)) {
CookieManager.delete(name);
}
});
}
static canSetCookie(name) {
const essentialCookies = ['cookieConsent', 'sessionId'];
return essentialCookies.includes(name) || this.hasConsent();
}
}
// Modified cookie manager with consent check
class ConsentAwareCookieManager extends CookieManager {
static set(name, value, options = {}) {
if (CookieConsent.canSetCookie(name)) {
super.set(name, value, options);
} else {
console.warn(`Cookie ${name} not set due to lack of consent`);
}
}
}
```
Conclusion
Mastering cookie management in JavaScript is essential for creating dynamic, user-friendly web applications. Throughout this comprehensive guide, we've covered everything from basic cookie operations to advanced security considerations and real-world implementations.
Key Takeaways
1. Foundation Knowledge: Understanding cookie structure, limitations, and browser behavior is crucial for effective implementation.
2. Practical Implementation: Use helper functions and classes to create maintainable, reusable cookie management code.
3. Security First: Always prioritize security by using appropriate flags, validating data, and following best practices for sensitive information.
4. User Experience: Implement features like user preferences, shopping carts, and session management to enhance the user experience.
5. Compliance: Ensure your cookie usage complies with privacy regulations through proper consent management.
Next Steps
To further enhance your cookie management skills:
1. Explore Modern Alternatives: Learn about localStorage, sessionStorage, and IndexedDB for client-side storage needs that don't require server communication.
2. Server-Side Integration: Study how cookies work with server-side technologies for authentication and session management.
3. Advanced Security: Investigate Content Security Policy (CSP) and other security headers that affect cookie behavior.
4. Performance Optimization: Learn techniques for minimizing cookie overhead and optimizing web application performance.
5. Testing and Debugging: Develop skills in testing cookie functionality across different browsers and environments.
By applying the knowledge and techniques presented in this guide, you'll be well-equipped to implement robust, secure, and user-friendly cookie management in your JavaScript applications. Remember to always consider user privacy, security implications, and performance impacts when working with cookies in production environments.