# Cookies

Every cookie and every browser key Demofy sets, what each is for, and which need consent.

This is every cookie and every browser-storage key Demofy sets, what each is for, and which of them wait for your permission. It is a complete list rather than a representative one: if something is not here, this site does not set it. This page covers what is stored in your browser; what is recorded about you and where it goes is the [privacy policy](https://demofy.io/privacy).

## Two categories, and only one of them asks

**Strictly necessary** — the things without which the product does not do what you just asked. These are set regardless, because a consent bar offering to switch off the cookie that signs you in would be offering to break the site.

**Analytics** — page counting, error reports from your browser, and a recording of a sample of sessions. Nothing in this category loads until you accept. Declining does not degrade anything: the tags are simply not put on the page, so they make no request and set nothing.

There is no third category. Demofy runs no advertising, no retargeting and no cross-site tracking of any kind, so there is nothing to offer you a switch for.

## Strictly necessary

| Name | Set by | What it is for | How long |
| --- | --- | --- | --- |
| `better-auth.session_token` (`__Secure-` prefixed over HTTPS) | Demofy, on `app.demofy.io` | Keeps you signed in. Read on every request that needs to know who you are. | 30 days |
| `better-auth.state`, `better-auth.pkce_code_verifier` | Demofy, on `app.demofy.io` | Only during a Google or Apple sign-in, to tie the redirect back to the request that started it. Deleted as soon as the sign-in completes. | Minutes |
| `demofy_verify_token` | Demofy, on `app.demofy.io` | Only when you open the link in an email-confirmation message. It holds that link’s one-time token for the next page, so the token is not left in the address bar, where page views and error reports could pick it up. It is not readable by scripts on the page, is sent only over HTTPS and only to the confirmation page, and is cleared when you confirm. It holds the signed confirmation token from the link, which includes the email address being confirmed. | No longer than the link, which works for an hour |
| `demofy_reset_token` | Demofy, on `app.demofy.io` | Only when you open the link in a password-reset message. It holds that link’s one-time token for the next page, for the same reason. It is not readable by scripts on the page, is sent only over HTTPS and only to the reset page. | The browser session |
| `demofy_reset_next` | Demofy, on `app.demofy.io` | Only alongside the cookie above. It holds nothing but the page inside the studio to return you to after the reset, and only a page that passes the same check as the sign-in redirect. It has the same protections and the same reach as the cookie above. | The browser session |
| `demofy_known_device` | Demofy, on `app.demofy.io` | Only after you sign in with an email address and password. It lets this browser keep signing in to that account if somebody else has made a run of wrong guesses at the address, which otherwise pauses sign-in from browsers that have never signed in to it. It holds a one-way fingerprint of the address, never the address itself, and up to five of them, one for each account you have signed in to on this browser. It is not readable by scripts on the page and is sent only over HTTPS. | 180 days |
| `demofy_invite_done` | Demofy, on `demofy.io` and `app.demofy.io` | Only after you create an account or sign in having arrived through a partner’s referral link. It says the invitation is over, so our pages stop showing it to you; if you have just created your account, it also lets the studio tell you once that the invite is linked. It holds no identifier — the same value for everybody — and is never read to decide anything about your account. | 1 year |
| `dub_id` | Demofy, on `demofy.io` and `app.demofy.io` | Only if you arrived through a partner’s referral link. It holds the click id that link carried, so that if you sign up the partner who sent you is credited. Read when you create an account, and to show you an invitation on our pages instead of the usual welcome; it carries nothing about you. | 90 days |
| `demofy_consent_analytics` | Demofy, on `demofy.io` and `app.demofy.io` | Remembers whether you accepted or declined analytics, so that an answer you gave on one of the two is not asked for again on the other, and so that changing it on one changes it on both. It holds one word, `granted` or `denied`, and is written only when you press one of those buttons or the switch below. Our pages read it in your browser; nothing on our servers uses it. | 1 year |
| `demofy.consent.analytics.v1` (browser storage, not a cookie) | Demofy | Remembers whether you accepted or declined analytics on this site, so you are asked once. The same answer is kept in the cookie above so the other of the two sites can read it. The answer reaches our server once, with the sign-up form, so your account records whether where you first arrived from may go to our analytics product. | Until you clear site data |
| The icon rail’s expanded/collapsed state (browser storage) | Demofy, in the studio | Remembers whether you left the sidebar open. Carries no identifier. | Until you clear site data |
| A step-editor draft (session storage) | Demofy, in the editor | Keeps unsaved edits if the tab reloads. Dies with the tab, on purpose. | The tab |
| `demofy_prompt_pref` and the `demofy_prompt_*` counters (browser and session storage) | Demofy | Remembers whether you asked for tips and prompts to be switched off, which one you were last shown and when, how many times you have closed each, how many times you have visited, whether you have already answered the Refer & Earn page's one "was this clear?" question, and, if you arrived through an invitation, whether this visit has already checked for it and whether you closed its bar. It is what stops the same card appearing twice in one visit or ever again once you have waved it away three times. It carries no identifier and never leaves this browser. | Until you clear site data, except the per-visit ones, which die with the tab |

None of the last four is a cookie. They are listed anyway, because a page that named only the cookies would be technically complete and practically misleading, and this page is not for lawyers.

The prompt switch is in [settings](https://demofy.io/settings) as **Show tips and prompts**. It is free for everyone and it is on until you turn it off; the cookie bar above is the one thing it cannot silence, because asking that question is not optional for us.

## Analytics — only after you accept

| Name | Set by | What it is for | How long |
| --- | --- | --- | --- |
| `_ga`, `_ga_<container id>` | Google Analytics 4 | Tells a returning visit from a new one, so page counts are not everybody counted once per visit. Set to expire in 90 days rather than Google’s default two years. | 90 days |
| `ph_<key>_posthog` and its matching browser-storage entry | PostHog | The same job for product analytics, when the deployment has a PostHog key. It also records whether this session is one of the sample that is recorded. | 1 year |
| `ph_<key>_window_id`, `ph_<key>_primary_window_exists` (session storage, not cookies) | PostHog | Tell one open tab of this site from another, so events and recordings from two tabs are not mixed together. Written only after you accept, and only when the deployment has a PostHog key. | The tab |
| `demofy.first_touch.v1` (browser storage, not a cookie) | Demofy | Remembers the campaign link you first arrived from, once, so a signup can be attributed to it. Written only after you accept, and never overwritten afterwards. | Until you clear site data |
| `sentryReplaySession` (session storage, not a cookie) | Sentry | Holds the identifier of the session replay in progress and whether it is being recorded or only held in case of an error, so one visit is one replay. Written only after you accept, and only when the deployment has a browser Sentry key. | The tab |

All five are first-party. None is used for advertising: Google signals and ad-personalisation signals are switched off in the tag itself, and no identifier is shared between Google Analytics and your Demofy account.

## Set by someone else, during checkout only

If you buy a plan, RevenueCat’s hosted checkout loads Stripe’s payment fields in Stripe’s own frames, and Stripe sets its own cookies there (`__stripe_mid`, `__stripe_sid`) for fraud prevention. Demofy neither sets nor reads them. They appear only on the upgrade page and only if you open checkout.

## Changing your mind

The bar asks once, so this is where the answer is changed. The switch below reads the same stored answer the bar wrote and writes the opposite one, and the tags follow it in this visit: turning analytics off takes them off the page you are on, without a reload, and turning it on puts them there the same way.

Two honest caveats. The switch changes what loads from here on; it does not reach back and delete a cookie a tag already set, so if you have just turned analytics off and want the `_ga` pair gone as well, your browser’s own “cookies and site data” panel is the thing that removes them. And clearing this site’s cookies and storage still works and does something slightly different: it forgets the answer entirely rather than recording the opposite one, so the bar asks again from scratch. (Clear only the storage and not the cookie, and the answer you gave is read back from the cookie.)

## A shared video is not measured at all

A public share link — and the same page embedded in someone else’s site — loads no analytics tag, shows no consent bar, reads no session and sets no cookie. What is recorded about a shared demo is a count per video and per moment reached, on our own server, with no viewer, no address, no session and no timestamp attached. There is nothing about a viewer to consent to, because nothing about a viewer is written down.

Canonical page: https://demofy.io/cookies
