- Legal
Cookie Policy
Every cookie the portal sets, the browser storage beside it, and the two things the consent banner actually asks your permission for.
Version 1.0Last updated
This page lists every cookie the HyperJobs portal sets, the browser storage it uses alongside them, and the two things we ask your permission for. Most of what is here is strictly necessary to run the site. The parts that are not, we ask about first.
The short version#
There is product analytics on this site: PostHog, which we use to measure how the docs and the signup flow are actually working. It goes in the first line because it is the thing you would most want to know, and burying it four headings down would be the sort of decision this page exists not to make.
There are no advertising cookies and no cross-site tracking here. There is no ad network, no ad pixel, and no third-party tracker of any kind. Nothing is sold, and nothing is shared with anyone for their own purposes.
Every cookie in the table below except PostHog's is strictly necessary — under the ePrivacy Directive, Article 5(3), as implemented in Italy, those are exempt from consent, because there is nothing to decide. Switching off the cookie that signs you in just means not being signed in. PostHog's cookie is the opposite: nothing breaks without it, so we ask, and it is not set unless you say yes.
The banner asks about the two things that genuinely are your call:
- Product analytics. With your consent, PostHog stores an id on this device, links what you read before signing up to your account afterwards, and records session replays. Without your consent it still counts pages — but stores nothing on your device, builds no profile, and never receives your IP. Both modes are described below, including what the second one still does.
- Abuse prevention — the device fingerprint taken at signup and sign-in to catch bulk account farming. Not a cookie, but Article 5(3) covers reading information from your device as well as storing it, and a canvas and GPU probe is squarely that.
Decline either and the thing it gates never happens on your device: no ph_*
cookie is written, no replay is recorded, no fingerprint is computed — the code
checks before it runs, not after. Nothing about your account changes and no
feature is withheld. "Reject" works exactly as well as "accept", and you can
change your mind from Cookie settings in the footer at any time.
Two things "reject" does not stop, stated here rather than left for you to find in a network tab. Anonymous page counts continue, because they touch nothing on your device — see the analytics section below. And our own backend keeps recording what your account does: that you signed up, created a key, or bought a plan. That is the database we run the business on, it never involves your device, and declining a cookie cannot un-sell a subscription. The Privacy Policy gives the legal basis for both.
The banner appears in the EU/EEA, the UK, and Switzerland, where opting in is required. Elsewhere the same controls live in the footer instead of interrupting you. If we cannot tell where you are, you get the banner — we would rather show it unnecessarily than skip it wrongly.
The API at api.hyperjobs.io sets no cookies at all. It authenticates with API
keys. If you only use the API and never open the portal, none of this touches you.
Cookies we set#
| Cookie | Purpose | Lifetime | Flags | Category |
|---|---|---|---|---|
__session | The Firebase session cookie. This is what keeps you signed in. Without it there is no authenticated portal. | 5 days | httpOnly, secure, sameSite=lax | Strictly necessary |
__csrf | A double-submit CSRF token. Page JavaScript reads it and echoes it back as a header, which proves a state-changing request came from our page and not from someone else's. | 5 days | secure, sameSite=strict, readable by JS by design | Strictly necessary |
__session_hint | A flag saying "someone is signed in", so the header can render the right button on first paint instead of flashing a placeholder. A UI hint only — never trusted for any authentication decision, server-side or otherwise. | 5 days | secure, sameSite=lax | Strictly necessary |
portal_country | Your country, taken from Cloudflare's cf-ipcountry edge header. Set only on authenticated and auth-flow routes, so public pages stay cacheable. | 24 hours | secure, sameSite=lax, not httpOnly | Strictly necessary / functional |
sidebar_state | Whether you collapsed the dashboard sidebar, so it stays how you left it. | 7 days | sameSite default, readable by JS | Functional |
ph_<project-key>_posthog | PostHog's own cookie: the random id that lets us tell this browser's visits apart from another's, plus the current session. Set only if you consent to product analytics. Decline and PostHog holds everything in memory instead — this cookie is never written. | 365 days (PostHog's default; we do not override it) | secure, sameSite=lax, readable by JS | Analytics — consent |
All of them are first-party: they are set on our own domain, and none is readable
by another site. __session is httpOnly, so page JavaScript cannot read it
even on our own site; the rest are readable by JavaScript because the code that
needs them runs in your browser.
One honest qualification on ph_<project-key>_posthog. The cookie itself is
first-party and nobody else can read it — but the id inside it is what identifies
your events to PostHog, our analytics processor, so unlike every other row in
this table its contents do leave our systems. PostHog is bound by a data
processing agreement and processes it only for us; it is listed in
Subprocessors. No other cookie here is shared with
anyone.
The secure flag is set in production. In local development it is not, because
localhost is not served over HTTPS.
Browser storage we use#
Not cookies — no browser attaches this to a request on its own — but it is stored on your device, so it belongs on this page. Two of the rows below are read by our own code and sent somewhere deliberately; both say so.
| Key | Storage | Purpose |
|---|---|---|
hyperjobs-cookie-consent | localStorage | Your answer to the banner, and when you gave it. Kept on your device rather than in our database — it is a record about a browser, and this is the browser. |
hyperjobs-ui-theme | localStorage | Whether you chose light, dark, or system theme. Read before first paint so the page does not flash white. |
hyperjobs-docs:recent / hyperjobs-help:recent | localStorage | Your recent searches in the docs and help search boxes, shown when you reopen them. Stays in your browser. |
portal_session_id | localStorage | An id for this browser's device session, sent as a header when you sign in so the security page in your dashboard can show you this device in your session list. |
ph_<project-key>_posthog | localStorage | PostHog's copy of the same id and session state as its cookie above, and what it needs to hold a session replay together. Its contents go to PostHog with each event. Written only if you consent to product analytics — decline and PostHog runs with persistence: 'memory', which means its id lives in the tab and disappears when you close it, and nothing is written here at all. |
Clearing your browser storage clears all of it. You lose your theme choice and your recent searches, we will ask about analytics and the fingerprint again, and PostHog stops recognising this browser; nothing breaks.
Why each of these is strictly necessary#
"Strictly necessary" means necessary to deliver a service you actually asked for
— not necessary for our business. It covers the cookies in the first table except
ph_<project-key>_posthog, which is not necessary for anything and is therefore
never set unless you say yes.
__sessionis the sign-in. You asked to sign in.__csrfprotects your account from a third-party site making requests as you. Security of the service you asked for.__session_hintexists so the portal renders correctly and fast without extra database reads. It carries no identifier of you beyond "signed in".portal_countryis a country code from an edge header, used for country-dependent rendering. It is not a location trace: it is two letters, it lasts a day, and we already saw your IP when you connected.sidebar_stateremembers a preference you expressed by clicking a button. It is a functional cookie in the narrow sense — it holds a UI setting and nothing else. It contains no identifier at all, so it cannot be used to recognise you.
None of these follows you to another site, and none of them can. There is no third-party cookie, no advertising pixel, and no fingerprinting for advertising anywhere on this site.
What about product analytics?#
This is the half of the banner most worth reading, because it is the half that keeps doing something after you say no.
We use PostHog to answer questions our database cannot: how many people read the quickstart, which page they left from, what they searched the docs for and did not find. Our own Postgres knows what accounts do. It knows nothing about the reader who never became an account, and that reader is the one we most need to understand.
It is proxied through our own origin. Your browser talks to
hyperjobs.io/ingest, not to posthog.com. That is a plain reverse proxy, and
it is there because a large share of a developer audience runs an ad-blocker
that blacklists analytics domains — unproxied, the numbers would be skewed
towards the people least like our users. Being straight about what it means: the
proxy changes who your browser connects to, not who receives the data.
PostHog still processes it, on their EU cloud in Germany. They are a
subprocessor, and they are listed as one.
With your consent#
PostHog runs in its full mode: the ph_* cookie and localStorage above, a
person profile, identify() linking your anonymous browsing to your account once
you sign in, and session replay.
Without your consent#
PostHog still runs, and we would rather tell you that than have you find it. It runs in a different mode, and the difference is the whole argument:
persistence: 'memory'— nothing is written to your device. No cookie, no localStorage. The id it uses exists in the tab and dies with it.- It never calls
identify()— nothing is ever linked to your account. person_profiles: 'identified_only'— no profile is created for you at all. There is no record to look you up in.ip: false— PostHog does not receive your IP address (this is true in both modes).- No session replay.
That is anonymous, aggregate page counting. Our basis for it is legitimate interests (Art. 6(1)(f) GDPR) rather than consent, and the reason we do not ask is that there is nothing to ask about under Article 5(3) of the ePrivacy Directive: that Article governs storing information on your device or reading information from it, and this mode does neither. It touches your device exactly as much as our web server's access log does, which is not at all.
Session replay records your screen#
A developer will ask, so: yes, in the consented mode, replay reconstructs what happened in your browser window. Two things constrain it, and both are code, not policy:
- Every form input is masked. Replay never captures what you type into a
field —
maskAllInputs, on. - The "copy your key" dialog is blocked entirely. The one moment a full API key is ever visible in the portal, replay is not looking: that dialog renders the key in a code block, which input-masking would not have covered, so the subtree is excluded from capture outright. This is deliberate and load-bearing — without it, every key we issue would be recorded in plaintext at the exact moment it is revealed.
We record what you search the docs for#
The docs and help search boxes send the text you typed to PostHog, as a property
on a docs_search event — and a docs_search_empty event when your search
returned nothing. In both modes: the anonymous mode still counts these, without
storing anything on your device and without a profile to attach them to.
We are telling you rather than burying it, and the justification is honest: this
is a search box on public documentation, not a form. What people type into it is
salary_annual_max. The searches that return nothing are the single most
useful thing this product collects — every one is a developer who wanted
something our documentation did not have, or had under a name they did not guess.
That is a to-do list written by users. If you would rather not contribute to it,
do not use the search box; the pages are all navigable without it.
What about the device fingerprint?#
The other thing the banner asks about, and the one people assume the worst about. It deserves a straight answer.
At signup and sign-in we compute a device fingerprint for abuse prevention — stopping one person from farming free accounts. It uses the open-source FingerprintJS library, which runs entirely in your browser and sends nothing to FingerprintJS. It stores nothing on your device; it reads characteristics your browser already exposes (screen, timezone, fonts, GPU) and hands the result to us.
Three things worth stating plainly:
- It is never used for advertising, analytics, or cross-site tracking. It is read when a human investigates suspected abuse. It blocks nothing automatically, and no decision about your account is ever made by a machine on the strength of it.
- We ask, rather than claim an exemption. There is a respectable argument that fraud prevention is strictly necessary to provide a metered service, and we could have relied on it. We would rather ask: the exemption is contested, and asking costs you one click and costs us a signal we can live without.
- It runs only when you sign up or sign in — not on the public site, not in the docs, not on this page, and not while you browse. The library is not even loaded until you open the sign-in form.
Decline it and nothing else changes. The Privacy Policy explains what we store, for how long, and how to object.
Third parties involved in storage on your device#
We embed no advertising trackers. These providers are the ones with a hand in what lands on your device, either because you deliberately used them or because you consented to analytics:
| Provider | When | What for |
|---|---|---|
| PostHog | Any page, if you consented to product analytics | The ph_<project-key>_posthog cookie and localStorage above. Set by our own page on our own domain, not by a PostHog script from a PostHog domain — but the id in it goes to PostHog, who process the events for us on their EU cloud |
| Google (Firebase Authentication, reCAPTCHA Enterprise) | Signing in, especially with Google; bot protection on auth | The sign-in flow, and telling a human from a script |
| Stripe | Opening checkout or the billing portal | Payment processing and fraud prevention |
| Cloudflare | Any request | Edge security and delivery |
Apart from PostHog's, those cookies are set by those providers under their own policies, in the course of doing the thing you asked for. Subprocessors lists who they are and what they receive.
Managing cookies#
Cookie settings in the footer reopens the banner on any page, so you can
change or withdraw your answer whenever you like. Withdrawing takes effect
immediately, not at your next visit: session replay stops, the person link is
reset, PostHog's ph_* keys are cleared from this browser, and it drops back to
the memory-only mode described above. Anything already computed is dropped there
and then.
Your answer is stored in your own browser (hyperjobs-cookie-consent in
localStorage), not in our database. Clearing your browser storage clears it, and
we will ask again.
You can also block or delete cookies in your browser settings. If you block ours,
sign-in stops working — __session is the sign-in, so removing it logs you
out. That is the trade, and it is your call to make. Blocking sidebar_state,
blocking the ph_* cookie, or clearing localStorage costs you nothing but a
preference.
"Do Not Track" and Global Privacy Control. We do not currently act on either
signal, and this page used to say we honoured them trivially because we were not
doing the thing they turn off. That is no longer true, so here is the accurate
version: PostHog's SDK can be configured to respect DNT and we have not
switched it on. The banner is the control that actually works, and it works
completely — choose Essential only and nothing is stored on your device.
Neither signal has any bearing on selling or sharing your data, because we do
neither. In the EU/EEA, the UK, and Switzerland nothing is stored until you opt
in anyway.
Changes#
If we add a cookie, this page changes first, and it will say what the cookie does and which category it is in. One that needs consent goes in the banner as its own choice, off by default, and we ask before setting it rather than after.
That is the rule analytics itself went through. It is a new category rather than a wider reading of an old one, so any stored answer is invalidated and the question asked again from a clean slate: an "accept" given to a banner that never mentioned PostHog is not consent to PostHog. If you are asked something you thought you had already answered, that is why, and it is deliberate.
Questions: [email protected].