Hemos cambiado el idioma a Español.View in English
Guías

Mapa de datos personales

Qué datos personales guarda el producto, dónde, durante cuánto tiempo y qué hacen con ellos las herramientas de privacidad.

Esta guía está en inglés. Las guías siguen de cerca el producto y cambian a menudo, así que mantenemos una sola versión exacta en lugar de traducciones que se quedan atrás.

What personal data of an end customer (a website visitor or a contact of a tenant) this product stores, where, why, how long, and what the data-subject tools do with it. Tenants can use it for their record of processing activities; the platform owner for theirs (as processor). Staff (operator) accounts are listed at the end for completeness — they are not covered by data-subject requests.

Engineering documentation, not legal advice. Retention defaults are product defaults; each tenant decides its own periods (Settings → Privacy & data → Retention) within the platform maximums.

How a person is linked

Link Meaning
contact id CRM profile, one per email address per website (contacts).
visitor id One browser session (visitors), or the stand-in “visitor” of an email address / messaging-channel user. A visitor has at most one conversation.
conversation id Everything said with that visitor (conversations → messages).
email address Contacts, verified/unverified visitor email, email-channel identities, campaign recipients, status-page subscribers, CSV import logs.
IP address visitors.geo.ip (unless “Do not store visitor IP”), webhook payload copies, server request logs.
free text Message text, notes, email bodies, AI answers / translations / summaries, rating comments, chatbot answers.

Who counts as the person (identity matching). A request is about a contact and/or an email address. Matched automatically: sessions whose email was verified (identity signature) and the email channel’s identity for the address when the address is proven there — at least one inbound mail from it was authenticated by the mailbox provider (its own top-most Authentication-Results: DMARC pass or aligned DKIM / SPF pass; IMAP only, with the authserv-id configured in the email settings) or answered an operator’s reply (our Message-ID or signed reply token). A forged From: alone proves nothing. Sessions where someone only typed the address (and unproven email threads) are listed separately as “unverified” and only included when the admin ticks the box. Erasure always removes the address itself from those sessions (“detach”), even when their content is left alone.

Data categories

Erasure modes: Delete removes the row (or the file); Anonymise keeps the row for the tenant’s records and reports but removes identifiers; Detach (unverified sessions not included) strips only the subject’s address / matching name and phone. “Scrub” = the subject’s known email, phone, name and IP are replaced by [erased] in free text (website-wide for email and phone).

