9
2
Fork
You've already forked platform
2

Optional email + explicit consent flow at signup #142

Closed
opened 2026年04月03日 17:38:07 +02:00 by xenushka · 2 comments

Summary

Caution allows anonymous sign-up via passkey/YubiKey: no email, username, or password required. We want to introduce an optional email step during registration, with explicit informed consent for users who choose to skip it. Users who skip email should also be able to add one later from Account Settings.


Background

Our anonymity-first model is a feature, not a gap. But not collecting email creates real consequences for users: no billing notifications, no invoices, no service updates, no account recovery path. Users need to understand this trade-off at the point of sign-up and actively consent to it, not discover it later when an invoice goes missing or their balance hits zero with no warning.

Reference: Mullvad VPN handles a similar pattern. Their support form lets users submit without an email but clearly states: "if you want a reply from us, you need to add an email." Caution's version needs to be more explicit given the billing consequences attached.


User Flow

Overview

See the attached flow chart covering both paths from the passkey ceremony:

  • Left branch (skip) → inline consent screen → Path B log → dashboard with the three timed nudges → billing notice as the only permanent passive reminder
  • Right branch (add email) → verification → Path A log → same dashboard

The account settings "add email later" path sits in the middle, feeding into Path C logging. The dashed line separating the nudge column makes clear those triggers only apply to no-email users.

image

Registration > Step: Add Email (optional)

After the passkey ceremony succeeds, present a single optional step. This is the main point of collection, so it should contain both the decision UI and a concise link to the relevant privacy notice subsection.

Screen: Add your email (optional)

Headline: Stay informed, or stay anonymous

Body:

Your account is ready. No email required.
If you'd like to receive billing notifications, invoices,
and service updates, add your email below.
If you skip this, we won't be able to contact you — for any reason.

[ Email address input ]

Primary CTA: Add email and continue →
Secondary CTA: Skip. I understand I won't receive emails.

Helper text under the secondary CTA: How Caution uses (and doesn’t use) your email
Link target: https://caution.co/privacy.html#email-addresses-optional

Optional tertiary line under the input or helper text: Read our Privacy Notice
Link target: https://caution.co/privacy.html#email-addresses-optional


This is the best place for a just-in-time reminder because it appears exactly when the user confirms they do not want to provide personal contact data.

⚠ By continuing without an email, you confirm you understand:
 · Invoices will not be sent to you
 · You won't be notified of low balance or billing issues
 · We cannot contact you about service updates or security notices
 · There is no account recovery path without a passkey
You can add an email at any time from Account Settings.

CTA: I understand. continue without email.

Final helper line below the warning text or under the CTA: How Caution uses (and doesn’t use) your email
Link target: https://caution.co/privacy.html#email-addresses-optional

This confirmation must be logged server-side with a timestamp and the policy/copy version shown to the user


Account Settings > Add Email Later

Users who signed up without email should see a persistent but non-intrusive prompt in Account Settings. A privacy link is useful here too because this is another point where the user may decide to provide email later.

No email on file
Add an email to receive invoices and billing notifications.
[ Add email ]

Small helper text below the prompt: How Caution uses (and doesn’t use) your email
Link target: https://caution.co/privacy.html#email-addresses-optional

Users who add an email later must receive a verification email before it is saved. The add-email event must also be logged as Path C.


Billing UI > "No Email" Notice

At the point of payment or checkout, if no email is on file, show a non-blocking notice. This is not the main legal notice, but it is an appropriate operational reminder because it appears exactly where invoice expectations are most likely to matter.

No email on file. Your invoice will not be emailed to you.
Add an email in Account Settings.

Optional inline link on the second line: How Caution uses (and doesn’t use) your email
Link target: https://caution.co/privacy.html#email-addresses-optional

This is the only persistent passive reminder. It appears every time the user transacts, regardless of nudge state.


Dashboard > Soft Nudge (no email on file)

