Skip to content

cookies ​

app.cookies — the webview's cookie jar, backend only

Every window in your app shares one cookie jar: the webview's own, the one a page's requests and a wrapped site's sign-in use. app.cookies lets the backend read and change it — HttpOnly cookies included — to keep someone signed in across reinstalls, sign them out, or hand a session to another part of your app.

It's backend only, and there's no page-side version: a page that could read the jar could read every site's session. If a page needs a cookie's value, return it from an api function of your own.

reading cookies ​

js
const cookies = await app.cookies.get({ url: 'https://app.example.com' });
const [sid] = await app.cookies.get({ url: 'https://app.example.com', name: 'sid' });

get(filter?) resolves to an array of cookies:

field
name, value
domaina leading . means the domain and its subdomains; without one the cookie is host-only
path
expiresmilliseconds since the epoch, or null for a session cookie
secure, httpOnly
sameSite'lax', 'strict' or 'none' — see SameSite

Filter by name, domain or path. With url, you get exactly the cookies a request to that URL would carry (matching domain, path and secure). Without url, get() returns the whole jar — on Linux that needs WebKitGTK 2.42 or newer.

setting a cookie ​

js
await app.cookies.set({
  url: 'https://app.example.com',
  name: 'theme',
  value: 'dark',
  expires: Date.now() + 365 * 24 * 3600 * 1000,
});

set(cookie) replaces any cookie with the same name, domain and path, and resolves true.

field
name, valuerequired
urlwhere it belongs. url alone makes the cookie host-only for that host
domain'.example.com' covers subdomains. Needed when there's no url
pathdefault /
expiresa Date or milliseconds since the epoch. Leave it out for a session cookie
secure, httpOnly
sameSitedefault 'lax'

removing cookies ​

js
await app.cookies.remove({ url: 'https://app.example.com' });             // sign out: all of them
await app.cookies.remove({ name: 'sid', domain: '.example.com' });        // one, e.g. straight from get()

remove(target) resolves to the number of cookies removed. Pass either a cookie's name and domain (and path, default /) — what get() returns — or a url, with an optional name, to remove everything get({ url, name }) would match.

keeping a session ​

A wrapped site's session lives in its cookies. To keep someone signed in after the app's data is reset, or move a session between machines, save the cookie somewhere safe and put it back later — secrets is the place for anything that grants access:

js
// backend
const SITE = 'https://app.example.com';

export const api = {
  saveSession: async (_, app) => {
    const [sid] = await app.cookies.get({ url: SITE, name: 'sid' });
    if (sid) await app.secrets.set('sid', JSON.stringify(sid));
  },
  restoreSession: async (_, app) => {
    const saved = await app.secrets.get('sid');
    if (saved) await app.cookies.set({ url: SITE, ...JSON.parse(saved) });
  },
  signOut: async (_, app) => {
    await app.cookies.remove({ url: SITE });
    await app.secrets.delete('sid');
  },
};

SameSite ​

set() defaults sameSite to 'lax' on every OS, because the engines disagree about a cookie without one. get() reports what the engine actually enforces, so a cookie a site set without SameSite reads as 'none' on macOS, 'lax' on Windows, and either on Linux depending on the WebKitGTK version. Passing a get() result straight back to set() keeps it behaving the same way. 'none' generally needs secure: true to be sent cross-site.

errors ​

The calls reject when a name or value contains a control character or ;, when a url isn't http:// or https://, or when set() has no name.

tiny.fetch is a separate client: it doesn't send the jar's cookies. Set a Cookie header yourself if you need one there.