# Category (registry key) Where it lives Linked by Purpose Retention after this work Erasure: Delete / Anonymise
1 Contact profile (profile) contacts (email, name, phone, company, avatar, segments, custom data, operator notes, unsubscribe flag + date, source), privacy_legal_holds contact id, email CRM, campaigns Kept until deleted or erased Deleted in both modes (the profile is the identity)
2 Sessions, devices, locations, page history (sessions) visitors (email, verified flag, nickname, phone, avatar, custom data, segments, device + user agent, geo incl. IP/city/coordinates, current page), page_views (url, title, referrer), privacy_consents (policy version + time) visitor id Chat, routing, analytics, identity Visitors who never chatted: 395 days after last seen · page views: 395 days · consents: with the visitor Delete: rows removed (cascade). Anonymise: email/phone/avatar/custom data/segments removed, name → pseudonym, IP + region/city/coordinates removed (country kept), user agent / screen / timezone removed, URL query strings removed, referrer → origin, page titles removed, browser session token invalidated
3 Conversations (conversations) conversations (status, subject, last-message preview, rating + comment, tags, assignment), platform_locked_conversations conversation id Inbox Default never; per tenant: delete or anonymise N days after resolved / after last activity Delete: removed. Anonymise: preview, subject and rating comment scrubbed (or [redacted])
4 Messages (messages) messages (text, notes, files, chatbot pickers, timeline events — e.g. “email set to …”), message_revisions (edit history) conversation id The conversation itself With the conversation Delete: removed incl. edit history. Anonymise: scrubbed; optional “redact message text” replaces text/notes and rating comments with [redacted]; edit history removed. Elsewhere in the website the subject’s email / phone are scrubbed from any message
5 Uploaded files (files) uploads rows + objects on disk (DATA_DIR/uploads/<website>/<key>) via file messages of the conversation Attachments Default never; per tenant N days (message keeps a “file no longer available” placeholder) Removed from disk in both modes, quota freed; anonymise leaves the placeholder
6 Emails (emails) email_messages (from/to/cc, subject, full original text and quoted part, Message-ID), email_identities (address → visitor) conversation id, email Email channel threading, replies Originals: 180 days (headers + thread message stay) Delete: removed. Anonymise: addresses and originals removed, subject scrubbed; identities removed. Other conversations: the address is scrubbed from headers and originals
7 AI data (ai) ai_answers (question, answer), ai_translations (cache), ai_conversation_state.summary (cache), ai_bot_sessions conversation id Operator assist, answer bot Caches: 90 days (re-created on demand); answers with the conversation Caches purged in both modes (and website-wide where they quote the address/phone); answers deleted, or scrubbed / redacted
7a Live translate originals (ai.live_translate) ai_live_outgoing (an agent’s own wording of a reply that was sent translated, its language and the language sent — the message row holds what the visitor received; operators only). ai_conversation_state also keeps the customer’s language and where it came from conversation id, message id Show agents what they wrote; audit of what was sent With the conversation (removed with the message, and when the reply is edited or deleted) Delete: removed. Anonymise: the subject’s identifiers scrubbed from the original (or [redacted]); website-wide the address / phone is scrubbed. Exported as data/live-translate.json (handler in modules/ai/privacy.ts)
7b Diagnostics runs (diagnostics) diagnostics_runs (the domain an agent checked for the customer, every check’s plain-sentence finding and evidence — DNS answers, HTTP status / redirect chain, certificate dates, a page title at most, never page bodies or cookies — the verdict, who ran it; for a verified WHMCS client also the matching service / invoice / domain status. Operators only; each run also leaves one private note, which is a message (row 4)). diagnostics_settings is tenant configuration (exempt) conversation id Agent-facing troubleshooting of the customer’s website / email With the conversation (FK cascade + conversation retention); at most 20 runs per conversation Delete and Anonymise: removed. Exported as data/diagnostics.json (handler in modules/diagnostics/privacy.ts)
8 Webhook delivery logs (webhooks) webhook_deliveries.payload — the exact JSON sent (contains message text, visitor email, IP, geo), response bodies ids + identifiers inside the payload Retries, debugging 30 days (pending retries are never cut short) Every stored delivery that mentions the person (any id or identifier) is removed in both modes
9 Campaign emails (campaigns) campaign_recipients (email, name, company, status, sent at, mailbox provider of the address, whether the email was tracked, bounce kind + time) contact id, email Campaign sending + stats With the campaign Removed in both modes (aggregate campaign stats lose the row)
9a Campaign opens, clicks and tracking preferences (campaign-tracking) — only when the website turned on open/click tracking campaign_events (per open / click: time, kind, classification — person / Apple privacy proxy / Gmail or Yahoo proxy / security scanner — and a reason code, the clicked link, and only for a person: ISO country, city when the website keeps city-level location, device class, mail app / browser family). No IP address and no user-agent string is stored: both are used in memory to derive the above and discarded. campaign_contact_flags (“do not track” set by the team or by the person through the link in the email, the address that bounced hard, the bounce reason + time) recipient → contact id, email See where / how campaign emails are read; leave out addresses that do not exist Events: the website’s page-view retention (default 395 days), swept every few hours; legal-hold contacts kept. Flags: with the contact Removed in both modes (handler in modules/email/tracking/privacy.ts); exported as data/campaign-email-activity.json
10 Email sequences (sequences) crm_sequence_runs, crm_sequence_events, crm_sequence_seen contact id Drip emails With the contact Removed in both modes; active runs are cancelled (removed) so no further step is sent
10a Sequence confirmation requests (sequence_confirmations) crm_email_confirmations (when a double opt-in email was sent / confirmed; the address only as a keyed hash, the link token hashed, the visitor session id) contact id Double opt-in for addresses only an unverified visitor typed (capped per address / website / visitor) With the contact Removed in both modes (handler in modules/crm/privacy.ts)
11 Contact activity (crm_activity) crm_activity (timeline incl. subscription / segment changes) contact id CRM timeline, consent history With the contact Removed in both modes
12 Automations (automations) automation_trigger_fires (which proactive message was shown when), automation_runs (chatbot runs). Answers collected by chatbots are stored in the session’s custom data (row 2) visitor id, conversation id Frequency capping, chatbot With the visitor / conversation Delete: removed. Anonymise: kept (no identifiers)
13 Screen-sharing control audit (cobrowse) cobrowse_control_sessions (operator name, times, action counts — typed text is never stored) conversation id Security audit of remote control With the conversation Delete: removed. Anonymise: kept
14 Analytics facts (analytics) analytics_conversation_facts (first page origin + path, response times, stars), analytics_visitor_activity (visitor id per hour) conversation / visitor id Reports With the conversation / visitor Delete: removed. Anonymise: kept (no identifiers)
15 Push receipts (push_receipts) push_receipts (operator ↔ conversation, time) conversation id Avoid duplicate unread emails 7 days Delete: removed
16 Status-page subscriptions (status_subscriptions) status_subscribers (email), status_notifications (outbox) email Incident mail Until unsubscribed / erased Removed in both modes
17 Help-article votes (helpdesk_feedback) helpdesk_feedback — widget votes as v:<visitor id>; public-page votes as a SHA-256 of IP + user agent visitor id (widget votes only) One vote per person With the article Widget votes removed in both modes. Public-page votes cannot be attributed to a person (hash) and are not erased by a request; article counters are anonymous aggregates
18 Imports (imports) import_refs (source system ids ↔ local ids), import_errors (messages may contain an address), import_runs.sample, crm_imports (problem rows with addresses, preview rows, stored CSV file on disk) local ids, email Re-runs without duplicates, checking an import Import logs and stored CSV files: 30 days after a finished import Refs removed; error rows mentioning the address removed; sample / preview / problem rows filtered; the stored CSV of a finished import that contains the address is deleted
19 Earlier data exports (privacy_requests) Export ZIPs on disk (DATA_DIR/privacy-exports) + request rows (masked label, keyed subject reference; the resolved scope is sealed while a job runs) subject reference Answering access requests ZIPs: 7 days An erasure deletes earlier export files about the same person and relabels their rows
20 Messaging channels (registered by the channels feature) channel_identities (Telegram id / phone / Messenger PSID / Instagram IGSID, profile name, username, profile: stored avatar copy + profile link), channel_inbound_events.payload, channel_messages, channel_consents, channel_audit visitor id, contact id Telegram / SMS / WhatsApp / Messenger / Instagram See the channels feature Handlers in modules/channels/privacy.ts (erasure also deletes the stored avatar upload). Exempt: channel_policies (destination countries + daily cap for operator-started SMS / WhatsApp), channel_meta_apps (app credentials), channel_meta_oauth_flows (admins’ short-lived logins), channel_meta_deletions (hashes + counts of Meta data-deletion / deauthorize callbacks), channel_meta_signed_requests (hashes of accepted signed_requests, ~1 h replay guard). Inbound queue rows are deleted after 30 days (processed) / 90 days (never processed). Meta data-deletion requests run eraseScope for matching identities
21 Consent to the chat notice privacy_consents visitor id Proof of consent With the visitor Part of row 2 (exported; removed with the visitor; kept on anonymise — it holds no identifier)

