Privacy Policy
Effective 4 September 2026 Applies to: factbox.app
Factbox is a subscription you read on the web, and it now has accounts and a server behind them. Most of what it remembers about you is still written into your own browser, where clearing site data is the whole of deleting it. Some of it is not: an account, the answers you gave when you started, what you have read, and a payment all live somewhere your phone cannot reach. This page keeps those two piles apart — what is written where, what leaves the browser, which companies receive it, and how to be rid of each.
The short version
- You can sign in with Google, or with an email address and a password. The account is held by Google Firebase; your password never reaches us.
- Signing in creates a record on our side under a Firebase user id. Whether you are a subscriber is written there by Stripe's webhook, and that is what makes a subscription work on a second phone.
- The six questions at the start of signing up are answered by tapping one of a fixed set of buttons, never by typing, and all six are written into this browser. If you are signed in, two of the six are also copied to your account record — the subjects you picked and the minutes a day you chose — along with your name and email address if you gave them. The other four stay on this device. Section 07 lists that record field by field.
- What you have read, how far into each story, and which stories you saved are written into this browser. If you are signed in they are also written to your account, which is what carries your place in a story to a second phone. Signed out, they never leave the browser. Section 08 is the whole of it.
- Payment is handled by Stripe, on Stripe's own pages. Card details never touch our pages.
- Your restore link is a bearer token: anyone holding it has access.
- Every page sends events to PostHog and to Google Analytics. Once you are signed in, those events carry your Firebase user id, so they are not anonymous. There is a one-tap off switch in section 05.
- The people who run Factbox can open an internal dashboard. Almost everything on it is counted rather than named — but one view lists readers by email address, with the stories they read and how far they got. The email is joined to your reading on our server, from your account record; it is never sent to the analytics services. Section 05 is the whole of it.
- Every page also loads a font from Google, which means Google sees your IP address on every page whether or not you have an account.
- Anything you write in the two boxes on the support page is sent to us and stored, along with the reply address you give.
- Clearing this site's data in your browser removes everything in section 02 and section 03. It does not remove your account, the record under it, or a message you have sent us — for that, see section 11.
01 · Who this is from
Factbox is published by Iris Monet Labs LLC. In this policy "we"
means that company, and "the site" means the pages served from
factbox.app. Questions go to
hello@factbox.app.
This policy covers the site and the small backend behind it. It does not cover Stripe, whose pages take the payment, or the sites you reach by following a link out of the artwork credits. The other companies involved are named in section 09.
02 · What the site stores in your browser
These are the exact keys, as written by the code. Nothing on this list is
read off your device by anything other than the site's own code running in
it, and while you are signed out none of it leaves at all. Signed in,
three of these keys are mirrored to your account and say so:
fb_acct_v1 (section 07), and fb_read_v1 and
fb_saved_v1 (section 08). Your email address is also
separately re-entered at Stripe (section 06).
| Key | What it holds |
|---|---|
fb_unlocked_v1 | Whether this browser has access without an account. The value is the single character 1, or nothing at all. |
fb_pass_v1 | Your restore token, so the restore link can be rebuilt on demand. See §06. |
fb_passsrc_v1 | Where that access came from: stripe, restore or local. |
fb_read_v1 | Your reading memory, as one small JSON object: per story, the furthest card you reached, how many cards that story had, a whole-second timestamp of when you last touched it, and a finished flag. Capped at 60 stories and about 20 KB; the oldest entries are dropped first. |
fb_saved_v1 | Stories you saved, as a list of story id and a whole-second timestamp, newest first. Capped at 200 entries and about 8 KB. |
fb_saveprobe | Written and immediately deleted once per page load, purely to find out whether this browser will accept a write at all. |
fb_owner_v1 | Set only if someone unlocks the site with the owner passphrase. It exists so the person who makes the site can read it on a new phone without paying. |
fb_acct_v1 | What you told the opening questions and the sign-up funnel, as one small JSON object: a randomly generated local id, the email address you typed, your first name if you gave one, the subjects you picked, why you are here, what usually stops you reading, how much of a day goes to scrolling, who you want to be a year from now, the minutes a day you chose (or a marker meaning you asked us to choose), which plan you chose, whether you finished the questions, and when the record was made. It also holds the answers to an earlier version of these questions, where they were given: what draws you to history, which of three "sounds familiar" statements you ticked, the streak you picked and the plan questions' three yes/nos. Every one of these is a value from a fixed list written into the page; none of them is text you typed except the email address and first name. Capped at 700 bytes. |
fb-sound | Whether you switched a story's ambient sound on or off, so it does not have to ask again. |
fb-sound-hint | Set once, after you have been shown the note about your phone's silent switch, so it is never shown twice. |
fb_analytics_optout_v1 | Set to 1 if you press the off switch in §05. It is the reason the analytics scripts do not load on your next visit, so deleting it turns them back on. |
fb_support_last_v1 | The time you last sent a message from the support page, as a number of milliseconds. It is there so a double tap does not send the same message twice. |
fb_cache_owner_v1 | The Firebase user id whose reading and saves the two keys above are currently holding. It is how the site knows not to show one person's reading to the next person who signs in on the same browser, and it is emptied on sign-out. |
fb_analytics_notice_v1 | Set once you have been shown the note about analytics, so it is not shown again. |
fb_access_seen_v1 | Up to twenty characters: how access arrived, plus the first eight characters of the token it arrived with. It exists so a single unlock is counted once rather than on every page. The token itself is never sent anywhere. |
Four further values are kept in sessionStorage, which your
browser discards when you close the tab. fbx_corrected_v1 is
set after the page has reloaded itself once to correct a paywall it drew
before your subscription had loaded, so it can never do that twice.
fbpg_pulled_v1 does the same job for a shelf drawn before
your account's reading had arrived. fb_auth_redirect_v1 is
set while you are away at Google's sign-in page, so the site knows to
expect you back. fb_live_v1 holds the Firebase user id this
tab has actually seen signed in, so a page cannot draw personal state on
the strength of a stale hint.
Story ids are strings like 07B. With the single exception of
fb_acct_v1, no key on this list contains a name, an email
address, or anything else that identifies you.
PostHog, Google Analytics and Firebase each keep storage of their own in your browser, under names they choose rather than ones written here. Sections 05 and 09 say what those are for. Clearing this site's data removes them along with everything above.
03 · Cookies
The site sets first-party cookies under four names:
fb_unlocked_v1, fb_pass_v1 and
fb_passsrc_v1 — the three access values above — and
fb_acct_v1, which is mirrored only while it stays under 700
bytes and is silently skipped if it grows past that. They are set for one
year on path=/ with SameSite=Lax, and with the
Secure flag when the page is served over HTTPS.
The reason is specific. Most readers arrive from Instagram or TikTok, and those apps open links in an in-app browser that routinely throws away localStorage between sessions while keeping cookies. Without the cookie, a person who paid inside Instagram would be asked to pay again the next day. The site reads whichever of the two stores still has the value, and repairs the other.
Your reading memory and your saved stories are never put in a cookie. They are far too large, and a cookie rides along on every request — which would mean sending your reading history to the web server on every page load. They stay in localStorage. Signed out, that is the end of them; signed in, they are written to your account by a request that goes to Firestore and nowhere else, which is section 08.
Those four are the ones our own code sets. They are functional: they remember a purchase you made and what you typed into the funnel. They do not follow you to other sites and they feed no advertising system. The analytics services in section 05 set cookies of their own, on this domain, which is what an identifier for a returning reader is.
04 · Signing in
There are two ways in: Google, and an email address with a password. Both are handled by Google Firebase Authentication. We never see your password — Firebase holds it, and the site has no field, no code and no storage that could keep one. Signing up with an email address makes Firebase send you a verification message. Asking for a password reset makes Firebase send you another. Both leave Google's servers, not ours.
Signing in with Google hands Google the fact that you are signing in to Factbox, and hands us the email address, display name and profile photo on that Google account.
Phone sign-in was offered on an earlier version of these pages. It is gone: there is no phone field, no SMS code and no reCAPTCHA on the site.
05 · Analytics
Every page sends events to PostHog, a product-analytics service hosted in the United States, and to Google Analytics 4 through Firebase. Both get the same events. It is how we find out which stories people finish and which ones lose them.
Running two is a duplication, and it is meant to be temporary: they are being compared on the same traffic so that one can be dropped. Until then your visit is measured twice. The switch below turns off both.
Analytics is only transmitted from factbox.app and
www.factbox.app. On any other host the code loads, runs and
sends nothing, so a test build cannot report itself as a reader.
What is attached to you
Once you sign in, the events are no longer anonymous. The
site calls PostHog's identify with your Firebase user id, which
ties this browser to your account and joins the reading you did before you
signed in to the same person. From that point every event also carries
three properties: whether you have an account, whether you are a
subscriber, and which of admin, subscriber,
legacy or none your access is. Signed out, no user
id is sent and those three still are.
Both services also keep an identifier of their own in your browser, so two visits from the same browser are recognised as the same reader. That is true whether or not you have an account.
The opening questions also keep a short random code of their own in this browser, so that one run through them can be told from another and we can see where people stop. It is generated by your browser, it is not derived from anything about you, it is never sent to Stripe or to anyone else, and clearing this site’s data removes it.
Where the requests go
PostHog is not reached at posthog.com. The site sends its
analytics to factbox.app/ink/…, a path on this domain served by
a Cloudflare Worker that forwards it to PostHog. This is deliberate, and the
reason is worth stating plainly: blocker lists match PostHog by hostname,
and a request to factbox.app matches no list. A content
blocker that blocks PostHog will not stop these events. The off
switch below will, and blocking factbox.app/ink/ will.
Two things the Worker does are worth naming. It strips the cookie
header before forwarding, so the site's own cookies — including
Firebase's — never reach PostHog. And it passes your IP address on in an
X-Forwarded-For header, so PostHog places you in a country
rather than in a Cloudflare datacentre. If the Worker does not answer, the
site falls back to PostHog's own hosts and the events go there directly.
Google Analytics is not proxied. Those events go to Google.
What the events say
This is the complete list of event names, grouped. Every one of them also carries the three properties above, and your user id if you are signed in.
page_open— which page was opened, as a name likehomeorlibrary. The query string is dropped.ui_click— a button or link was tapped, carrying the page and the control's name. The name comes from the element's id or the words printed on it, which are copy written in our own repository. It never reads a text box, a menu or anything you typed. If the control is an on/off switch — the ambient-sound button, the save bookmark — it also carries whether that switch was on or off at the moment you pressed it. The sound button's name says which way you turned it:sound_onorsound_off.client_error— something on the page failed. This carries the error message, the file and line it came from, the page name and which release of the site you were on. The message and the filename are stripped of anything that could identify you or unlock anything before they are sent: web addresses lose their query strings, so a restore link or a Stripe session id cannot travel with them; anything shaped like an email address is replaced with the word<email>; and any long unbroken run of letters and numbers, which is what an id or a token looks like, is replaced with<id>. We never send the full stack trace. A single page load can send at most eight of these, and none at all once you have started navigating away.stack_open,resume_used,stack_complete,stack_dropoff,story_time— a story was opened, resumed, finished or left part-way, carrying the story id, the card reached, and how many seconds you were actually reading with the tab in front of you.card_view— a card left the screen, carrying the story id, the card number, the name of the page you were reading it on, its narrative beat, its subject, and how many seconds it was on screen. The page name is there because the same story is served at more than one address, and without it we cannot tell how far people get on the one our links point at. Anything under a second is treated as a swipe passing through and is not sent. (This applies to story cards. The opening questions are measured with no minimum — seeob_leaveabove.)save_add,save_remove,library_unsave,library_view,library_own_view,home_view,rec_view,rec_click— a story was saved or unsaved, a shelf was opened, or an end-of-story recommendation was shown or followed. These carry a story id and which slot was tapped.join_view,join_step,join_skip,join_draw,join_relate,join_time,join_streak,join_praise,join_plan_start,join_plan_ask,join_plan_answer,join_plan_built,join_plan_pick,join_signup,join_login_hit,join_login_known,join_login_miss,join_restore_use— a step of the sign-up funnel was shown, answered, skipped or completed, carrying the step name and the answer key or plan name.ob_step— a screen of the opening questions was shown, carrying the screen’s name, its number in the sequence, what kind of screen it is (a question, an interstitial, the loader, the results), whether you were picking up an unfinished run, and which release of the site you were on.ob_answer— you chose an answer, carrying which question it was and which of the fixed options you picked, as a short key likepeople. These are the options printed on the screen, written in our own repository. There is no text box in these questions, and nothing you type anywhere on the site is in this event.ob_leave— a screen ended, carrying its name and how many milliseconds it was on your display, along with how it ended: you pressed Continue, you pressed Back, you skipped it, or you went away. Unlike card time, there is no minimum here — a screen you dismissed in a fifth of a second is recorded as a fifth of a second, because how fast people move through these screens is the thing we are trying to see. Anything over thirty minutes is treated as a device that went to sleep and is not sent.ob_done— you reached the end of the opening questions, carrying how many screens you saw, how many questions you answered, and whether this run had been picked up from an earlier one.signin_google,signin_email,signup_email,signout— someone signed in, signed up or signed out. These carry no properties of their own.paywall_view,subscribe_click,checkout_start,checkout_blocked,billing_portal,access_gained— the subscribe screen was shown, a plan was chosen, a checkout was started or refused, the billing portal was opened, or access began working in this browser.access_gainedcarries how it arrived:stripe,restoreorlocal.support_send,support_idea— a message was sent from the support page. The event records that it happened, and carries nothing else. What you wrote is not in it. Where the message itself goes is section 08.owner_unlock— the site was unlocked with the owner's own passphrase.
None of these carries your email address, your name, or anything you typed into a box. Your Firebase user id is on all of them once you are signed in, and that id is the thread back to the account record in section 07.
Who here can see it, and what they see
The accounts marked as administrators — the people who run Factbox — can open an internal dashboard. Everything on it is counted rather than named: how many people opened a story, how far they scrolled, how many subscribed. There are three exceptions, and they are deliberate rather than accidental.
One view on that dashboard lists readers by email address. For each reader it shows the email address on their account, which stories they opened, the furthest card they reached in each one, whether they finished it, and when they were last reading. If you have no account you appear on it with no email address, as “anonymous”, with the same reading beside you.
A second view shows how long each reader spent on each card. For each reader — by email address where they have an account, anonymously where they do not — it shows every card they were measured reading, the page they read it on, how many seconds it was on their screen, and a total for that reader. This is the card_view data described above, listed per person rather than added up.
A third view shows one reader’s activity in order. Choosing a reader from those lists shows what that one person did, oldest first, within a window of at most 31 days: the pages they opened, the stories and cards they read and for how long, the buttons they pressed by name, where they stopped, and the time between each thing and the next — so a gap of a day between two visits is visible as a gap. It is bounded to at most 500 events and it shows nothing that is not already in the list of events above. It does not show the text of any error message, and it does not show your country.
The email address is not in the analytics and is never sent there. What PostHog holds is the Firebase user id described above. The dashboard joins that id to the email address Firebase Auth holds (section 07) at the moment an administrator asks, on our own server, and stores the result nowhere. Nothing about this changes what is collected, what is sent, or who it is sent to — it changes who here can read it back with a name on it, and that is the part worth telling you.
Administrators can also see a count of readers by country. As section 06 explains, PostHog works out an approximate country from your IP address at the moment an event arrives. The dashboard shows that as a list — how many people and how many story opens came from each country — and nothing finer: no city, no region, no IP address, and no country shown beside any individual reader. It is a count of a place, never a place attached to a person.
The off switch below covers this as well: no events, no rows on that dashboard.
Turning it off
Press the button. It takes effect immediately in this browser, is remembered, and stops both analytics scripts from loading at all on your next visit — not merely from reporting. Turning it back on takes effect when you next load a page.
Every analytics call on the site is wrapped, so a browser that refuses to load either script behaves identically to one that loads both.
06 · Payment, and the restore link
Subscriptions are taken through Stripe, on a checkout page that Stripe hosts. You leave the site to pay and come back when you are done. Your card number, your billing address and your name are typed into Stripe's page, not ours. They never touch our pages and we never see them. Stripe is responsible for what you enter there, under its own privacy policy.
Two things are added to that checkout address when you go to it. The first
is your email address as Stripe's prefilled_email, so the
payment page's email field is already filled in and you do not type it
twice; you can change it there. The second is your Firebase user
id as Stripe's client_reference_id — or, if you are
not signed in, the random local id from fb_acct_v1. That is the
entire link between a payment and an account: it comes back on Stripe's
webhook and is what lets your subscription be written under your record.
Nothing else about you goes with them.
When Stripe reports a successful payment, our webhook writes the subscription under your account. What it stores is in section 07.
The checkout's return address carries a success flag and a checkout session
id. That session id becomes your restore token, stored as
fb_pass_v1, and your restore link is that token on the end of a
factbox.app address. It moves access from the browser you paid in to another
phone. Signing in does the same thing and is the route we would rather you
used; the restore link remains for anyone who subscribed before accounts
existed.
The restore link is a bearer token. Nothing checks it against a server, so possession is the entire proof. Anyone you forward it to gets access, and so does anyone who reads it over your shoulder or finds it in a screenshot. Treat it like a key, not like a receipt.
It contains no personal information: it is a random-looking string plus a four-character check that tells a mistyped link apart from a real one.
07 · Your account, and what is held under it
An account is a document in Google Firestore, keyed by your Firebase user id. Four things write to it, and each writes somewhere different.
- Firebase Auth holds the account itself: your email address, whether it is verified, your display name and photo if you came in through Google, when it was created and when you last signed in. Firebase holds your password; we do not.
- Our Stripe webhook writes whether you are a subscriber, your Stripe customer id, and, for each subscription, its id, status, price, amount, currency, billing interval, whether it is set to cancel, when the period ends and when any trial ends. Nothing about a card is in it. A browser cannot write here — the rules forbid it — which is why it is worth trusting.
- The site itself copies part of
fb_acct_v1tocustomers/{your id}/profile/onboarding. The whole of what that document may contain is fixed in our database rules, and it is this and nothing else: the subjects you picked, your minutes a day, your streak, what draws you to history, which statements sounded familiar, the plan questions' three answers, how often you said you read, the plan you picked, your first name, your email address, the random local id from §02, and whether the questions were finished. Nothing is inferred, scored or bucketed; a question you skipped produces no field at all, and an answer you change is changed there too. - The site also writes your reading and your saved
stories to
customers/{your id}/profile/reading. That is section 08.
Four of the six questions at the start of signing up —
why you are here, what usually stops you, how much of a day goes to
scrolling, and who you want to be a year from now — are not in
that record and are not sent anywhere. They are stored in this
browser only, under fb_acct_v1, because the rules that fix
the shape of the document above do not name them. Choosing "let Factbox
decide" rather than a number of minutes also stores nothing there. What
does leave, for these four, is the measurement in section 05, which
records which answer was tapped without being tied to that record.
Story text for subscribers is served by a function of ours that verifies your sign-in token and reads the subscriber flag itself, rather than believing anything the browser says. Its ordinary server logs are Google Cloud's, under Google's terms.
08 · Your reading, and where it now goes
This section changed. An earlier version of this policy said your reading never left your browser. That was true of an earlier version of the site and it is no longer true, because reading now follows an account rather than a device. What follows is what the code does today.
Your reading progress is: which stories you opened, how far into each you got, how long ago you last touched each one, which you finished, and which you saved. Signed out, all of it is written to your own browser and to nothing else — we do not have it and no page has an endpoint to send it to.
Signed in, the same information is also written to
customers/{your id}/profile/reading in Firestore, under your
Firebase user id. It holds a story id against four numbers — the furthest
card, how many cards that story had, a whole-second timestamp, and a
finished flag — plus the list of stories you saved, and counts of both. It
holds nothing else; the shape is fixed in our database rules and capped in
size there. This is what carries your place in a story to a second phone,
and it is the reason signing in on a friend's phone does not show them your
reading: the browser's copy is tagged with the account it came from and is
thrown away when a different account signs in.
The trade has moved and is worth stating plainly. Your reading is now restorable — sign in anywhere and it comes back — and in exchange it is now something we hold, and so something that could be demanded of us or leak from us. Clearing your site data no longer deletes it; section 11 says how to have it deleted. The one thing that leaves in both cases is the measurement in section 05, which says a story was opened and for how long, not a list of what you have read.
What you write on the support page, and in the cancellation note
What you type into the two boxes on the support page
does leave your browser. Pressing Send posts what you wrote to a function of
ours, which writes one document into a support collection that
we read in the Firebase console.
The document holds six things and no others, and the function builds every
one of them itself rather than accepting them from the page: the time, the
reply address you typed if you typed one, which of the two boxes it came
from, your message, the page you sent it from, and your Firebase user id if
you were signed in. Your IP address is not stored on the message.
Messages are capped at 4,000 characters.
It is counted, though, and that changed on 4 September 2026. To stop one person flooding the box, the function keeps a running count per address. What it stores is not the address: it is a keyed hash of it, cut to 96 bits, under a salt that rotates daily — so yesterday’s counter cannot be matched to today’s, and neither can be turned back into an address. An IPv6 address is cut to its first half before that. The counter document holds numbers and nothing else — no message, no address, no account — and a Firestore expiry policy deletes it automatically. It is never joined to your message: the two live in separate collections and share no key.
If that post does not go through, the page offers you a link that opens the message in your own mail app instead, addressed to hello@factbox.app, with what you wrote already in it. Nothing is sent that way until you send it yourself. If you are signed in, the reply box is filled in with the address on your account; you can change it or empty it.
09 · Hosting, and every other company involved
The pages are static files hosted on GitHub Pages. Like every web server on earth, it receives the ordinary request information needed to send you a page: your IP address, the address you asked for, your browser's user agent, and the time. That handling is GitHub's, under its own privacy policy. We do not receive or keep those logs.
Loading a page also makes your browser reach these, each of which necessarily sees your IP address:
- Google Fonts —
fonts.googleapis.comandfonts.gstatic.com, on every page, signed in or not, for the typeface the site is set in. - Google at
www.gstatic.com, for the Firebase code that runs sign-in and analytics. - Cloudflare, for the analytics path described in section 05.
- PostHog, when the Cloudflare path does not answer and the site falls back to reaching it directly.
- Google Firebase — authentication and Firestore — once you sign in.
- Google Cloud Functions at
us-central1-factbox-7cb97.cloudfunctions.net, when you send a message from the support page and when a subscriber loads paid story text. - Stripe, when you go to a checkout page or the billing portal.
- Resend —
api.resend.com, a mail service, in two cases and only from our own server. It carries what you write in the help boxes to us, and it carries a short notice to us when somebody creates an account. That notice contains the new account’s email address, because the point of it is to tell us a real person has joined. Your browser never talks to Resend, and nothing else about your reading is sent there. Mail is delivered from a subdomain,send.factbox.app, kept separate from the address that receives our mail.
Every image is served from this domain. Artwork is downloaded from Wikimedia Commons once, in advance, and re-hosted here, so reading a story sends no request to Wikimedia and tells them nothing about you. Following a source or licence link from the credits page is an ordinary outbound link, and that site then sees you the way any site you visit does.
10 · Children
Factbox is not aimed at children under 13, and we do not knowingly collect anything from them or knowingly let them hold an account. If you believe a child has signed up, write to us and we will delete the account, anything sent from the support page, and everything else held under it.
11 · Your rights, and how to use them
Depending on where you live — the UK and EU under the GDPR, California under the CCPA, and many places besides — you have rights to see, correct, export or delete the personal information a company holds about you. There are two halves to that here, and they work differently.
- What is in your browser: it is under the keys listed in §02, and your browser's developer tools will show you every one of them in full. To delete them, clear this site's data. On an iPhone that is Settings → Safari → Advanced → Website Data; Chrome and Firefox have the equivalent. That removes every key in §02, the cookies in §03, and the analytics services' own storage, in one action.
- Note that this deletes your access too if you do not have an account, because access is one of those keys. Save your restore link first, or sign in, and it comes back.
- What is under your account: clearing your browser does not touch it. Your name, email address, onboarding answers and — since reading moved to the account — your reading progress and saved stories stay in Firestore, and your account stays in Firebase Auth, until they are deleted. There is no button on the site that does this yet. Write to hello@factbox.app and we will delete the account, both profile records — the answers and the reading — and the subscription records under it, and confirm that we have.
- If you have written to us: a message sent from the support page is a document in Firestore; an email is in our inbox. Ask for either to be deleted and we will delete it and confirm that we have.
- If you have paid: Stripe holds a billing record, and has to, for tax and accounting reasons. Deleting your account does not delete that. A request about it can come to us and we will pass it on, or you can go to Stripe directly.
- Analytics: the off switch in §05 stops future events. To have events already sent about you removed from PostHog or Google Analytics, write to us; we can ask both to delete the records tied to a user id, and we will tell you what came back.
We do not sell personal information and never have.
12 · Security
The account side is Google's: Firebase holds the passwords and the sign-in tokens, and the rules on our database are written closed, so a signed-in reader can read their own record and no one else's, and cannot write the flag that decides whether they are a subscriber. Paid story text is not readable from a browser at all; it comes from a function that checks the flag for itself.
Two limits are worth being plain about, because the alternative is you finding out later. The restore link is a bearer token, as §06 says. And for a reader without an account, the access flag is a value in their own browser rather than a check against a server, so it is something the site remembers rather than something the site enforces. Free story text is served as a public data file.
Email is not encrypted end to end. Please do not put anything sensitive in a message to us.
13 · Changes
If the site starts doing something this page does not describe, this page is updated before that ships, and the effective date at the top changes with it. We do not backdate a change or edit one in quietly.
14 · Contact
Questions about this policy, a request to delete your account, or a request to delete something you have sent us: hello@factbox.app. A person reads it.
Factbox · Privacy Policy · Effective 3 September 2026. Describes factbox.app as it stands on that date.