Skip to main content

Privacy friendly

Notifizz does not store your users’ personal data. Names, plans, segments, custom fields, profile graphs — none of it lives in the platform. When a campaign needs a recipient’s profile, the orchestrator fetches it live from your systems via an enricher, uses it to send the notification, and lets it go. The only customer data Notifizz retains is the strict minimum required to deliver the message and honour later requests (unsubscribe, right of access, right to erasure). That single rule — fetch live, don’t copy — is the core of the architecture. Everything below is what falls out of it: the email hashing story, the bounded cache, the redaction pass, the retention dials. None of it is a configuration option you opt into; it’s how the platform is wired.

TL;DR

  • No warehouse sync. Customer profiles stay in your systems. The orchestrator fetches what it needs at notification time via enrichers — never copies it.
  • Plain email is bounded by a window (default 90 days without a send to the person, configurable down to 7). Past it, the address is masked in Audiences, and what outlives it there is a keyed hash (HMAC), scoped to your organisation — enough to find the person by typing their address, to de-duplicate and to honour a past unsubscribe, never enough to email again. The next send makes the address readable again — see plain email lifecycle. The hash has a term too: 180 days after the last send to the person — or the last time identify() created an identity for them —, and never before the address is masked, a person known only by their address is removed, and a person known by your user id keeps only that id — except anyone who opted out of something, who keeps their hash for as long as the opt-out stands. Copies kept elsewhere — an in-app inbox message that displays the address, the exceptions listed under erasure — follow their own term.
  • Expired messages are redacted, not deleted. Everything that names the person is emptied; the delivery record survives so your Outbox keeps telling the truth about what shipped. It keeps a one-way reference to the person, used only to honour access and erasure requests — the person’s campaign history, shown to your team —, to attribute conversions and to count each person once in your campaign statistics (aggregated, never shown per person), until it is deleted 180 days after sending.
  • The enricher cache is bounded, not a sync. Per (org, env, enricher, params) keying with a TTL declared at registration. Eviction is automatic; only recently used records exist.
  • Five retention dials, configured per organisation, with conservative GDPR-aligned defaults and platform-enforced bounds.
  • Email opens and clicks are measured only with consent. Only recipients covered by your organisation’s declaration are measured — everyone under All my recipients have consented, the people whose consent your backend passed on under Only those who consented — and never someone who refused, whether your backend passed the refusal on or the person gave it from an email. Until your organisation declares, production emails carry no open pixel and record no opens or clicks; links and unsubscribe keep working. See open and click measurement.

Why it matters

GDPR Article 5 — and the equivalent regimes everywhere else — require you to hold customer data only as long as you need it, for explicit purposes. Notification platforms in the Customer.io / Braze / Iterable lineage centralise all customer data in their own database, indefinitely, in case a campaign ever fires for that customer. Your DPO ends up auditing a parallel customer graph that exists only for “we might send something one day”. Notifizz’s design eliminates that parallel graph. The privacy surface you have to audit is the event payloads you control, plus the per-message delivery snapshots — not a copy of every customer.

The three pillars

1. Enrichers — no warehouse copy

The platform doesn’t sync your customer database. Instead, the orchestrator calls enrichers — server-side functions you register that fetch live data from your systems at notification time.
  • Privacy surface stays in your systems. Notifizz processes; you store.
  • No drift. The user’s email is whatever your DB returns at notification time, not what last night’s sync ran with.
  • No schema migration. New attribute? Add a field to the enricher’s output. Renamed? One file changes.
The full positioning case is in why enrichers; the wire-level protocol is in enrichers protocol.

2. Email hashing — plain text only when needed

The platform handles email in two distinct states: plain during the operational window, hashed only outside it. The suppression list stores hashes only, and an unsubscribe is recorded on the person’s subscription preferences and matched by the hash too — neither needs the plain address to hold.

Normalisation, then hash

Every incoming email is normalised — trimmed and lower-cased — then hashed with a keyed hash (HMAC-SHA-256) under a secret key that Notifizz holds: without that key, nobody can recompute it from a list of addresses. The hash is scoped to your organisation: the same address in two different organisations produces two different hashes, so nothing correlates across customers of the platform. The hash is what makes the rest work. It de-duplicates a person arriving through several ingest paths, and it lets the platform recognise “this address unsubscribed” long after the address itself is gone.

Plain email lifecycle