Kept on purpose after an erasure

What Where Why
Suppression record privacy_suppressions: HMAC-SHA256 of the lower-cased address (key: APP_SECRET + website), “erased”, date, optional “keep blocking” So a later CSV import, sync or campaign does not silently re-create and re-email the person. Imports skip the address (“Erased on request (do not contact)”), sequences never enrol it, a contact re-created by an operator or the person stays unsubscribed. Not reversible without the server secret.
Audit entries privacy_audit Who requested / completed the export or erasure, when, mode, counts per category, a keyed subject reference — never the address. Subject to the audit-log retention (default 1 year).
Completion certificate privacy_requests.certificate Signed JSON (HMAC-SHA256 over the canonical body): counts per category, options, backup statement, limits. No personal data.
contact.erased webhook tenant’s endpoints Opaque ids of what was removed (contact / visitor / conversation ids), mode and time — so the tenant’s own systems can follow suit. No personal data.

Not reached by an erasure

What Where Behaviour
Backups deploy/backup.sh: database dump + uploads. Off-site mode (encrypted with age, docs/operations.md): 14 daily + 8 weekly + 12 monthly sets (BACKUP_KEEP_*, up to about 13 months), 3 days of encrypted local copies. Local-only mode: nightly plain files, 14 days (BACKUP_LOCAL_KEEP_DAYS) Not rewritten. Erased data can stay in backups until they age out; it is never restored into the product automatically. Restoring a backup re-introduces erased people — re-run the erasures listed in the audit log after a restore.
Server request logs stdout → journald / container logs Contain request IPs and URLs (visitor tokens and invite/login tokens are redacted). Retention is the host’s log configuration.
Reverse proxy / CDN logs Caddy / nginx / Cloudflare Outside the product; configure their retention.
In-memory caches WHMCS summary (≤ 60 s), presence, website settings (≤ 30 s) Expire on their own.
Copies outside the product Webhook receivers, the tenant’s email inbox (transcripts, notifications), WHMCS, push notifications already delivered to operator devices The tenant’s own systems.
Free text Messages, notes, emails Delete removes them. Anonymise keeps them unless “redact message text” is ticked: only known identifiers are replaced; other personal data written in free text stays.

Retention defaults and why

