Trust, security & privacy

What we collect. What AI sees. Who we share with.

Plain English. Every claim on this page is something you can verify in our code or our vendor contracts. We would rather ship an accurate short page than a polished long one.

Last updated 2026-04-18.

Section 1 of 7

What we collect

The smallest set of data we can use to send a survey and report results. If a field is optional, the platform keeps working without it.

  • Respondent email address — used to deliver the survey, dedupe sends, and honor unsubscribes.
  • Respondent name (optional) — shown in the response view if the org provided it.
  • Phone number (optional, only for SMS surveys) — used only to deliver a survey and verified via Twilio Verify before send.
  • Response score (0-10 for NPS, or the scale matching the survey type).
  • Free-text comment (optional).
  • Timestamps and the survey type.

What we do not collect:

  • No device fingerprint.
  • No third-party advertising cookies.
  • No cross-site tracking pixels in survey emails.
  • No social-graph or demographic inference.

Stripe runs the checkout flow when you upgrade a paid plan. Stripe sets its own cookies on its checkout domain to prevent fraud. We do not read those cookies.

Section 2 of 7

What AI sees

We use Claude (made by Anthropic) for sentiment scoring, theme extraction, churn-risk flagging, and coach answers. Every prompt goes through the same safety pipeline before it leaves our servers.

  • PII is redacted first. Every free-text field routes through lib/pii.js#redactPII() before the prompt is built. Emails, phone numbers, credit-card-shaped digit runs, and common first-name / first-last patterns are replaced with tokens like [email] and [name]. The function is deliberately biased toward over-redaction.
  • Non-English responses bypass sentiment. If a comment does not read as confidently English, the AI call is skipped entirely and the response is stored with reason: non_english_bypass. Sentiment models underperform on non-native-English text, so we decline to score rather than guess.
  • Raw prompts and raw responses are never logged. We log a promptHash (first 12 hex chars of a SHA-256), the model name, token counts, and latency. Nothing else.
  • Claude never writes SQL. For natural-language queries, Claude emits a strict JSON filter; our code builds the parameterized SQL with organization_id hardcoded as the outermost filter.
  • Orgs can turn AI off. Owners can disable all AI processing for their organization via Settings. When disabled, zero AI calls happen for any user in the org (enforced by migration 012_ai_opt_out.sql and checked on every code path).
The full AI data-processing contract, including the opt-in cross-org benchmark model, lives in AI_PROCESSING_ADDENDUM.md. Share with procurement on request.
Section 3 of 7

Subprocessors we share with

A subprocessor is any vendor that handles customer data on our behalf. We keep this list short and every entry here is referenced from the code (an environment variable, a library import, or a pinned rate constant). If you cannot find it in our repo, we are not sending data to it.

Always used

Vendor Purpose Trust / DPA
Anthropic
AI model provider (Claude)
Sentiment, theme, churn, coach, report generation. Receives redacted text only. Policy
SendGrid
Email delivery
Sends survey invites, magic-link sign-in, unsubscribe confirmations, and delivery-status webhooks. DPA
Twilio
SMS & phone verification
Sends SMS surveys and the Twilio Verify challenge for phone sign-in. Never receives response comments. DPA
Stripe
Billing
Subscription management. Receives billing email and plan; never receives response data. DPA
Railway
Application hosting
Runs the Node.js application and Postgres database. DPA
Cloudflare
CDN & edge proxy
Serves marketing pages and forwards app traffic to Railway. Trust hub

Polls only — when mail or phone channels are enabled

Vendor Purpose Trust / DPA
Lob
USPS mail delivery
Prints and mails paper poll invitations when a municipal poll uses the mail channel. Trust
Twilio Voice
Phone IVR delivery
Dials voters and reads the poll script when a poll uses the phone channel. DPA
AWS Polly
Text-to-speech for IVR
Generates the audio voice track for the phone channel. Receives the poll script only. DPA

Optional AI fallback (only if your operator configures them)

If OPENAI_API_KEY or GEMINI_API_KEY is set in the deployment, AI requests fall back to OpenAI, then Gemini, if Anthropic is unavailable. The same PII redaction pipeline runs for every provider. In the default RallyNPS deployment, only Anthropic is configured.

Section 4 of 7

Retention

  • Survey definitions and responses: kept until the organization deletes them or closes the account.
  • Account deletion: deleting an organization deletes its surveys, contacts, responses, and AI-analysis rows on the same transaction.
  • AI prompts: we store prompt hashes (SHA-256 prefixes) for debugging. We never store raw prompt text or raw model responses.
  • Webhook delivery logs: retained for 30 days, then deleted.
  • Email engagement events (opens, bounces, unsubscribes from SendGrid): retained for the life of the contact record so unsubscribes are honored.
  • Unsubscribes: permanent. An unsubscribed contact is never emailed again.
Section 5 of 7

Token security

  • Survey response tokens and unsubscribe tokens are UUID v4 — random, never sequential, never derived from the recipient's email.
  • The score token and the unsubscribe token are different values, so an unsubscribe link cannot be used to submit a fake score.
  • Session tokens are 256 bits of entropy from the OS random source.
  • Phone sign-in runs through Twilio Verify (rate-limited by Twilio, plus five attempts per ten minutes per phone in our own code).
  • Public endpoints are rate limited to 60 requests per minute per client IP. Proxied IPs are trusted only from Cloudflare / Railway / loopback.
Section 6 of 7

Organization isolation

Cross-organization data leak is on our internal Top 5 Damage Risks list. We treat it as the worst thing we could do.

  • Every database query filters by organization_id. This is a code-review gate on every PR.
  • Every AI route resolves the org's ai_enabled flag before any external call.
  • We maintain a dedicated cross-org isolation test battery (test/integration/cross-org-isolation-battery.test.js) that attempts access across organizations for every mutation endpoint.
  • Opt-in cross-org benchmarks publish only when at least 10 organizations contribute to a vertical, so removing one org cannot reverse-engineer its data.
Section 7 of 7

Contact

Security reports, data-request questions, or anything not covered here: [email protected].

We are a small team and do not have a 24/7 security desk. Reports are read within one business day. Please include reproduction steps and do not publicly disclose vulnerabilities before we have had a chance to respond.

Data-processing addendum requests, subprocessor updates, and procurement paperwork can be sent to the same address.

Transparency beats claims

Anything on this page can be verified in our source code. If you spot a gap, tell us — we would rather fix it than defend it.