Skip to main content
Scramjet provides a complete cookie emulation system that allows proxified pages to use cookies as if they were on the original domain. This guide explains how cookie management works and how to interact with it. When a website is accessed through Scramjet, it’s technically served from your proxy domain, not the original domain. This means normal browser cookies wouldn’t work correctly. Scramjet solves this by:
  1. Intercepting Set-Cookie headers from responses
  2. Storing cookies in IndexedDB keyed by the original domain
  3. Injecting stored cookies into requests to the original domain
  4. Emulating document.cookie to work with the stored cookies
All cookie data is stored client-side in IndexedDB under the $scramjet database.
Cookies are stored in IndexedDB with the following schema:
type Cookie = {
  name: string;
  value: string;
  path?: string;
  expires?: string;
  maxAge?: number;
  domain?: string;
  secure?: boolean;
  httpOnly?: boolean;
  sameSite?: 'strict' | 'lax' | 'none';
};
Each cookie is uniquely identified by:
const cookieId = `${cookie.domain}@${cookie.path}@${cookie.name}`;

CookieStore class

The CookieStore class manages cookie operations:

Setting cookies

Cookies are automatically set from HTTP response headers:
import { CookieStore } from '@/shared/cookie';

const cookieStore = new CookieStore();
const url = new URL('https://example.com/page');

// Set cookies from Set-Cookie headers
const setCookieHeaders = [
  'sessionId=abc123; Path=/; HttpOnly',
  'theme=dark; Path=/; Max-Age=86400',
  'consent=true; Domain=.example.com; Secure; SameSite=Lax',
];

cookieStore.setCookies(setCookieHeaders, url);

Getting cookies

Retrieve cookies for a specific URL:
const url = new URL('https://example.com/page');

// Get cookies for JavaScript access (excludes HttpOnly cookies)
const jsCookies = cookieStore.getCookies(url, true);
console.log(jsCookies); // "sessionId=abc123; theme=dark"

// Get all cookies including HttpOnly (for HTTP requests)
const allCookies = cookieStore.getCookies(url, false);
console.log(allCookies); // "sessionId=abc123; theme=dark; consent=true"
The fromJs parameter controls whether HttpOnly cookies are included. Set it to true for JavaScript access, false for HTTP requests.
The getCookies method applies several filters:
1

Expiration check

Expired cookies are automatically removed:
// Cookies with past expiration dates are filtered out
if (cookie.expires && new Date(cookie.expires) < now) {
  // Cookie is removed from storage
}
2

Secure flag check

Secure cookies are only sent over HTTPS:
// Secure cookies require HTTPS
if (cookie.secure && url.protocol !== 'https:') {
  // Cookie is excluded
}
3

HttpOnly flag check

HttpOnly cookies are excluded from JavaScript access:
// HttpOnly cookies are not accessible to JavaScript
if (cookie.httpOnly && fromJs) {
  // Cookie is excluded
}
4

Path matching

Cookies are only sent to matching paths:
// URL path must start with cookie path
if (!url.pathname.startsWith(cookie.path)) {
  // Cookie is excluded
}
5

Domain matching

Cookies are only sent to matching domains:
// Check domain match for wildcard domains
if (cookie.domain.startsWith('.')) {
  if (!url.hostname.endsWith(cookie.domain.slice(1))) {
    // Cookie is excluded
  }
}
When setting cookies, Scramjet applies sensible defaults:
// If domain is not specified, use the current hostname
if (!cookie.domain) {
  cookie.domain = '.' + url.hostname;
}

// Ensure domain starts with a dot for wildcard matching
if (!cookie.domain.startsWith('.')) {
  cookie.domain = '.' + cookie.domain;
}

// Default path to root
if (!cookie.path) {
  cookie.path = '/';
}

// Default SameSite to Lax
if (!cookie.sameSite) {
  cookie.sameSite = 'lax';
}

// Normalize expires to string
if (cookie.expires) {
  cookie.expires = cookie.expires.toString();
}

Persisting cookies

The CookieStore provides methods to serialize and deserialize cookie data:
import { CookieStore } from '@/shared/cookie';

const cookieStore = new CookieStore();

// ... set some cookies ...

// Serialize cookies to JSON string
const serialized = cookieStore.dump();
console.log(serialized); // '{"domain@path@name":{...},...]'