For users who skipped email at signup, show a single dismissible banner in the dashboard. The banner triggers at up to three meaningful moments, then is permanently gone, fully respecting the user's choice. It never reappears after dismissal at any stage.

Trigger 1: First login after account creation
Trigger 2: First login after adding a payment method
Trigger 3: First time funds are added to the account

After all three triggers have fired or been dismissed, the nudge is permanently suppressed. The billing UI notice (above) remains as the only ongoing reminder.

Banner copy:

No email on file
You won't receive invoices or billing notifications.
Add an email → [Dismiss]

Small secondary link beneath the banner body: How Caution uses (and doesn’t use) your email
Link target: https://caution.co/privacy.html#email-addresses-optional

Dismiss is permanent per trigger: clicking it at Trigger 1 does not suppress Trigger 2, but dismissing at any stage means that specific trigger never resurfaces.

Placement rule

Use the full "How Caution uses (and doesn’t use) your email" link text on screens where the user is actively deciding whether to provide an email, and shorten it to Privacy Notice or How we use email in compact surfaces like banners or billing notices. That keeps the main decision points explicit while preserving UI cleanliness


Technical Requirements

Data model

  • email field on user/org record: nullable, optional
  • email_verified boolean: false until verification link is clicked
  • email_consent_declined boolean + email_consent_declined_at timestamp: set when user explicitly skips
  • nudge_dismissed_flags — track dismissal state per trigger (e.g. nudge_post_signup, nudge_post_payment_method, nudge_post_first_topup): once set, never unset
  • Internal account_uuid assigned at account creation — all consent logs keyed to this UUID
  • UUID ↔ passkey credential ID mapping stored in a separate, access-controlled table

Email handling

  • All transactional email sends must check email IS NOT NULL before attempting delivery — silent skip if null, no crash, warning logged
  • Billing system must not hard-fail on missing email
  • Email verification flow required when email is added (at signup or later via settings)

Consent logging — GDPR Article 7(1) + Cayman DPA Schedule 5

A bare timestamp + boolean will not satisfy audit or dispute requirements. Three distinct log schemas are required:

Path A: Email provided (legal basis: consent, GDPR Art. 6(1)(a))

{
 "account_uuid": "...",
 "event": "email_consent_given",
 "email_hash": "sha256(...)",
 "purposes": ["billing_notifications", "invoices", "service_updates"],
 "consent_copy_version": "v1.0",
 "timestamp": "2026年04月03日T10:00:00Z",
 "ip_country": "KY"
}

Path B: Email skipped (legal basis: contract performance, GDPR Art. 6(1)(b))

{
 "account_uuid": "...",
 "event": "email_consent_declined",
 "consequences_acknowledged": [
 "no_invoices",
 "no_balance_alerts",
 "no_service_notices",
 "no_account_recovery"
 ],
 "consent_copy_version": "v1.0",
 "timestamp": "2026年04月03日T10:00:00Z",
 "ip_country": "KY"
}

Path C: Email added later

{
 "account_uuid": "...",
 "event": "email_added_post_signup",
 "email_hash": "sha256(...)",
 "verified_at": "2026年04月03日T11:00:00Z",
 "consent_copy_version": "v1.0"
}
  • consent_copy_version must be bumped any time the skip screen copy changes
  • Consent logs must be retained for the life of the account + applicable statutory period
  • On account deletion/erasure request: email and email_hash must be deleted; consent log skeleton (UUID + event + timestamp) may be retained for legal accountability purposes
  • Consent logs must be surfaced in internal admin/ops tooling

Pseudonymity note

A passkey credential ID is pseudonymous personal data under GDPR Recital 26 — not truly anonymous — because it can be linked to an account via the public key store. The account_uuid approach above addresses this by keeping the mapping in a separate access-controlled table.


Out of Scope

  • Making email mandatory
  • Marketing email
  • Account recovery via email — passkey is the only recovery path, intentionally

