Isomorphic and bulletproof πͺ cookie management for Meteor applications with support for Client, Server, Browser, Cordova, Meteor-Desktop, and other Meteor environments.
- π¨βπ» Stable codebase
- π 400,000+ downloads
- π¨βπ¬ TDD with Tinytest, CI fails below 95% coverage (
npm run test:coverage) - π¦ No external dependencies (no
underscore,jQuery, orBlaze) - π₯ Consistent API across Server and Client environments
- π± Compatible with Cordova, Browser, Meteor-Desktop, and other client platforms
- γοΈ Full Unicode support for cookie values
- π¨βπ» Supports
String,Number,Array,Object,Boolean, andnullas cookie value types - βΏ IE support, thanks to @derwok
- π¦ Shipped with TypeScript types
- π€ Shipped with an AI agent skill for Claude Code, Codex, Cursor, and other coding agents
- π¦ Looking for persistent Client (Browser) storage? Try the
ClientStoragepackage.
- Installation
- Import
- AI agent skill
- FAQ
- API
new Cookies()constructor β Create a newCookiesinstance.get()β Read a cookie.set()β Set a cookie.remove()β Remove one or all cookies.has()β Check if a cookie exists.keys()β List all cookie keys.send()β Sync cookies with the server.sendAsync()β Sync cookies asynchronously.middleware()β Register cookie middleware manually.destroy()β Unregister hooks, callbacks, and middlewarenew CookiesCore()constructor β Low-level class that can be used to directly parse and manage cookies
- Examples
- Running Tests
- Security
- Support our open source contributions
meteor add ostrio:cookiesUpgrading from v2? See docs/migration-v3.md
import { Cookies } from 'meteor/ostrio:cookies';The ostrio-cookies skill gives a coding agent the API, the common client and server mistakes, the Cordova setup, and the migration notes for the package version in your app. It follows the Agent Skills format.
Run in the root of your Meteor app:
npx skills add veliovgroup/Meteor-Cookies --skill ostrio-cookiesOr copy the file without extra tools:
mkdir -p .agents/skills/ostrio-cookies
curl -fsSL https://raw.githubusercontent.com/veliovgroup/Meteor-Cookies/master/.agents/skills/ostrio-cookies/SKILL.md -o .agents/skills/ostrio-cookies/SKILL.mdClaude Code reads skills from .claude/skills/. For a manual copy, use that directory instead of .agents/skills/.
- Cordova and Meteor-Desktop: Server-set cookies work out of the box. To send cookies from Client to Server, set
{ allowQueryStringCookies: true, allowedCordovaOrigins: true }on both Client and Server. See docs/cordova.md - Cookies missing on Server? Call
new Cookies()before registering routes, and placeostrio:cookiesabove community packages in.meteor/packages. See docs/server.md
Note
On the Server, new Cookies() registers one middleware that sets req.Cookies, a CookiesCore instance. req.Cookies.set() adds a Set-Cookie header to the current response. A Client instance sees the new cookie after a page reload or after send() / sendAsync() resolves
Many new Cookies() instances share that one middleware. See docs/server.md
Create a new instance of Cookies (available on both Client and Server).
Arguments:
opts{CookiesOptions} - Config object
Available CookiesOptions:
opts.auto{boolean} β [Server] Auto-bind asreq.Cookies(default:true)opts.handler{function} β [Server] Custom middleware handler; receives aCookiesCoreinstanceopts.onCookies{function} β [Server] Callback triggered after.send()or.sendAsync()is called and the cookies are received by the server. Runs only in the auto-registered middleware, not in a manual.middleware()opts.TTL{number | boolean} β Default expiration time (max-age) in milliseconds. Set tofalsefor session cookiesopts.runOnServer{boolean} β Set tofalseto disable server usage (default:true)opts.allowQueryStringCookies{boolean} β Allow passing cookies via query string (primarily for Cordova)opts.allowedCordovaOrigins{RegExp | boolean} β [Server] Allow setting cookies from specific origins (defaults to^http:\/\/localhost:12[0-9]{3}$iftrue)opts.name{string} - Sets.NAMEproperty of Cookies & CookiesCore instances, use it for instance identification, defaultCOOKIES
Example:
import { Cookies } from 'meteor/ostrio:cookies';
const cookies = new Cookies({
TTL: 31557600000 // One year TTL
});(Anywhere) Read a cookie. Returns undefined if the cookie is not found
Arguments:
key{string} β The name of the cookie.
cookies.get('age'); // undefined if not found
cookies.set('age', 25); // returns true
cookies.get('age'); // returns 25Cookies store text. After a page reload, and on the Server, a number comes back as a string ('25'). true, false, null, objects, and arrays keep their type.
(Anywhere) Create or update a cookie
Arguments:
key{string} β The cookie namevalue{string | number | boolean | null | object | array} β The cookie valueopts{CookieOptions} β Optional settings
Supported CookieOptions:
opts.expires{number | Date | Infinity}: Cookie expiration as aDateor a timestamp in milliseconds.0creates a session cookie and overridesTTLopts.maxAge{number}: Maximum age in secondsopts.path{string}: Cookie path (default:/)opts.domain{string}: Cookie domainopts.secure{boolean}: Transmit only over HTTPSopts.httpOnly{boolean}: Inaccessible to client-side JavaScriptopts.sameSite{boolean | 'None' | 'Strict' | 'Lax'}: Cross-site cookie policyopts.partitioned{boolean}: SpecifiesPartitionedattribute inSet-Cookieheader. When enabled, clients will only send the cookie back when the current domain and top-level domain matchesopts.priority{'Low' | 'Medium' | 'High'}: Specifies the value for thePriorityattribute inSet-Cookieheaderopts.firstPartyOnly{boolean}: Deprecated (usesameSiteinstead)
cookies.set('age', 25, {
path: '/',
secure: true
});(Anywhere) Remove cookie(s)
remove()β Removes all cookies on the current domain. Only a call without arguments does this;remove('')andremove(null)returnfalseremove(key)β Removes the specified cookieremove(key, path, domain)β Removes a cookie with the given key, path, and domain
Arguments:
key{string} - [Optional] The name of the cookie to removepath{string} - [Optional] The path from where the cookie was readable. E.g., "/", "/mydir"; if not specified, defaults to/. The path must be absolute (see RFC 2965). For more information on how to use relative paths in this argument, read moredomain{string} - [Optional] The domain from where the cookie was readable. E.g., "example.com", ".example.com" (includes all subdomains) or "subdomain.example.com"; if not specified, defaults to the host portion of the current document location (string or null)
const isRemoved = cookies.remove(key, path, domain); // boolean
const isRemoved = cookies.remove('age', '/'); // boolean
const isRemoved = cookies.remove(key, '/', 'example.com'); // boolean(Anywhere) Check if a cookie exists
Arguments:
key{string} β The name of the cookie
const hasKey = cookies.has(key); // boolean
const hasKey = cookies.has('age'); // boolean(Anywhere) Returns an array of all cookie names
const cookieKeys = cookies.keys(); // string[] (e.g., ['locale', 'country', 'gender'])(Client only) Send all current cookies to the server via fetch and callback. The server runs onCookies hooks, and cookies set by hooks are available on the client when the callback runs. Requires runOnServer: true (default)
Arguments:
callback{function} β Callback with signature(error, response).
cookies.send((error, response) => {
if (error) {
console.error(error);
} else {
console.log('Cookies synced:', response);
}
});(Client only) Same as .send(), returns a Promise<Response>. Rejects with Meteor.Error when runOnServer is false
const response = await cookies.sendAsync();
console.log('Cookies synced:', response);(Server only) Returns a middleware function to integrate cookies into your serverβs request pipeline.
Usage: Register this middleware with your Meteor server (e.g., via WebApp.connectHandlers.use).
import { WebApp } from 'meteor/webapp';
import { Cookies } from 'meteor/ostrio:cookies';
const cookies = new Cookies({
auto: false,
handler(cookiesInstance) {
// Custom processing with cookiesInstance (of type CookiesCore)
}
});
WebApp.connectHandlers.use(cookies.middleware());(Server only) Unregisters hooks, callbacks, and middleware
cookies.isDestroyed // false
cookies.destroy(); // true
cookies.isDestroyed // true
cookies.destroy(); // false β returns `false` as instance was already destroyedCookiesCore is low-level constructor that can be used to directly parse and manage cookies
Arguments:
opts{CookiesCoreOptions} β Optional settings
Supported CookiesCoreOptions:
_cookies{string | CookieDict} - Cookies string fromdocument.cookie,Set-Cookieheader, or{ [key: string]: unknown }ObjectsetCookie{boolean} - Set totruewhen_cookiesoption derives fromSet-Cookieheaderresponse{ServerResponse} - HTTP server response objectTTL{number | false} - Default cookies expiration time (max-age) in milliseconds. If false, the cookie lasts for the sessionrunOnServer{boolean} - Client only. Iftrueβ enablessendandsendAsyncfrom clientallowQueryStringCookies{boolean} - If true, allow passing cookies via query string (used primarily in Cordova)allowedCordovaOrigins{RegExp | boolean} - A regular expression or boolean to allow cookies from specific originsname{string} - Sets.NAMEproperty of CookiesCore instances, use it for instance identification, defaultCOOKIES_CORE
Note
CookiesCore instance has the same methods as Cookies class except .destroy() and .middleware()
import { CookiesCore } from 'meteor/ostrio:cookies';
// Parse a Set-Cookie header
const cookies = new CookiesCore({
_cookies: 'session=abc; Path=/; HttpOnly, theme=dark; Path=/',
setCookie: true
});
cookies.get('theme'); // 'dark'
cookies.keys(); // ['session', 'theme']Note
An object passed as _cookies is kept in memory only. On the Client it isn't written to document.cookie, so .send() doesn't transfer it. Use .set() to store a cookie in the browser
Server usage without middleware: docs/server.md
Use new Cookies() on Client and Server separately or in the same file
import { Cookies } from 'meteor/ostrio:cookies';
const cookies = new Cookies();
cookies.set('locale', 'en');
cookies.set('country', 'usa');
cookies.set('gender', 'male');
console.log(cookies.get('gender')); // "male"
console.log(cookies.has('locale')); // true
console.log(cookies.keys()); // ['locale', 'country', 'gender']
cookies.remove('locale');
console.log(cookies.get('locale')); // undefinedimport { Cookies } from 'meteor/ostrio:cookies';
import { WebApp } from 'meteor/webapp';
new Cookies();
WebApp.connectHandlers.use((req, res, next) => {
const cookiesInstance = req.Cookies;
cookiesInstance.set('locale', 'en');
cookiesInstance.set('country', 'usa');
cookiesInstance.set('gender', 'male');
console.log(cookiesInstance.get('gender')); // "male"
next();
});- Multiple handlers across modules
- Set cookies based on URL
- Manual middleware registration
- Cordova and Meteor-Desktop
- Clone the package repository.
- Open a terminal in the cloned directory.
- Run tests using:
# Default, headless Tinytest runner
npm test
# Direct command
mtest --package ./ --port=8888 --once
# Coverage report (text, coverage/index.html, coverage/lcov.info)
npm run test:coverage
# Type definitions
npm run test:types
# Browser fallback
meteor test-packages ./ --once --driver-package test-in-consoleOn Apple Silicon, the Chromium bundled with mtest is x86-only. Point it to a local Chromium-based browser:
PUPPETEER_EXECUTABLE_PATH="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" npm testReport vulnerabilities privately, see SECURITY.md.
- Try π Bridge CDN - A SEO-focused alternative to Cloudflare. CDN, DNS, IndexNow, Prerender, SEO, Edge Computing.
- Upload and share files using βοΈ meteor-files.com β Continue interrupted file uploads without losing any progress. There is nothing that will stop Meteor from delivering your file to the desired destination
- Use β² ostr.io for Server Monitoring, Web Analytics, WebSec, Web-CRON and SEO Pre-rendering of a website
- Star on GitHub
- Star on Atmosphere
- Sponsor via GitHub
- Support via PayPal