Policy Default Why
Conversations Never Nothing changes on upgrade; the tenant decides (delete or anonymise, after resolved or last activity).
Visitors who never chatted 395 days Device / location / page data of people who never chatted; 13 months is the common limit for analytics data.
Page-view history 395 days Same reasoning.
Uploaded files Never Files are part of conversations; removing them silently would change records.
Webhook delivery logs 30 days Retries finish within ~24 h; the rest is only for debugging, and the bodies contain message text.
Email originals 180 days The thread keeps the visible message; originals are for debugging and “show quoted text”.
Import logs + stored CSV files 30 days Only needed while checking a finished import.
AI caches 90 days Re-generated on demand.
Push receipts 7 days Only used for minutes (unread-email coordination).
Audit log 365 days Long enough for security reviews and to show requests were handled.
Export downloads 7 days (fixed) Long enough to hand over; short enough not to become a second copy.

Platform admins can set maximums per policy (/platform/privacy). A tenant cannot save a longer period or “never” when a maximum exists; with a maximum on conversations, “never” becomes “anonymise after the maximum”. The nightly job (01:00–06:00 UTC) applies the policies in bounded batches (500 rows per policy per run; the rest continues the next night), never touches contacts on legal hold, and writes the retention log. The dry run counts exactly what a run would remove.

Staff (operator) data — not covered by data-subject requests

operators, sessions, account_tokens, authx_*, memberships, invites, push_subscriptions, push_preferences, inboxorg_preferences, inboxorg_views, inboxorg_mentions, platform_admins, platform_audit, privacy_audit (actor name + IP). These are the platform’s / tenant’s own staff records, handled by account deletion. Exports show staff by name only.

Onboarding (exempt, no end-customer data): onboarding_states holds the tenant’s setup progress — timestamps, the first page URL of the tenant’s own site where the widget was seen, the last “Check my site” result and the ids of the owner’s own test visitors from the try-it page; onboarding_operators holds staff preferences (orientation seen, setup emails on/off). Both cascade with their website / operator.

Website icons (exempt, no end-customer data): website_icons + websites.icon_url hold the tenant’s own icon — its public favicon or an admin’s upload (file under the website’s storage folder), where it was downloaded from and the discovery schedule. Deleted with the website (cascade + storage folder).

Campaign builder (exempt, no end-customer data): campaign_brand_kits holds the sender’s own brand kit (logo, colour, sender / company name, the business’s postal address, footer text and links); campaign_templates holds email designs operators saved as templates. Campaign pictures are operator uploads in uploads (like help-center images). A “specific people” campaign audience (campaigns.audience, kind contacts) lists contact ids only; an erased contact’s id then matches nothing (the contact row is gone) and is never mailed. All cascade with their website.

Campaign tracking (exempt, no end-customer data): campaign_links holds the destinations of the rewritten links of a measured campaign — written by operators; links with personalisation (merge tags) are never rewritten, so a contact’s details never end up there. campaign_tracking_settings holds the website’s opt-in, the footer-notice switch and DKIM selector names learned from our own returned mail. Both cascade with their campaign / website.

Sending (exempt, no end-customer data): sending_domains holds the website’s own sending domain, its ownership token, the provider’s DKIM / return-path records and their DNS check sentences; sending_pauses whether the reputation guard or a platform admin paused bulk sending (a rate sentence or the admin’s note); sending_daily per-day counts (sent, bounces, complaints — numbers only); sending_events the ids and kinds of provider notifications already processed (kept 14 days, never addresses); sending_platform the platform’s notification set-up. Bounces and complaints that the provider reports act on existing data only — the campaign recipient’s bounce fields and campaign_contact_flags (row of campaign tracking) and the contact’s unsubscribe flag — so their handlers cover them. Mail sent through the service passes through the provider (Amazon SES), which keeps its own sending logs and suppression list under the platform operator’s account. Tenant tables cascade with their website.

Trust & safety (exempt, no end-customer data): trust_settings holds the platform’s knobs (blocked / allowed sign-up domains, caps) and “admins were emailed” markers; trust_tenants a tier a platform admin pinned on a website (with the admin’s note); trust_mail_daily per website and day how many shared-mailbox emails were sent / refused (numbers); trust_recipient_daily per day a count of unauthenticated-trigger emails (status-page confirmations, sign-up verification, password reset) keyed by a salted HMAC of the recipient address — never the address — kept two days; trust_signup_blocks refused sign-ups per day and reason (numbers). trust_abuse_reports holds public abuse reports about tenants’ pages: the reported URL, category, the reporter’s own description and optional email for follow-up — platform records written by a third party, not a tenant’s visitors or contacts, never the reporter’s IP (the per-IP rate limit uses a hash). Reports keep a tenant_id without a foreign key so they outlive a termination; resolved reports are deleted after a year. Tenant tables cascade with their website.