> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ollie.shop/llms.txt
> Use this file to discover all available pages before exploring further.

# Session storage and cookies

> Keep small per-shopper state between calls with the sessionStorage global, and set cookies on the shopper's browser from a function

Functions are stateless between calls. Two mechanisms give you state per shopper: a **session storage** that Ollie carries for you in an encrypted cookie, and **cookies** you set yourself.

## Session storage

Inside a handler, a `sessionStorage` global is available with the Web Storage API: `getItem`, `setItem`, `removeItem`, `key`, `length`. Everything you store is encrypted, sent to the shopper's browser as an `HttpOnly` cookie named `__ollieshop_session`, and handed back to your functions on the shopper's next call. Nothing to import, nothing to return.

```typescript theme={"system"}
export const handler = async ({ res }: { req: Request; res: Response | null }) => {
  const seen = Number(sessionStorage.getItem("cartLoads") ?? "0");
  sessionStorage.setItem("cartLoads", String(seen + 1));
};
```

Rules that follow from how it is stored:

* **Store strings only.** `setItem("count", "3")`, not `setItem("count", 3)`. Serialize anything else with `JSON.stringify` first.
* **It is small.** The hub refuses a store over 4096 bytes (measured as the JSON of all keys and values) with `QuotaExceededError`, and browsers drop a cookie larger than 4 KB; after encryption that happens at roughly **2.8 KB** of stored data, silently. Treat 2 KB as the budget: ids, flags and counters, not copies of the cart. The checkout's own session is the place for cart data.
* **One namespace per shopper, per store.** Every function of the store reads and writes the same keys, for every version. Prefix keys with your function's name to avoid collisions.
* **Writes are kept only if the function succeeds.** A function that throws or times out loses its writes for that call.
* **Overwrite rather than clear.** To reset a key, set it to a marker value such as `""` instead of removing it or calling `clear()`.
* Writes made during the initial page render (the first load of the cart or checkout page) are not sent back to the browser; writes made on later calls (adding an item, saving an address) are.
* Components and the browser cannot read it. To expose a value to a component, put it in the response body of a response function; it reaches the component through `session.extensions`.

### Keeping it small

* Store only what the consumer reads. Never spread an upstream object into the store.
* Prefer one id and a count over an array of objects.
* Compress large values before storing them (`zlib.deflateSync` and base64url is enough), and log the stored length while developing.

## Cookies

A function can set cookies on the shopper's browser by returning a `Response` with `Set-Cookie` headers. This works from a request function that answers the call and from a response function:

```typescript theme={"system"}
export const handler = async ({ res }: { req: Request; res: Response | null }) => {
  if (!res) return;
  const headers = new Headers(res.headers);
  headers.append("Set-Cookie", "__ollieshop_segment=vip; Path=/; Expires=Wed, 31 Dec 2026 23:59:59 GMT");
  return new Response(await res.text(), { status: res.status, headers });
};
```

What survives the trip to the browser:

* **Only cookies named `__ollieshop_*`** are forwarded to the shopper. Other names are dropped by the checkout.
* The cookie is re-issued by the checkout on its own host; any `Domain` you set is replaced.
* `Expires` is kept, **`Max-Age` is lost**. Set `Expires` for a persistent cookie; without it the cookie lasts for the browser session.
* To delete a cookie, set `Expires` in the past. `Max-Age=0` does not delete it.
* `HttpOnly`, `Path` and `SameSite` are kept. `Secure` is added in production.
* Cookies are forwarded on the checkout's own calls (adding an item, saving an address), not during the initial page render.

Reading cookies in a function: `req.headers.get("cookie")` holds the shopper's cookies as the checkout forwarded them, without `__ollieshop_session`. Values can contain `=`, so split each pair at the first `=` only. Very large cookie headers are trimmed to the platform's own cookies, so do not rely on third-party cookies being present.

## Related

* [Writing a function](/ollie-shop/functions/writing-a-function.md): returning a `Response`
* [function dev](/ollie-shop/cli/function-dev.md): the local runtime keeps a plain session object, without the cookie round trip


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.