Priority: Medium

Should ship before public launch. Billing consequences of silent no-email are a support and compliance risk.

## Summary Caution allows anonymous sign-up via passkey/YubiKey: no email, username, or password required. We want to introduce an optional email step during registration, with explicit informed consent for users who choose to skip it. Users who skip email should also be able to add one later from Account Settings. --- ## Background Our anonymity-first model is a feature, not a gap. But not collecting email creates real consequences for users: no billing notifications, no invoices, no service updates, no account recovery path. Users need to understand this trade-off at the point of sign-up and actively consent to it, not discover it later when an invoice goes missing or their balance hits zero with no warning. Reference: Mullvad VPN handles a similar pattern. Their support form lets users submit without an email but clearly states: "if you want a reply from us, you need to add an email." Caution's version needs to be more explicit given the billing consequences attached. --- ## User Flow ### Overview See the attached flow chart covering both paths from the passkey ceremony: - Left branch (skip) → inline consent screen → Path B log → dashboard with the three timed nudges → billing notice as the only permanent passive reminder - Right branch (add email) → verification → Path A log → same dashboard The account settings "add email later" path sits in the middle, feeding into Path C logging. The dashed line separating the nudge column makes clear those triggers only apply to no-email users. ![image](/attachments/c90e82bd-e58f-4c47-ad74-6149f43b95da) ### Registration > Step: Add Email (optional) After the passkey ceremony succeeds, present a single optional step. This is the main point of collection, so it should contain both the decision UI and a concise link to the relevant privacy notice subsection. **Screen: Add your email (optional)** Headline: `Stay informed, or stay anonymous` Body: ``` Your account is ready. No email required. If you'd like to receive billing notifications, invoices, and service updates, add your email below. If you skip this, we won't be able to contact you — for any reason. ``` [ Email address input ] Primary CTA: `Add email and continue →` Secondary CTA: `Skip. I understand I won't receive emails.` Helper text under the secondary CTA: `How Caution uses (and doesn’t use) your email` Link target: https://caution.co/privacy.html#email-addresses-optional Optional tertiary line under the input or helper text: `Read our Privacy Notice` Link target: https://caution.co/privacy.html#email-addresses-optional --- ### If user clicks Skip — inline consent confirmation (not a modal): This is the best place for a just-in-time reminder because it appears exactly when the user confirms they do not want to provide personal contact data. ``` ⚠ By continuing without an email, you confirm you understand: · Invoices will not be sent to you · You won't be notified of low balance or billing issues · We cannot contact you about service updates or security notices · There is no account recovery path without a passkey You can add an email at any time from Account Settings. ``` CTA: I understand. continue without email. Final helper line below the warning text or under the CTA: `How Caution uses (and doesn’t use) your email` Link target: https://caution.co/privacy.html#email-addresses-optional This confirmation must be logged server-side with a timestamp and the policy/copy version shown to the user --- ### Account Settings > Add Email Later Users who signed up without email should see a persistent but non-intrusive prompt in Account Settings. A privacy link is useful here too because this is another point where the user may decide to provide email later. ``` No email on file Add an email to receive invoices and billing notifications. [ Add email ] ``` Small helper text below the prompt: `How Caution uses (and doesn’t use) your email` Link target: https://caution.co/privacy.html#email-addresses-optional Users who add an email later must receive a verification email before it is saved. The add-email event must also be logged as Path C. --- ### Billing UI > "No Email" Notice At the point of payment or checkout, if no email is on file, show a non-blocking notice. This is not the main legal notice, but it is an appropriate operational reminder because it appears exactly where invoice expectations are most likely to matter. ``` No email on file. Your invoice will not be emailed to you. Add an email in Account Settings. ``` Optional inline link on the second line: `How Caution uses (and doesn’t use) your email` Link target: https://caution.co/privacy.html#email-addresses-optional This is the only persistent passive reminder. It appears every time the user transacts, regardless of nudge state. --- ### Dashboard > Soft Nudge (no email on file) For users who skipped email at signup, show a single dismissible banner in the dashboard. The banner triggers at up to three meaningful moments, then is permanently gone, fully respecting the user's choice. It never reappears after dismissal at any stage. **Trigger 1:** First login after account creation **Trigger 2:** First login after adding a payment method **Trigger 3:** First time funds are added to the account After all three triggers have fired or been dismissed, the nudge is permanently suppressed. The billing UI notice (above) remains as the only ongoing reminder. Banner copy: ``` No email on file You won't receive invoices or billing notifications. Add an email → [Dismiss] ``` Small secondary link beneath the banner body: `How Caution uses (and doesn’t use) your email` Link target: https://caution.co/privacy.html#email-addresses-optional Dismiss is permanent per trigger: clicking it at Trigger 1 does not suppress Trigger 2, but dismissing at any stage means that specific trigger never resurfaces. ### Placement rule Use the full "How Caution uses (and doesn’t use) your email" link text on screens where the user is actively deciding whether to provide an email, and shorten it to Privacy Notice or How we use email in compact surfaces like banners or billing notices. That keeps the main decision points explicit while preserving UI cleanliness --- ## Technical Requirements ### Data model - `email` field on user/org record: nullable, optional - `email_verified` boolean: false until verification link is clicked - `email_consent_declined` boolean + `email_consent_declined_at` timestamp: set when user explicitly skips - `nudge_dismissed_flags` — track dismissal state per trigger (e.g. `nudge_post_signup`, `nudge_post_payment_method`, `nudge_post_first_topup`): once set, never unset - Internal `account_uuid` assigned at account creation — all consent logs keyed to this UUID - UUID ↔ passkey credential ID mapping stored in a separate, access-controlled table ### Email handling - All transactional email sends must check `email IS NOT NULL` before attempting delivery — silent skip if null, no crash, warning logged - Billing system must not hard-fail on missing email - Email verification flow required when email is added (at signup or later via settings) ### Consent logging — GDPR Article 7(1) + Cayman DPA Schedule 5 A bare timestamp + boolean will not satisfy audit or dispute requirements. Three distinct log schemas are required: **Path A: Email provided** (legal basis: consent, GDPR Art. 6(1)(a)) ```json { "account_uuid": "...", "event": "email_consent_given", "email_hash": "sha256(...)", "purposes": ["billing_notifications", "invoices", "service_updates"], "consent_copy_version": "v1.0", "timestamp": "2026年04月03日T10:00:00Z", "ip_country": "KY" } ``` **Path B: Email skipped** (legal basis: contract performance, GDPR Art. 6(1)(b)) ```json { "account_uuid": "...", "event": "email_consent_declined", "consequences_acknowledged": [ "no_invoices", "no_balance_alerts", "no_service_notices", "no_account_recovery" ], "consent_copy_version": "v1.0", "timestamp": "2026年04月03日T10:00:00Z", "ip_country": "KY" } ``` **Path C: Email added later** ```json { "account_uuid": "...", "event": "email_added_post_signup", "email_hash": "sha256(...)", "verified_at": "2026年04月03日T11:00:00Z", "consent_copy_version": "v1.0" } ``` - `consent_copy_version` must be bumped any time the skip screen copy changes - Consent logs must be retained for the life of the account + applicable statutory period - On account deletion/erasure request: email and email_hash must be deleted; consent log skeleton (UUID + event + timestamp) may be retained for legal accountability purposes - Consent logs must be surfaced in internal admin/ops tooling ### Pseudonymity note A passkey credential ID is pseudonymous personal data under GDPR Recital 26 — not truly anonymous — because it can be linked to an account via the public key store. The account_uuid approach above addresses this by keeping the mapping in a separate access-controlled table. --- ## Out of Scope - Making email mandatory - Marketing email - Account recovery via email — passkey is the only recovery path, intentionally --- ## Priority: Medium Should ship before public launch. Billing consequences of silent no-email are a support and compliance risk.
109 KiB
Owner
Copy link