The plain email is held for the window after the last send to the person — or the last time your backend declared a new identity for them with identify() — and for as long as an email or web push that has not been redacted yet still names it — an in-app inbox message names its recipient by user id only (see redaction). Erasing the person erases that message through the address. Past both, a daily job masks it automatically: Audiences and the export show j•••@acme.com instead of the address — or, in the Audiences list, your user id for a person you identify —, and the plain copy leaves the person’s record; copies kept elsewhere follow their own term (see the exceptions under erasure). The hash stays, up to the hashed-address term (below). Until then, searching by the address still finds the person, and their opt-outs and the suppression list keep applying. When a new send arrives for the same address, the hash matches the existing recipient, the plain email is reintroduced, and the history is continuous. A send counts from the moment Notifizz prepares it, even when it does not leave: a rehearsal, a sample of a broadcast, or a campaign that is not live yet. A recipient included in one keeps their address for another window.

Hashed address lifecycle

180 days after the last send to the person — or the last time identify() created an identity for them —, and only once their plain address has been masked, Notifizz no longer recognises them by their address:
  • A person known only by their address is removed — their record, its hash and their preferences. Their Audience goes with it when nothing else is left in it, and so do the statistics records that carry only the person’s one-way reference: the markers that keep a unique open or a conversion from counting twice, the records that stop a sequence once its objective is reached, and the entries of the “Who converted” list that name no one, even before their own term. A measurement consent you sent by address, kept without an Audience, stays as long as another record in its environment holds the same address; an opt-out, wherever it is recorded, is kept for as long as it stands (below).
  • A person known by your user id keeps the user id and loses the hashed address. Audiences shows them by your user id, and searching by the address no longer finds them.
Copies kept elsewhere follow their own term, not this one: the “Who converted” list keeps an address it shows until its own dial, objective evaluations keep it 180 days, campaign runs 180 days, or longer while their sequence is still running, and an in-app inbox message that displays the address keeps it until it is deleted at its term (5 years by default) — see the exceptions under erasure. Anyone who opted out of something by email — unsubscribed, muted a category, refused open and click measurement — keeps their hashed address, on all their records, for as long as the opt-out stands, wherever in your organisation they expressed it: that is what keeps them opted out. An address still held in plain is never forgotten before it has been masked, so a longer plain-address window delays this term too. The 180 days are set by the platform, not by a dial: they are also how long a conversion reported by the address alone is attributed to the campaign that wrote to the person. Linking two records that already exist with identify() does not restart them: only a send, or an identity identify() creates, does. Past them, a send to the address alone starts a new person with a new history — counted as a new person in a campaign that spans both; a send that carries your user id and the address finds the person again and restores the address. The window defaults to 90 days and is configurable per organisation. The platform enforces a 7-day minimum, so that a bounce or a complaint reported a few days after a send can still be shown against the address it concerns. Applying the bounce or the complaint does not need the plain address: it goes through the hash.

3. Cache — bounded, not a sync

Enricher responses are cached server-side to keep latency low. This is not a sync. The differences are structural: Cache key is (organisationId, environmentId, enricherName, sha256(params)) — strict cross-tenant isolation, identical params from different organisations never collide. TTL precedence: per-call override → declared at registration → 1-hour default. An enricher declaring cache: false cannot be overridden upward. The enrichers protocol covers the cache policy in detail.

What Notifizz stores — and what it doesn’t

The cap is deliberate. You can’t ask Notifizz to “store the user’s plan” or “store the user’s segment”. The platform doesn’t have those columns. If a campaign needs them, an enricher fetches them on demand.

Retention configuration

GDPR places retention under the responsible-party (you, the controller) — not the processor (Notifizz). Notifizz exposes five configurable dials per organisation, with conservative defaults and platform-enforced bounds: The current configuration is the truth — for plain addresses, sent messages, the in-app inbox and the converted list. A daily retention job applies those four dials to every organisation’s existing data, including an organisation that never changed a dial (it is purged at the defaults): lowering one purges or masks records that fall outside the new window, raising one keeps records the old window would have purged. One exception: the suppression list keeps, for each block, the period set when it was added — shortening the dial never unblocks anyone. Lowering a dial that purges existing data asks for confirmation before applying — destructive changes are deliberate, not accidental. For the plain-address window, the confirmation also tells you how many addresses the next job will mask. Every dial change is written to an append-only journal (actor, timestamp, old → new), shown on the Retention settings page — useful for CNIL / ICO inspections and for protecting both parties in a dispute. Each dial also says where its current value comes from: the platform default, or who set it and when. A value with no journal entry that is not the default says so, rather than passing for a default.

