Privacy Policy
Last updated 26 October 2026
What this covers
HackOffer listens to a call you are on, transcribes it, and suggests answers. This page describes what that produces, where it goes, who else sees it, and how long it stays.
It covers the website, the web app and the desktop app, and it is written to be accurate about how the product is actually built rather than broad enough to cover anything we might do later. Where the architecture makes something impossible, it says so. Where it is a decision we could reverse, it says that instead.
Who we are
HackOffer is run by one person, not a company. That person is the data controller for everything described here, is resident in Poland, as a registered sole trader, and can be reached at support@hackoffer.com. There is no support queue in front of them.
Stripe processes every purchase. It holds your payment details on its own terms rather than under ours; the seller on your invoice is us.
Call audio
Call audio is transcribed by Deepgram, our speech-to-text provider, while the call is running. It travels from your device to our own transcription relay, which passes it straight on to Deepgram and keeps nothing: the audio is held in memory only for as long as it takes to forward it, and never written anywhere. We store no recording of any call.
Which relay, and which of Deepgram’s servers, depends on where your connection enters the network of our hosting provider, which is normally the point nearest to you. A connection entering in Europe or Africa is transcribed in the European Union: our relay in the Netherlands, Deepgram in Germany. One entering in South-East Asia, Hong Kong or Australia is transcribed through our relay in Singapore by Deepgram in India. Everywhere else, Japan and Korea included, it is transcribed in the United States. If the nearest relay cannot be reached, the call continues through the next nearest.
Every connection to Deepgram is opted out of its Model Improvement Program, so the audio of your calls — including the voices of the other people on them — is not used to train Deepgram’s models. Everything else Deepgram does with the audio it receives is governed by its own terms, as our processor.
On macOS the desktop app asks for Screen Recording permission the first time it runs. That is the only interface Apple exposes for tapping the system audio mixer, and it is what the app uses it for. No video is captured through it unless you press the screenshot shortcut described below.
When one microphone hears both you and the other side — a phone beside your laptop, or a laptop with the call on its speakers — the app tells the two voices apart from a voice sample: a few seconds of you reading a passage aloud, recorded once per browser. The sample is kept in that browser’s own storage and never leaves the device: it is not sent to us or to Deepgram. It is compared on the device by a speaker-recognition model that your browser downloads from our own server, and which receives nothing back. You can hear the sample and delete it from the settings page at any time, and clearing the browser’s site data deletes it too. So does signing out of that browser, or signing in to it with another account: the sample belongs to the person who recorded it, not to the machine.
What a session stores
We store the finalized transcript of each session, with each segment attributed to either you or the other side and placed in time.
Interim transcription — the text that flickers and rewrites itself while someone is still speaking — is rendered on your screen and thrown away. It is not stored.
We store each question that was answered and the answer that was generated for it, along with which model produced it, how long the first word took, roughly how much text went in and came out, and the rating if you left one. That last set is how we can tell whether question detection is getting better or worse.
We store the session itself: when it started, how long it ran, how it ended, and the model, language and answer style it was configured with. Those are what the plan limits are measured against and what your session list is built from.
The transcript switch, and what it does not do
The setup screen has a switch that stops the transcript being stored. It is enforced where the storing happens, not only in the interface: with it off, transcript segments are discarded as they arrive rather than written down.
Two things it does not do, said plainly because assuming otherwise would be reasonable. It does not stop the recent dialogue being sent with a question — that is how an answer gets its context, and it travels in the request rather than being read back out of storage. And it does not stop questions and answers being stored; those are the record of what the product told you, and they are kept and then deleted on the same schedule as everything else.
Screen captures
One shortcut sends a picture of your screen to the model, so it can answer about a task that was never spoken aloud — an algorithm on a shared editor, a diagram, a bug.
In the desktop app the capture is taken directly, without a further prompt: it is the display the overlay is on, with the overlay itself excluded, so the model sees roughly what someone sharing your screen would see. In a browser tab the browser opens its own picker every time and you choose what is shared; one frame is taken and the capture stops immediately.
The image goes to the model provider with your question and is not stored. We record only that a capture was attached, never the picture itself.
It captures whatever is on that display at that moment, including anything open on it that has nothing to do with the call. That is worth knowing before the shortcut becomes a reflex.
Mock interviews
A mock interview is a practice session with an AI interviewer in place of a person, and nobody else is on it. Your microphone is the only thing it listens to. The transcript is made the way any session’s is, through our relay and Deepgram, and the microphone is held silent while the interviewer speaks, so its voice is not transcribed as yours.
The interviewer is a language model. It writes its questions from the job description and the documents on the session, and after an answer it reads what you said to decide whether to follow up — both on the model the session is set to. Every line it says is written by our server and then turned into speech by OpenAI: the speech service is only ever given text our server wrote, never text sent from your device, and the audio is streamed to you and not kept. When the interview ends, the model that thinks longer writes the feedback, from the job description, the documents on the session, the questions and your answers.
We store what the interview needs in order to be scored and read back: the questions it planned, each line the interviewer said with the answer you gave to it, and the feedback — a score for the interview and for each answer, what worked, what was missing, and a stronger answer written for you. The lines and your answers are deleted thirty days after they were said, like a transcript, and the transcript switch does not stop them being stored, because without them there is nothing to score. The planned questions and the feedback stay with the session until you delete it.
Your documents and session setup
Documents you attach as context — a resume, a job description, free-form notes — are stored as plain text on your account and sent to the model provider as part of the prompt when a question is answered.
They are used for one other thing. Names and uncommon terms are picked out of them — and out of the job description and the company name on the session — and sent to Deepgram as a short vocabulary list each time a transcription connection opens, so that those words are spelled the way you spell them. Email addresses and links are left out of that list. Beyond the prompt and that list, documents are used for nothing: not for training, not for analytics, not for anything shared between accounts.
If you upload a PDF instead of typing one out, we read the text out of it and keep the original file so you can open and download it later. Only the text is ever sent to the model — the file itself is never handed to a model provider or to anyone else. It is stored in a private bucket on the same host that runs the app, and it is reachable only through a short-lived link this app issues after checking that the account asking for it owns the document.
The same is true of what you type into the setup screen: the company, the role, and any instructions you give for how answers should sound. Those are stored on the session, and unlike the transcript they stay there until you delete the session.
If you paste a link — a job posting on the setup screen, or any page you save as a document — our server fetches it and asks the model to pull the relevant text out of it. The request comes from our server rather than from your device, so the site you linked to sees us and not you; what comes back is stored like anything you had typed yourself, and the page itself is not kept.
Delete a document and it stops being sent immediately, and its uploaded file is deleted with it. Deleting it does not rewrite answers already generated from it, which remain in the sessions they belong to until those sessions or their retention window are gone.
Account and billing data
We store less about you than you would expect. Your account row holds the identifier Clerk, our sign-in provider, gave you; the defaults you save for new sessions — model, transcript language, answer style and profile, instructions, whether questions are answered on their own, whether the transcript is kept, and which resume to attach; your Stripe customer identifier once you have bought something; and how many test calls you started today. Your name, email address, password and sign-in methods live with Clerk, which is where you edit them and where the app reads them to draw them on screen. We keep no copy of any of it.
Payments are handled by Stripe. It holds your payment details and billing address and issues your invoice on our behalf; we never see a card number. What we store is your Stripe customer and subscription identifier, the plan, its status, the current period dates and any scheduled change — the facts the app needs in order to decide what your account may do.
If you open the invite dialog, your account also gets an invite code, which is what your link carries, and a mark if the operator turns that link off. For every account that joins through a link, we store which account invited which, when the friend joined, whether and when the friend’s first payment arrived — with its Stripe invoice and charge identifiers and Stripe’s hash of the card it was paid with, never the card — and the time it granted or took back, with the reason when time was refused or taken back. An inviter sees only numbers from those records — how many friends joined, how many paid and how much time that earned — and never which accounts they are; we never tell a friend who invited them either. The code travels only in the link: following one writes nothing to your device.
We keep a per-month total of seconds used, and within it the part used while the account was on the free tier. Your free time is checked against that part, and a fair-use budget on a paid plan against the month’s whole total.
Devices
If you install the desktop app we store which platform it runs on, its version and when it last checked in — one row per platform. It is what tells you which machines are set up, and where a support conversation starts.
The installed app checks GitHub for its own updates, which means GitHub sees your device’s network address when it does. Downloads from the website are streamed through our own server instead, so that visit is not passed on.
For each day you open the app while signed in, we also store where you opened it — the desktop app, a browser on a computer, or a phone or tablet — how many times, and when first and last that day. A time counts once per page load, and again when you come back to it after half an hour away. It is one row per day and place, in our own database, and it says nothing about what you did while the app was open. It is how we learn whether people come back to the product, which is a number we cannot get any other way.
Support requests
When you write to us through the Contact support form, the message goes to a support inbox we run ourselves, on the same hosting provider as the rest of the app. The form takes no screenshot and attaches no file.
With the message we receive what we need to answer it and to find the problem: whether you marked it as a bug, a question or an idea; the text you wrote; the email address to reply to — your account’s, if you are signed in, or the one you type in if you are not; if you are signed in, your account identifier and the name on your account; the address of the page you wrote from, without its query string or fragment; your interface language; your browser’s user agent; the version of the app that was running; whether you came from the desktop app, and which version of it; and, if you are signed in, your plan, the status of your subscription and how much session time you have left. Never a transcript, an answer or a document.
We are told of a new message in a private Telegram chat, with its kind, whether it came from an account or a guest and up to its first 700 characters — never your email address or your name. We reply from our own email to the address you gave. Your messages are kept in the inbox, apart from your account, so deleting your account does not delete them: write to us and we will.
Cookies, local storage and technical data
The public website is counted with Plausible, which measures pages without cookies, without local storage and without anything that follows you to another site. It has no identifier to write on your device.
Besides page views, Plausible counts four moments and nothing else: an installer downloaded, an account created, a checkout opened and a payment completed. Each arrives as a bare event name — with the installer’s platform in the first case and whether the account was created from the website or the desktop app in the second — and never with your account, your email address or anything that identifies you. It tells us how many people who arrived from a given link went on to sign up, never which people.
Beyond those four, Plausible measures nothing inside the product — not the screens of the app you sign in to, not the overlay, not the desktop app, which sends no analytics of any kind. The only record the product keeps of its own use is the daily visit described under Devices, and it stays in our database rather than going to anyone else. There is no session recorder and no heat map, and none of what Plausible does collect can be tied back to you: it is counts, referrers, campaign names and countries in aggregate.
There is no advertising tag on this site: no Google tag, no Meta or TikTok pixel, nothing that tells an advertising network which pages you open. We do buy ads on Google, on Instagram and Facebook through Meta, and on TikTok, and what those three networks learn from us about them is described in the next two paragraphs, which are the whole of it.
Whether we keep that click depends on where you are. Where the GDPR or a law built on it applies — the European Economic Area, the United Kingdom, Switzerland, Andorra, Monaco, San Marino, the Vatican and France’s overseas territories — we ask first: a question at the bottom of the page, until you answer it. Closing it is not an answer, and nothing is kept. Everywhere else we keep the click without asking, and you can say no at any time. We tell the two apart by the country of your network address, looked up on our own server in a database kept there (IP Geolocation by DB-IP, db-ip.com), so the address is sent to nobody for this; neither the address nor the country is stored. When the database cannot place the address, or our server does not answer, we go by the time zone your browser reports instead, and a browser whose time zone does not say where it is gets asked. Either way your answer is kept in this browser’s storage, and you can give or change it at any time from the Ad click reporting link in the footer or the switch of the same name in the app’s settings. A browser that sends the Global Privacy Control signal is never asked, and is treated as having said no.
Unless you said no — and, where we ask, only if you said yes — we tell the network whose ad you clicked what that ad led to, and we do that from our own server rather than from your browser. The address of a page reached from one of our ads carries that network’s identifier for the click: Google’s, Meta’s or TikTok’s. Facebook and Instagram add theirs to every link that leaves them, so we take it only from an address that also marks it as one of our paid ads. We keep that identifier, the latest one from each network: in your browser’s storage until you sign in, and then on your account. We send the network the identifier with one of three things: that an account was created, and when; that a checkout was opened, and when, once per account; or that a payment was made, with the amount paid less tax, its currency, the time and the Stripe invoice’s identifier. The first two carry a number of our own that lets the network count them once and says nothing about who you are. So that neither is ever reported twice, your account keeps a note of the networks each was reported to, without the identifier, until the account is deleted. A report to Meta also carries the time we first saw the click and the line your browser describes itself with, its user agent — the browser’s name and version, those of your operating system and, on some phones, the model — because Meta refuses a report without one; for a Meta click we keep that user agent beside the identifier, read from your browser when it hands the click to your account. Google and TikTok are not sent it. Each report to Google says that it is not to be used for showing you ads and, where we asked, that you said yes. Where we did not ask, the report claims no consent from you, and a standing setting in our Google Ads account tells Google it may count such reports anyway: there they rest on our legitimate interest, as set out under “Why we are allowed to hold it”, not on consent. Meta and TikTok take no such statement: what they receive, their own terms let them use for measuring and delivering ads as well, and their reports rest on the same grounds. That is the whole of it: never your name, your email address, your account identifier or anything you created in the product. The identifier is deleted ninety days after the click, when no network would credit anything to it any more, and at once if you say no or delete your account. Saying no also cancels any report not yet sent; one already sent stays with the network, which offers no way to take it back.
The cookies we set ourselves are the ones the app cannot work without: your Clerk session, your chosen interface language, and whether the sidebar is open. Pressing play on a tutorial video loads YouTube’s player, which sets cookies of its own.
Your device also keeps a few things in its own browser storage. Most are settings: transcript language, saved answer presets, which microphone to use and whether a call takes one microphone or two, the overlay’s appearance, size and layout and whether it hides from screen capture, the text size of a call in the browser, whether a list is shown as a table or as cards, the tips you have dismissed and the tutorial videos you have started, the choices the setup form remembers, and your answer to the ad-click question. Two describe you: a session you have set up but not started, and the voice sample described above — and beside them the identifier of the account they belong to, so that another account signing in on the same browser finds them gone. The rest are short-lived: a one-time random value that proves a desktop sign-in link was started on this device, two markers that stop a page from reloading itself in a loop after an error, and, unless you said no, the ad click identifiers described above until the account takes them over, with a marker that remembers it did so and one that asks the account to forget it after you change your answer. None of it is sent to us, with three exceptions: a session you start is sent with the setup it was started with, the one-time value travels once, in the link that signs the desktop app in, and the ad click identifiers are handed to your account once you are signed in. The defaults for new sessions that you save in Settings are different: they are stored on your account, as described above, so the website and the desktop app see the same ones.
Our server sees your network address on every request and uses it in memory to enforce rate limits and, until you answer the ad-click question, to look up the country it is in, as described above. It is not written to the database. Railway, which hosts the app, keeps ordinary infrastructure logs of requests.
Who else processes your data
Clerk — accounts, sign-in, and the profile shown in the app.
Deepgram — speech-to-text. It receives the call audio, through our relay, in order to transcribe it, and the vocabulary list described above, on its servers in the European Union, India or the United States as described under Call audio.
Google — answer generation on the default model, and reading the pages you import by link. Gemini receives the recent dialogue, the detected question, the documents attached to that session, your session instructions, and the screen capture if you sent one. When a mock interview runs on it, it also receives the job description and those documents, to plan the questions, and each answer you give, to decide on a follow-up.
OpenAI — answer generation on the GPT models: the model that thinks longer, which answers coding sessions, draws the design whiteboard and answers the chips that ask for more; GPT-5.6 Luna when you pick it; and whichever of the two providers stands in when the other fails mid-call. It receives the same things Gemini would for that answer. For a mock interview it also gives the interviewer its voice, from the text of each line and nothing else, and writes the feedback afterwards, from the job description, the documents on the session, the questions and your answers; when the interview runs on a GPT model, it plans the questions and decides on follow-ups from the same things Gemini would.
OpenRouter — a stand-in for the two above, asked only when neither Google nor OpenAI answers a request. It then receives the same things the model it stands in for would have received for that request, and passes them to one model on its list: the same Gemini or GPT model, run by Google Cloud or Microsoft Azure, or else a Claude model by Anthropic, run by Google Cloud or Amazon Web Services. Every such request is restricted to endpoints that keep no copy of the prompt or the answer once it is given (zero data retention) and that do not collect data for training.
Stripe — payment processing, invoicing and subscription management.
Railway — hosting for the website, the API, the transcription relays and our support inbox, the databases everything above is stored in, their backups, and storage for the files you upload.
GitHub — distribution of the desktop app and its updates.
Plausible — aggregate visitor counts for the public website and the four anonymous events described above, without cookies, hosted in the European Union.
Google Ads — from our server, unless you said no: Google’s click identifier with an account created, a checkout opened or a payment made after one of our Google ads, and for a payment its amount, currency and Stripe invoice identifier, as described above.
Meta — the same for one of our ads on Instagram or Facebook, with the time of the click and your browser’s user agent, as described above.
TikTok — the same for one of our ads on TikTok, as described above.
Sentry — error reports from our server, the signed-in app and the desktop app: what failed and where, tagged with your account identifier, and never the transcript, a prompt or a document. From the desktop app a report can include a crash dump of the app’s main process, which does not hold the call.
Telegram — the notice we get of a new support message: its kind and up to its first 700 characters, without your email address or your name, as described under Support requests.
YouTube — the tutorial videos in the app. Nothing is loaded from YouTube until you press play on one; from that click, YouTube’s own player, cookies and terms apply.
That is the complete list. We do not sell your data. The only thing shared for advertising is the reports to Google Ads, Meta and TikTok described above, and nothing you create in the product — no transcript, answer, document or account detail — is ever part of it. No one outside this list receives your data unless the law requires us to hand it over.
Training
We do not train models on your content. We do not sell it, and no advertising system receives it: Google, Meta and TikTok learn that an account, a checkout or a payment followed one of their clicks, never what was said, asked or answered in the product. Call audio is opted out of Deepgram’s model training on every connection, as described above.
What each provider above may do with what it receives is governed by that provider’s own terms. Those differ between them and they change, so this page does not restate them: a summary of somebody else’s policy is exactly the kind of promise that goes quietly out of date while still sounding reassuring. The section above names each of them so you can read the ones you care about, and if the answer for a particular provider matters to your decision, ask us and we will tell you what our contract with them currently says.
Where it is processed
The operator is in Poland, inside the EEA. Most of the providers above are based outside the EEA, chiefly in the United States. So if you are in the EEA your data leaves the region once, in reaching them; if you are anywhere else it is handled outside your own country from the start. Call audio is the exception that can stay inside the EU: a call whose connection enters our hosting provider’s network in Europe is transcribed there, as described under Call audio.
Each of those providers offers standard contractual clauses for that transfer. Ask us and we will tell you which of them we have in place at the time you ask, rather than leaving you to assume from this page that all of them are.
Why we are allowed to hold it
For readers under the GDPR and the UK GDPR, the grounds are these.
Running the service you asked for — your account, your sessions, your transcripts, your answers, your documents — is performance of our contract with you.
Rate limiting, abuse prevention, error reports, the daily visit record, and the quality data attached to each suggestion rest on our legitimate interest in keeping the product working and affordable for everyone on it. Keeping an ad click and reporting what it led to rest, in the places listed under “Cookies, local storage and technical data”, on your consent, given in answer to the question described above; everywhere else, on our legitimate interest in knowing which of our ads work, which you can object to by saying no. Either way the answer can be changed at any time from the Ad click reporting link in the footer or the switch in the app’s settings.
An invite record is performance of our contract with the account that shared the link, since the invite terms are part of it. For the friend who joined through it, and for the checks that keep people from inviting themselves, it rests on our legitimate interest in running that programme honestly.
Invoices and tax records are a legal obligation; Stripe holds them for us, and we keep them for as long as the law requires.
Where a permission is genuinely a choice — the microphone, system audio, a screen capture — it is consent, given at the operating system prompt or in the browser, and withdrawable in your system settings at any time.
How long it is kept
Transcripts, questions and answers are deleted automatically thirty days after they are created. Nobody re-reads an interview from six months ago, and text nobody reads is only exposure. A scheduled job does this; you do not have to ask for it.
The session outlives its words. Its title, the company, the role, the duration and the counts stay until you delete the session, so your history and your usage remain checkable after the transcript is gone. A mock interview’s planned questions and its feedback stay with it the same way; the lines of the interview and your answers go after thirty days with the rest.
Documents stay until you delete them. The device rows stay for as long as the account does; there is one per platform, and installing again overwrites rather than adds. The daily visit rows stay for as long as the account does too.
Deleting your account removes your sessions, transcripts, answers, documents, uploaded files, devices, daily visit record, usage counters, ad click records, invite code and subscription record together, and cancels any subscription immediately so nothing keeps billing an account that no longer exists. The invoices and payment records we are required to keep for tax and accounting survive it, in Stripe, for as long as the law requires.
The invite records you are part of stay, with your account detached from them: the time an invite granted has to stay correct for the account still holding it, and a refund or chargeback that arrives later still has to find the payment it concerns. What remains on such a record is the code it came through, its dates, the Stripe identifiers and card hash described above, and the time it granted or took back; the record of anything the operator did to it, or to your invite link, stays as well. That leaves it pseudonymous rather than anonymous, because those Stripe identifiers still lead to the payment in Stripe.
Your rights
You can ask for a copy of what we hold, have it corrected, have it deleted, have it handed to you in a portable form, object to a use of it, or ask us to restrict one while a question is settled. Write to us and you will have an answer within thirty days.
Most of it is faster done yourself: sessions and documents are deletable in the app, your profile is editable in the account dialog, and closing your account there removes the rest.
If you are in the EEA or the United Kingdom and think we have handled any of this badly, you can complain to your national data protection authority. We would rather you wrote to us first.
Keeping it safe
Everything travels over TLS, and every database query that serves you is scoped to your account’s identifier. The code that reads across accounts is the operator’s own, and all of it is listed here. An admin screen, open only to an account marked as the operator’s and checked on every request, which shows accounts, plans, usage, answer statistics, how many days each account opened the app and when it last did, and the invite records between accounts, but never a transcript, an answer or a document; from it the operator can refuse or take back time an invite earned, on one of the grounds the invite terms name, and turn an invite link off or back on; each such action is recorded with who took it and when, and a refusal or a revocation also with its ground. The scheduled jobs: one deletes expired transcripts, questions and answers; one closes abandoned sessions; one deletes uploaded files that no document points to any more; one compares every subscription in Stripe with our copy of it and cancels a subscription whose account no longer exists; one checks the past week’s payments, refunds and disputes in Stripe against the invite records, so that a lost webhook neither withholds time an invite earned nor leaves time in place that should have been taken back; one sends Google, Meta and TikTok the signups, checkouts and payments waiting to be reported against an ad click, as described above, and deletes each click, and every report made against it, ninety days after the click; and one checks that each provider above still answers, which counts the accounts at Clerk without reading any of them. And the two webhooks, which look up the single account that an event from Stripe or from Clerk names — and, for a payment, a refund or a dispute, the account that invited that one, if any.
Invites read across accounts in two more places. When a new account arrives through an invite link, the code is looked up to find the account that shared it. And before a friend’s payment earns anything, the webhook or that job checks the two accounts against each other: at Clerk, whether they share an email address and whether the inviter is the operator; through Stripe, whether the friend paid with one of the inviter’s cards or with a card an earlier friend of theirs paid with. The inviter’s cards are compared by Stripe’s hash and not kept; what is stored is the outcome, beside the friend’s card hash described above.
The credential handed to your browser for transcription is a ticket for our own relay that expires in minutes and names one session. The Deepgram key is held by the relay, and by our server only to check that it still works and to read the balance left on it; the model provider keys stay on our server. None of them ever reaches your device.
No system is beyond reach. If something happens that puts your data at risk, we will tell you and the relevant authority within the time the law allows, and we will say what actually happened.
Other people on the call
The other participants on your call are not our users and have agreed to nothing with us. You are the one who decides to transcribe a conversation they are part of, and whether that is lawful and appropriate where you are is yours to establish before a session starts, not ours to establish afterwards.
Several jurisdictions require every party to consent to a recording or a transcript, and some employers, platforms and examiners forbid assistance regardless of what the law says. Check both.
If someone else on your call writes to us about what was said, we will need you to identify the session before we can act: it sits on your account, and we have no way of finding it otherwise. You can delete it yourself at any time.
Age
The service is not for anyone under 18, and we do not knowingly hold data about anyone under that age. If you believe a minor has an account here, write to us and it will be removed.
Changes and contact
If this page changes, the date at the top changes with it. A change that materially affects what we do with data we already hold will be announced in the app before it takes effect, rather than applied quietly.
For access, correction, export, deletion, or any question about a sentence on this page, write to support@hackoffer.com.