Is this issue still relevant? @xenushka

Is this issue still relevant? @xenushka
Author
Owner
Copy link

Addressed by #365

Addressed by #365
Sign in to join this conversation.
No Branch/Tag specified
main
feat/paddle-byoc-subscriptions
feat/legal-publish-doc
fix/issue-116-duplicate-ssh-key
fix/issue-307-remove-apps
fix/issue-265-http-port-private
fix/issue-330-remove-build-binary
feat/issue-164-account-id
fix/issue-119-logout-confirmation
feat/add-tofu-lockfile-cache
feat/webauthn-discoverable-login
docs/issue-339-install-instructions
fix/issue-336-split-qr-login-tokens
fix/verify-app-source-preflight
fix/many-git-push-deploy
fix/issue-334-email-verification-throttle
fix/issue-273-billing-url
fix/issue-333-final-usage-collection
fix/issue-270-low-credit-email
fix/issue-301-remove-auto-topup
fix/issue-320-byoc-auth-first
fix/issue-348-git-progress-checklist
fix/issue-321-byoc-caution-hcl
fix/issue-332-resource-id-suspension
fix/eif-app-mode-normalization
feat/cli-stagex-container
fix/eif-s3-layer-cache
fix/authz-role-checks
fix/paddle-customdata-credit-mint
fix/cli-hangs-unsupported-ssh-url
feat/print-platform-commit-dashboard
anton/feat/multi-user
fix/config-domain-validation
anton/support-ssh-destroy-get
fix/cli-config-dir
feat/publish-build-inputs
feat/locksmith-polishing
fix/procfile-run-command-no-split
anton/byoc-require-login
fix/hcl-init-template
feat/egress-default-deny
ryansquared/hcl
quotas
anton/feat/region-routing-resource-unavailable-alert
fix/attestation-502-dashboard
ryansquared/systemdize
fix/verify-git-credential-hang
anton/fix-low-credits-alert
xenushka/rename-byoc
ryansquared/add-download-eif
add-debug-flag
test/pr1-integration-harness
anton/fix/only-pass-required-env-vars
ryansquared/add-database-bucket
No results found.
Labels
Clear labels
Compat/Breaking
Breaking change that won't be backward compatible
Component/Enclave-Builder
This issue affects Enclave Builder (git-push and CLI)
Component/Infrastructure
This issue affects generic Caution hosted infra components
Deploy/BYOC
Relates to Caution Bring-your-own-compute
Deploy/Full-managed
Relates to Caution fully managed cloud
Deploy/Self-hosted
Relates to Caution deployed on self-hosted infra
Interface/API
This issue affects the API
Interface/CLI
This issue affects the command line interface
Interface/Git
This issue affects the Git `push` interface
Interface/Web
This issue affects the web dashboard
Kind/Bug
Something is not working
Kind/Documentation
Documentation changes
Kind/Enhancement
Improve existing functionality
Kind/Feature
New functionality
Kind/Security
This is security issue
Kind/Testing
Issue or pull request related to testing
Priority
Critical
The priority is critical
Priority
High
The priority is high
Priority
Low
The priority is low
Priority
Medium
The priority is medium
Reviewed
Confirmed
Issue has been confirmed
Reviewed
Duplicate
This issue or pull request already exists
Reviewed
Invalid
Invalid issue
Reviewed
Won't Fix
This issue won't be fixed
Status
Abandoned
Somebody has started to work on this but abandoned work
Status
Blocked
Something is blocking this issue or pull request
Status
Need More Info
Feedback is required to reproduce issue or to continue work
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
caution/platform#142
Reference in a new issue
caution/platform
No description provided.
Delete branch "%!s()"

Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?