Set by the platform

Some periods are not dials: they are the same for every organisation, and the Retention settings page shows them read-only.

Redaction

Past messageRetentionDays, a sent message is not deleted. Everything on it that names the person is emptied — recipient (your user id and the address), rendered HTML, subject, properties and push payload; the row stays, flagged with a redaction timestamp. The emptied record is deleted in turn 180 days after the message was sent. That duration is set by the platform, not by a dial. Messages sent on or before 29 September 2026 may keep the destinations of their links and buttons — which can carry personal data, a magic sign-in link for instance — until that deletion. The distinction is operational as much as legal. Deleting the row outright would take the delivery status, the campaign, the step and the timestamps with it — and a delivery report that finds nothing concludes that everything went fine, including for sends where not a single message ever left. A redacted record still says what happened. It no longer names anyone. The redaction flag is what separates a record that was emptied from one that never carried anything — without it, “absent” and “blank” would be indistinguishable, which is the exact trap the redaction pass exists to close. In-app inbox messages are the deliberate exception: an inbox is a reading surface, so its entries are kept for notificationCenterRetentionYears and then deleted outright. A message someone is meant to read makes no sense emptied of its content. An entry keeps only what that notification shows — its template, the values it displays and its button links — and the user id it is addressed to. It does not keep the rest of the recipient’s profile, and it keeps their email address only if that notification displays it. Entries written before October 2026 were reduced the same way by a one-off clean-up pass.

What a redacted record still points to

A redacted record keeps a one-way reference to the person it was sent to: a pseudonym, specific to your organisation. Nothing turns it back into a name, an address or a user id — not the record, and not Notifizz. It only works the other way round: starting from a person still on file in your organisation, Notifizz can recognise the records that point to them. The reference serves to honour access and erasure requests, to attribute conversions and to count each person once in your campaign statistics (aggregated, never shown per person) — nothing else:
  • Access goes all the way. The person’s campaign history — on their record in Audiences, shown to your team, and your answer to a right-of-access request for what was sent — lists their redacted records alongside the others: campaign, channel, status and date, never the content. That is the 100 most recent deliveries, up to 180 days.
  • Erasure goes all the way. When you erase a person — the whole person, or the last channel identity they had — their redacted records are found through the reference and deleted with them, instead of waiting out their 180 days. So are the statistics records that carry only the reference: the markers that keep a unique open or a conversion from counting twice, and the records that stop a sequence once its objective is reached.
  • Conversions are attributed. When one of your events reports that the person converted, Notifizz still recognises them as someone the campaign wrote to after the message is redacted, and a sequence set to end when the objective is reached stops for them — for as long as the record exists, up to 180 days after sending. That window follows the record and is not configurable.
  • Statistics count people, not records. Your campaign statistics recognise the person behind a redacted record through the reference, so a person still counts once after redaction: a click on a redacted web push counts under them, and the delivery figures of a run in the Outbox or of a broadcast report count people, not records. These figures are aggregated: the reference is never shown per person.
The reference cannot be used to reach the person, and it lives exactly as long as the record. One exception, for erasure and access alike. When identify() merges two Audiences, Notifizz remembers that the absorbed one now leads to the surviving one, so erasing the survivor reaches the redacted records of both, and its campaign history lists them. detach() usually corrects a mistaken link, so it forgets every merge into the Audience the identity leaves — merges made in good faith included, since nothing records which merge brought which identity. Redacted records sent under an absorbed Audience, before its merge, are then reached by no erasure and listed in no campaign history — neither the detached identity’s nor the survivor’s. They name no one, and they are still deleted 180 days after sending. Records sent to the detached identity while the mistaken merge was in place follow it as long as they name it; once redacted, they name no one and stay with the Audience it left: its erasure takes them, its campaign history lists them. The same goes for the markers that keep a unique open or a conversion from counting twice under that absorbed Audience: they name no one either, and they are deleted 90 days after the campaign is archived.

Measurement after redaction

  • An email is no longer measured. An open or a click on a redacted email is not recorded, whatever your organisation declared for open and click measurement: the record no longer says who received it, so Notifizz can no longer check that this person may be measured. Its links keep working, and its line in the person’s campaign history keeps the status it had when it was redacted.
  • A web push is still measured. Its clicks keep counting. The reason email stops does not apply here: the measurement setting covers email only.

