Menu
For laboratory research use only; not for human or veterinary use.
Legal · version 0.1
What this site collects, why, who sees it, where it is held, how long it is kept, and what you can ask us to do about it.
Today
These three tables describe how the site currently works, read directly from the code that runs it rather than written by hand. They are the factual half of this notice: what leaves your browser, what is kept on your device, and what your browser contacts. The numbered sections below are the other half — what is done with information, why, and for how long — and are drafted by counsel, not derived from code.
| Field | Sent by you? | What it is |
|---|---|---|
| analytics | Yes | Whether the optional analytics category was accepted. A boolean the visitor chose. |
| marketing | Yes | Whether the optional marketing category was accepted. A boolean the visitor chose. |
| anonId | Yes | The random per-browser id above. Sent so repeated answers collapse to one record. |
| ipHash | No — server-derived | A truncated SHA-256 of the connecting IP address, computed on the server. The raw address is never stored. |
| ua | No — server-derived | The User-Agent string as the browser presented it in the request headers, truncated. Read off the request by the server, not sent as data. |
| recordedAt | No — server-derived | The server clock at the moment the choice was recorded. The browser clock is never trusted for this. |
| type | Yes | Which kind of enquiry this is (general, product, COA, complaint, ambassador application). |
| name | Yes | The name typed into the form. |
| Yes | The email address typed into the form — used only to reply. | |
| subject | Yes | The subject line typed or pre-filled. |
| message | Yes | The message body typed into the form. |
| website | Yes | A honeypot field, invisible to a person. Empty on every genuine submission. |
| meta | Yes | Answers to any extra question fields the specific form variant adds (e.g. an ambassador application). |
| consent | Yes | The record of which wording of the research-use and age notice was on screen when you confirmed it — which notice, its version, and a fingerprint of its exact text. Absent if you never confirmed the notice on this device. |
| caller IP (hashed) | No — server-derived | The browser does not send this as a form field — the server reads the request's own IP address, salts and SHA-256-hashes it, and stores that hash under `rate_limits` to count submissions per origin for one hour. The raw address is never stored; the hash cannot be reversed back to it. This exists purely to slow down automated abuse of the form. |
| email + password (sign in) | Yes | Sent to Firebase Authentication to sign in, not to this site's servers. The password is never stored here and is not readable by anyone running this site. |
| email + password + name (register) | Yes | Sent to Firebase Authentication to create the account. The name becomes the display name on the account and is what appears at the top of the account pages. |
| age confirmation (register) | No — server-derived | The tick is a CONDITION of the form: nothing is submitted until it is ticked, and the tick itself is not sent or stored anywhere. Age is checked again at checkout. |
| research-use acknowledgement (register) | No — server-derived | Same as the age tick: a condition of the form, not a stored field. |
| marketing opt-in (register + settings) | Yes | A true/false sent to the email-preferences function. When it goes from off to on, the SERVER stamps the moment and the exact wording that was on the screen against the account — from its own copy of the wording, not from anything the browser sends. |
| reviewRequestEmails (settings) | Yes | A true/false: whether to be asked for a review after an order. |
| order reference + email (link an order) | Yes | The two details from a guest order's confirmation. They are matched against a stored order; both must match the same one before it is attached to the account. The values are not stored — only the resulting link between the account and that order is. |
| cursor + pageSize (order history) | Yes | Which page of your own order history to return. It cannot widen who the orders belong to — that is taken from the signed-in session, server-side. |
| account identity (every account request) | No — server-derived | The browser sends a signed sign-in token; the server reads WHO YOU ARE out of it rather than believing any name or id in the request. That is why one account cannot ask for another account's orders or preferences. |
| caller IP (hashed, linking an order) | No — server-derived | The browser does not send this as a field — the server reads the request's own IP address, salts and hashes it, and counts claim attempts per origin for one hour so the order-claiming form cannot be brute-forced. The raw address is never stored and the hash cannot be turned back into it. |
| customerName | Yes | The name typed on the Your details step — who we come back to about the order. |
| customerEmail | Yes | The email address typed on the Your details step, used to confirm the order. The payment link itself goes to the mobile number below, by message. |
| customerPhone | Yes | The mobile number typed on the Your details step. Required since 2026-09-15: the payment link for the order is sent to it by message, and it is how we reach you if there is a question about the order or the delivery. |
| shipTo | Yes | The delivery address: recipient name, optional company, address lines, town, optional county, postcode, country code and optional delivery instructions. The courier phone field that used to sit here is gone — the number is now customerPhone, on the order itself, so a collection order carries one too. |
| lines | Yes | The basket as item codes and quantities. NO PRICES: the server re-prices every line from its own catalogue inside the write transaction. |
| clientRequestId | Yes | A random idempotency key minted in the browser for this checkout, so that submitting twice cannot create two orders. Not stored on the device. |
| website | Yes | A honeypot field, invisible to a person. Empty on every genuine submission. |
| consents | Yes | One entry per agreement you accepted — which agreement, its version, and a fingerprint of its exact wording. That is the research-use agreement you accept at checkout, plus the site-entry acknowledgement when this browser has one stored. The hash pins the exact wording that was on screen. |
| dateOfBirth | Yes | The date of birth typed on the Your details step (BATCH B4 LEG B ROW 2 — age is re-checked at checkout, separately from the site-entry gate). Sent once, to the server, to confirm it clears the site's stated age floor; the server discards it the instant that check has run and NEVER writes it to the order or any other record — the order document carries no date-of-birth field at all. An order whose date is absent or fails the check is refused before anything is written. |
| signature | Yes | Your signature, as an image — either the one you drew or your name as you typed it. Optional: nothing is sent if you leave the pad blank. |
| acceptedAt (on each consent record) | No — server-derived | The browser does not send a time with a consent claim at all. The server stamps every record with ITS OWN clock at the moment the order is written, because a browser clock can be wrong and this is a field a dispute may turn on. |
| prices, totals and the order reference | No — server-derived | None of these are sent. The server re-prices the basket inside its write transaction, computes the total, and mints the reference. A caller that sends any of them has it discarded and logged. |
| caller IP (hashed) | No — server-derived | The browser does not send this as a form field - the server reads the request's own IP address, SHA-256-hashes it with the rate-limit bucket name, and stores that hash (not the address itself) to count orders per origin for one hour. This is pseudonymisation, not anonymisation: the bucket name is a public constant, so the hash could be matched back to a candidate address by enumeration. It exists purely to slow down automated abuse and is deleted with the bucket window. |
| code (to the code-validation endpoint) | Yes | The code from the referral link, sent so the server can say whether it is live and attributing. No basket is sent with it: the landing has no order, and asking without one is what stops a per-code basket minimum wrongly refusing a code that would work at checkout. |
| the code stored in the cookie | No — server-derived | The browser never chooses what is remembered. Only the code the SERVER returned in its own answer is written to the cookie, so a visitor pasting a made-up or hostile value into the link never reaches the cookie at all. |
| name, email, subject, message (ambassador application) | Yes | The application is an ENQUIRY: it uses the same contact form machinery, the same endpoint and the same inbox as any other message, tagged as an ambassador application. Nothing about it creates an account or grants anything. |
| application answers (channels, audience, research context, conduct) | Yes | Free-text answers about where the applicant posts, who their audience is, their professional context and what an ambassador may never say. They ride in the enquiry as extra fields and are read by a person. |
| anything about health, use, results or dosing | No — server-derived | The application form asks none of it, and there is no field for it. The questions are about audience and conduct, because those are what the programme turns on. |
| commission rates, balances and ambassador ids | No — server-derived | None of these ever reach a shop-front page. Rates live in the functions package; an ambassador id and a balance exist only behind an admin sign-in and the security rules. The referral landing is told only whether a code was recognised. |
15 items of browser storage, all on your own device — none of these are sent anywhere unless the description below says so.
| Key | Kind | Holds | If cleared |
|---|---|---|---|
| rey.admin-rail-collapsed.v1 | localStorage | The single character "1" or "0" — whether the back-office navigation rail is collapsed to its icon width. Nothing else: no identifier, no account, no order, nothing about a person. | The rail opens at its full width on the next load, and can be collapsed again. No other effect. A visitor who has never opened the back office never has this key at all. |
| rey.admin-catalogue-collapsed.v1 | localStorage | A pipe-separated list of catalogue CATEGORY IDS whose section the admin has collapsed on the back-office catalogue board. Category ids only: no identifier, no account, no price, no order, nothing about a person or about what anyone bought. NO EXAMPLE VALUE IS GIVEN HERE, AND THAT IS DELIBERATE. This row first carried a worked example of two real category ids, and `npm run check:claims` blocked the commit on it: some of this catalogue's ids are outcome words, and the scoped waiver that permits them (operator, 2026-08-28, decision D5) covers the catalogue data files and the ids themselves — NOT this file. The gate was right. A narrow waiver stays narrow by refusing exactly this kind of convenient spill into a neighbouring file. | Every section opens on the next load and can be collapsed again. No other effect. A visitor who has never opened the back office never has this key at all. |
| rey.admin-enquiry-draft.v1 | localStorage | An in-progress reply an admin is drafting on the contact centre, one entry per thread — the message text and when it was last saved. Nothing else: no customer address, no order, no identifier for anyone other than which internal enquiry id the draft belongs to. An admin's own draft text can of course be about a customer, in the same way an email you have not sent yet is; this key does not add anything beyond what the admin typed. | Any in-progress, unsent replies on this admin's browser are lost; nothing sent is affected, because a sent reply is never read from this key. The composer opens empty on the next visit to each thread, exactly as it did before this feature existed. |
| firebaseLocalStorageDb | indexedDB | The signed-in session (tokens, refresh state) when someone IS signed in. Opened empty the moment the page loads, on every route — it exists even for a visitor who has never seen a sign-in form. | Signs the browser out of any Firebase session, the same as using a private window. No effect on a visitor who was never signed in. |
| firebase-heartbeat-database | indexedDB | The SDK's own record of which Firebase products/versions this page has loaded. | No visible effect on the site. |
| rey.cookie-consent.v1 | localStorage | A record of which optional cookie categories this browser accepted, when the choice was made by the browser clock, and which version of the banner asked. No personal data: two booleans, a timestamp and a number. | The banner appears again on the next page load and every optional category is counted as refused until it is answered. |
| rey.cookie-anon-id.v1 | localStorage | A random UUID minted in this browser the first time a cookie choice is saved. It is not derived from anything about the visitor and is never joined to an account, an order or an email address. | A new id is minted on the next saved choice. Previously recorded audit rows can no longer be tied to this browser, including by a data-subject request. |
| rey.ruo-acknowledged.v1 | localStorage | The literal string "yes" once the research-use + age notice has been cleared on this device — by dismissing the modal with "I have read this and I am 18 or over" (default mode) or by submitting a date of birth that clears the floor (where this site asks for a date of birth instead of a simple acknowledgement). | The notice or gate shows again on the next page load. Nothing else is affected. |
| rey.ruo-acknowledged-at.v1 | localStorage | The browser clock, in milliseconds since 1970, at the moment the research-use + age notice/gate above was cleared. Written every time RUO_ACKNOWLEDGED_STORAGE_KEY is written, at the same moment. No personal data — a number. | RUO_ACKNOWLEDGED_STORAGE_KEY (above) counts as expired even if it is still present, and the notice/gate shows again on the next page load. |
| rey.ruo-date-of-birth.v1 | sessionStorage | Your date of birth, as a plain date — for example "1990-04-23" — but ONLY if the date you entered at the entry gate passed the age check above. A date that does not pass is never written here at all. | Checkout asks for your date of birth again, exactly as it would if you had never cleared the entry gate. Nothing else is affected — the entry gate itself does not reopen. |
| rey.ruo-consent-claim.v1 | localStorage | A record of exactly which wording of the research-use and age notice was on screen when you confirmed it — which notice it was, its version, and a fingerprint of its exact text. It holds no personal data: the fingerprint is of our own wording, never of anything you typed. | No functional loss. A form submitted afterwards simply carries no consent claim — the server accepts or refuses on its own rules either way. |
| rey.cart.v1 | localStorage | A list of the item codes in your basket and how many of each. No price, no product name, no line total. | The basket is empty on the next visit. Nothing else is affected. |
| rey.account.remember.v1 | localStorage | The literal string "1" or "0" — whether the person ticked "keep me signed in" the last time they signed in on this device. Nothing else: no address, no token, no name. | The tick-box returns to its default (ticked). No effect on whether you are signed in right now. |
| rey.referral-code.v1 | cookie | The referral code this browser arrived with, exactly as the SERVER normalised it - never the raw query string. Nothing else: no ambassador id, no rate, no amount, no identifier for the person browsing. | The browser is no longer attributed to anybody. Orders placed after that are ordinary unattributed orders; nothing else changes, and no page behaves differently. |
| _ga | cookie | A randomly generated number identifying this browser to Google Analytics, and the time it was first generated. A second cookie is set alongside it whose name begins “_ga_”, holding the same kind of value for this site’s own analytics property. Neither holds your name, your email address, your delivery address or anything you typed into a form. | Nothing on the site changes and no price moves. Your next visit is counted as a new one rather than a returning one. |
| Host | Why |
|---|---|
| fonts.googleapis.com | Requests the stylesheet for the web fonts this site uses. Your browser asks Google for it as the page loads. |
| fonts.gstatic.com | Serves the actual font files the stylesheet above references. |
| api.resend.com | The service that sends our email. Your browser never contacts it — it is called only by our server, and only when we send you a reply to an enquiry. |
| identitytoolkit.googleapis.com | Firebase Authentication. The sign-in, registration and password-reset forms send the address and password straight to Google's identity service from the browser — this site's own servers never see or store a password. Called only when one of those forms is submitted. |
| www.googletagmanager.com | Serves the Google Analytics script itself. Requested only after you turn on the Analytics cookie category — never before. |
| www.google-analytics.com | Receives the analytics measurements described in the Analytics cookie category. Contacted only after you turn that category on — never before. |
| region1.google-analytics.com | The European collector the Google Analytics script posts measurements to. Same data as the row above, a nearer address. Contacted only after you turn the Analytics category on. |
| analytics.google.com | Used by the Google Analytics script alongside the collectors above. Contacted only after you turn the Analytics category on — never before. |
Contents
Reydeance is a trading name in use while the company behind it is being formed. Registered company details will appear here once it is.
Reydeance is the controller for personal data collected through this website — the party that decides why and how it is processed. Where this notice says “we”, “us” or “our”, that is who it means. Which registered company trades as Reydeance is shown above once that company exists.
Anything about this notice — a question, a request about your information, a complaint — reaches us through the contact page.
It covers information held about people who use this website: visitors, people who send a message, and — where the features below are switched on — people who order, hold an account, or take part in a referral or ambassador programme. It also covers the small amount of information kept on your own device by the site itself, listed in the tables above.
It does not cover other websites. Where this site links out, the site you arrive at has its own notice.
The three tables above are the exact, code-derived answer for what leaves your browser, what is kept on your device, and what your browser contacts. This section says the same thing the other way round — by the moment it is collected.
This site records a research-use and age acknowledgement when you first enter it, and a research-use agreement — and a signature, if you choose to give one — when you place an order. What that means for the records we keep is set out below.
Where a consent statement is recorded, what is stored is which statement you agreed to and a cryptographic hash of its exact wording at the time — not a fresh copy of the wording itself — plus, where a signature is asked for, your signature as an image. The hash exists so that if the wording is edited later, the record still proves exactly what you saw and agreed to.
Our primary database (Firestore) is held in Google's europe-west2 region — London, United Kingdom.
Email sent and received through Google Workspace, and transactional email sent through Resend, may be processed on infrastructure outside the United Kingdom as part of how those providers operate.
After the stated period the record is deleted from primary storage. Some derived, aggregated or anonymised data may be kept indefinitely because it is no longer personal data under UK GDPR.
Under UK GDPR you have the right to:
To exercise any of these, use the contact page. UK GDPR requires a response within one calendar month of a valid request — the law's own maximum, not a target we have set ourselves — extendable by a further two months for a complex or repeated request.
We send marketing email only where you have ticked the opt-in box, worded exactly: “Email me occasionally about new products and offers.”
You can unsubscribe at any time using the link in any email we send, or from your account settings. We never sell your details.
The lawful basis is your consent (Article 6(1)(a) UK GDPR).
No decision that produces a legal or similarly significant effect on you is ever made automatically without a person reviewing it. This site does not build a behavioural profile of visitors for advertising, scoring, or any other automated-decision purpose.
This site is for people aged 18 or over who are buying research materials for laboratory research use.
The site is not intended for anyone under 18.
We do not knowingly collect personal data from anyone under 18. If we become aware that someone under that age has placed an order or otherwise provided personal data, we delete that data as soon as we reasonably can, and treat the order (if any) as cancelled under the age policy.
Account passwords are stored as one-way hashes by Firebase Authentication; we never see or store your actual password. The site is served over HTTPS throughout.
Where UK GDPR requires it, a personal-data breach that meets the reporting threshold is reported to the ICO within 72 hours — the statutory maximum under Article 33, not a target we have set ourselves.
Tell us first through the contact page.
We aim to acknowledge a complaint within 5 working days of receiving it. Where a complaint about this website or an order cannot be resolved between us, either party may bring proceedings in the courts of England and Wales, under the governing-law clause in our terms of sale. We do not use a named alternative dispute resolution (ADR) scheme.
Where UK data protection law applies, you can also complain to the Information Commissioner's Office at ico.org.uk. You do not have to come to us first.
This is version 0.1 (not yet published). When this notice changes, the version and date at the top of the page change with it. The tables in the first section change on their own as the site changes, because they are generated from the code rather than hand-maintained.