// Save to localStorage, IndexedDB, etc.
localStorage.setItem('cookies', serialized);

// Later, restore cookies
const restored = localStorage.getItem('cookies');
const newCookieStore = new CookieStore();
newCookieStore.load(restored);

Accessing cookies in proxified pages

Inside a proxified page, document.cookie is automatically intercepted:
// In a proxified page

// Set a cookie
document.cookie = 'username=john; path=/; max-age=3600';

// Read cookies
const cookies = document.cookie;
console.log(cookies); // "username=john; sessionId=abc123"

// Parse cookies
function getCookie(name) {
  const value = `; ${document.cookie}`;
  const parts = value.split(`; ${name}=`);
  if (parts.length === 2) return parts.pop().split(';').shift();
}

const username = getCookie('username');
console.log(username); // "john"
Cookies are stored in IndexedDB:
// Database: $scramjet
// Object Store: cookies
// Format: { key: string, value: Cookie }
You can inspect cookies using browser DevTools:
1

Open DevTools

Press F12 or right-click and select “Inspect”
2

Navigate to Application tab

Click the “Application” tab (Chrome) or “Storage” tab (Firefox)
3

Find IndexedDB

Expand “IndexedDB” → “$scramjet” → “cookies”
4

View cookies

Browse the stored cookie objects

Managing cookies programmatically

You can access the cookie database directly:
import { openDB } from 'idb';

// Open the Scramjet database
const db = await openDB('$scramjet', 1);

// Read all cookies
const allCookies = await db.getAll('cookies');
console.log('All cookies:', allCookies);

// Read a specific cookie
const cookieKey = '.example.com@/@sessionId';
const cookie = await db.get('cookies', cookieKey);
console.log('Cookie:', cookie);

// Delete a cookie
await db.delete('cookies', cookieKey);

// Clear all cookies
await db.clear('cookies');
Directly manipulating the IndexedDB may cause unexpected behavior. Use with caution.

Domain attribute

Cookies can be set for specific domains:
// Cookie for exact domain
'session=abc; Domain=example.com'
// Stored as: .example.com
// Accessible to: example.com only

// Cookie for domain and subdomains
'session=abc; Domain=.example.com'
// Accessible to: example.com, www.example.com, api.example.com

Path attribute

Cookies can be restricted to specific paths:
// Cookie for all paths
'token=xyz; Path=/'
// Accessible to: /page, /api/data, /anything

// Cookie for specific path
'admin=1; Path=/admin'
// Accessible to: /admin, /admin/users
// Not accessible to: /page, /api

SameSite attribute

// Only sent in first-party context
'session=abc; SameSite=Strict'
// Not sent with cross-site requests

Common patterns

Session management

// Server sets session cookie
Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Lax; Max-Age=3600

// Cookie is automatically included in subsequent requests
fetch('https://example.com/api/user')
  .then(response => response.json())
  .then(data => console.log(data));
// Cookie: sessionId=abc123

Authentication tokens

// Store auth token in cookie
document.cookie = `auth=Bearer_${token}; path=/; secure; max-age=${60*60*24*7}`;

// Automatically sent with requests
const response = await fetch('/api/protected');

User preferences

// Save theme preference
document.cookie = 'theme=dark; path=/; max-age=31536000';

// Read theme on page load
function getTheme() {
  const value = `; ${document.cookie}`;
  const parts = value.split('; theme=');
  if (parts.length === 2) {
    return parts.pop().split(';').shift();
  }
  return 'light'; // default
}

const theme = getTheme();
document.body.classList.add(theme);

Clearing cookies

To clear cookies for a specific site:
import { openDB } from 'idb';

async function clearCookiesForDomain(domain) {
  const db = await openDB('$scramjet', 1);
  const allCookies = await db.getAll('cookies');

  for (const key of Object.keys(allCookies)) {
    if (key.startsWith(domain + '@')) {
      await db.delete('cookies', key);
    }
  }
}

// Clear cookies for example.com
await clearCookiesForDomain('.example.com');
To clear all cookies:
import { openDB } from 'idb';

async function clearAllCookies() {
  const db = await openDB('$scramjet', 1);
  await db.clear('cookies');
}

await clearAllCookies();

Working with frames

Learn about isolated browsing contexts

Configuration flags

Configure Scramjet behavior

Build docs developers (and LLMs) love