Suppression and right to be forgotten

When a user unsubscribes, marks a message as spam, or asks to be deleted, the obligation is “never email again” plus (for deletion) “remove the record”. Notifizz handles both without keeping the address indefinitely:
  • Unsubscribe, from the link in an email or the one-click header → recorded on the person’s own subscription preferences, not on the suppression list. Before a promotional send, the incoming address is hashed and matched against those preferences, so the plain email is not needed. The opt-out holds until the person re-subscribes from the preference centre; transactional mail still goes out.
  • Spam complaint, hard bounce, or an address your organisation adds itself → the email is hashed and added to the per-org suppression list. Subsequent sends hash the incoming address and check the list before dispatch. The plain email is not retained. Each entry is kept for a set number of years, then removed; a bounce is lifted earlier if the provider reactivates the address.
  • Right to erasure → declared by your system as part of your own user-deletion flow. Three routes, depending on what you are erasing:
Messages sent to the erased person’s address are purged with them, except those addressed to another of your users who is still on file: an address shared by two of your users is not one person, and erasing one never erases the other’s history. The address still goes on the suppression list, so it receives no further email from any of your users — when Notifizz still has it on file. A person known by your user id whose hashed address reached its term no longer has it on file (see hashed address lifecycle): erasing them blocks no address. Erasure also takes the person out of your campaign statistics: their entry in the “Who converted” list, their objective evaluations in the Outbox, and the records that stop a sequence once they reached its objective. The shared-address rule holds here too: a conversion found at that address but made by another of your users still on file stays theirs. Counters are not rewritten — a campaign that counted the conversion still counts it, and its list simply shows one person fewer. A few records outlive an erasure for a bounded time, then go on their own:
  • the event log behind your counters, about three to four months (see the table above);
  • what the internal queues still hold for them — a send, or the event behind a reminder or a digest: about two days after that work finished (see the table above);
  • once a person’s address has been masked: their conversions and objective evaluations that name them only by that address — not by your user id — until their own term; erasure no longer holds the address to find them by;
  • a one-way reference to the erased user id — a keyed hash, never the id — that stops the sequences already running for them (below), for as long as a sequence that started before the erasure is still running;
  • on a sequence still running for them: the event that started it, and, for each step it still plays, what your enrichers returned about them and which of your conditions applied to them — kept with the sequence: 180 days after it started, or until it ends if that is later;
  • an objective evaluation that names the person only through your own event properties, or only by push id or phone number — 180 days;
  • the statistics of people erased before this behaviour shipped, in October 2026 — until their retention ends.
Erasure stops the sequences already under way. A sequence that started before the erasure and still has steps to play never writes to the erased person again, on any channel, and creates no new record for them: they are counted under Blocked (bounce, spam or erasure). The other recipients of the same sequence are not affected, and the sequence keeps running for them — your enrichers may still be called with the erased user id until it ends. A sequence whose next step finds only people you erased by your user id ends there. This holds for a person who has not received anything yet, and so has no record: erasing them by your user id answers 403, as for anyone unknown, and still stops the sequences already started for them. An event you send after the erasure is new data: the sequence it starts reaches the person and creates a new record. Email stays blocked only if the erased record held their address, which erasure puts on the suppression list. Four limits:
  • the stop applies in the environment of the erased record — the suppression of the address, above, applies in all your environments;
  • a notification already handed to delivery when the erasure happens — typically seconds before it — still goes out, and creates a new record for them;
  • a sequence that starts after the erasure, or while it is being processed, counts as a new sequence even when it was set up before: an inactivity reminder or a digest armed before the erasure, or an event you sent just before it and still waiting to be processed, reaches the person;
  • a person erased before this behaviour shipped, in October 2026, can still be reached by a sequence that was already running, until that sequence ends.
There is no SDK shorthand for erasure today — call the endpoint directly from your own deletion flow.
Erasure feeds the suppression list. Every deletion writes the hashes of the addresses still on file for the person to the suppression list first, for suppressionListRetentionYears. This is deliberate: a person erased today must not be emailed again tomorrow because a fresh import reintroduced them. The address itself is gone — only the hash remains, and a hash cannot be emailed. An address Notifizz has already forgotten — past the hashed-address term, with no opt-out — is no longer on file, so it is not blocked.

How this composes with the rest

  • Enrichers — the no-copy primitive, the largest single reason Notifizz is privacy friendly.
  • Recipients — recipients carry only id + email (plus arbitrary fields you control); never absorbed into a profile store.
  • Authentication — widget auth modes keep authenticated and anonymous traffic strictly separated, in line with the CNIL January 2026 recommendation.
  • Open and click measurement — whether your emails carry an open pixel and record clicks is your organisation’s declared instruction, dated and journaled, closed by default — refined person by person by the consent or refusal your backend passes on.
  • Activity log — the audit trail of campaign work. Organisation-level choices — retention dials, open and click measurement — keep their own journals.

FAQ

The dashboard fetches the live profile from a configurable per-organisation Profile Resolver webhook at render time — same model as enrichers, scoped to UI display. Names, avatars, CRM links, custom fields stay in your systems; Notifizz never persists them. If the resolver is unconfigured or unavailable, the UI falls back to the email — masked once its window has passed — or the truncated external_id: display degrades, the platform doesn’t block. Once a person’s address is masked, the resolver is no longer given it: a resolver that looks people up by address returns nothing for them until the next send, and a person known only by a masked address is not called at all.
Because a user who unsubscribes today must not be re-emailed by a fresh campaign next year. Their opt-out is recorded on their subscription preferences, and the hash lets the platform recognise “this address has unsubscribed” without keeping the address itself. It also handles the case where the same person comes back through a different ingest path — the hash matches, the opt-out applies, no promotional email goes out. That is why the hash of someone who opted out outlives the 180-day term that ends everyone else’s — see hashed address lifecycle.
So that nothing correlates across customers of the platform. The same address in two organisations produces two unrelated hashes — one organisation’s data can never be joined to another’s on the hash. A single global hash would make every Notifizz customer’s audience comparable to every other’s, which is precisely the parallel customer graph this architecture exists to avoid.
No. A cache stores records actually used in the last TTL window. A sync stores every customer indefinitely. The privacy footprint scales with notification volume, not with customer count, and evicts itself automatically. If you need stronger guarantees for a specific enricher (say, one that fetches sensitive fields), declare cache: false at registration — the orchestrator will hit your endpoint on every call.
During the campaign window, yes — the plain address is held in order to dispatch. Once the window passes without a further send (default 90 days), the plain addresses are masked in Audiences and only hashes remain there, up to the hashed-address term; a new send restores them. Copies kept elsewhere — an in-app inbox message that displays the address, the exceptions listed under erasure — follow their own term. The window is configured per organisation: shorten it if your policy calls for it, down to the 7-day floor.
No. The export per person covers their identities — each identifier, its hash and, while it is still held, the plain address — and their preferences: subscription choices, the measurement consent your backend passed on, and the person’s own refusal of measurement if they expressed one. An answer given for an email address that is not yet linked to them appears once you link it with identify(). It does not contain their messages, neither the delivery history nor the in-app inbox. What was sent to the person is the campaign history on their record in Audiences — the 100 most recent deliveries, up to 180 days, redacted ones included; the content of a message opens one message at a time in the Outbox, which lists runs by campaign and event, not by person, for as long as it is held: an email or a web push is redacted after messageRetentionDays (7 days by default), an in-app inbox message is kept for notificationCenterRetentionYears. See answering a right-of-access request.
Notifizz is the processor in the GDPR sense; you remain the controller. The retention dials are exposed precisely because the duration is your decision. Notifizz enforces minima (so a controller can’t ask the platform to break bounce handling or skip the legal suppression-list floor) and provides safe defaults, but the policy choice belongs to you. A model DPA is provided at onboarding.
While a message keeps its content, that content is stored readable and Notifizz holds the means to read it — we do not claim otherwise. What we commit to is a record. When a member of our team, signed in as one of your users to assist you, opens one of your messages as it was rendered — the HTML of an email, or the data an in-app notification was composed with — a record is written before the message is shown: who, when, which message, and whether its content was still there. If the record cannot be written, the message is not shown. The tool our team uses to tell where a tracked link led works the same way, with a reason given for each look. The record is kept for one year. The record covers opening a message as rendered. The event data you sent and the enricher responses shown with each run, in the Outbox and in Review, are visible to our team during an assistance session without a record. A team member you invite into your organisation is a member like any other; their reads are not recorded.

See also

Why enrichers

The case against warehouse-sync platforms.

Enrichers protocol

Cache policy, HMAC, anti-replay — the wire spec.

Recipients

The minimal recipient shape and why it stays minimal.

Authentication

Auth modes that keep the authenticated / anonymous boundary strict.