Recense
Pricing Docs Log in

Verify for yourself

Last updated: May 2026

The claim

On Recense's local-auth deployments, after you sign in, no survey data leaves your browser to a Recense-controlled server. AI conversations go directly from your browser to the provider you authenticate with using your own API key. You can verify this from the browser without trusting our word.

How the guarantee is enforced

Three independent layers stack on top of each other. Each one alone would block survey data from reaching a Recense server; the combination is what makes the claim reproducible.

Layer 1 — Server-side 403

Every request to /api/* on a local-auth deployment is rejected at the SvelteKit hook with a 403 response, except for one endpoint that returns the published policy itself (/api/v1/local-only-policy). Two narrow exceptions exist for specific build variants — /api/v1/org/byok when the build flag PUBLIC_ORG_BYOK_ENABLED is on, and /api/v1/dev/* when the dev server is running. The Canva design-partner build ships with both flags off.

Layer 2 — Client-side network guard

At browser bootstrap, the app patches every outbound network primitive (fetch, XMLHttpRequest, WebSocket, EventSource, navigator.sendBeacon) and routes each call through a policy classifier. Any request that doesn't match the published allow-set throws synchronously. Because the patches install before any feature code runs, no application path can issue a network call without going through the guard.

Layer 3 — Content Security Policy

The HTTP response sets a Content-Security-Policy header that restricts connect-src to a closed list. In local-auth mode the list is: your own origin, your Supabase auth host, the four AI provider hosts you may BYOK to, and four ws://localhost origins for the optional desktop bridge. Any other destination is blocked by the browser before the network guard or the application code has a say.

Verify it in five minutes

Step 1 — Inspect the CSP header

  1. Open the local-auth Recense URL in a fresh browser profile.
  2. Open DevTools → Network tab → reload the page.
  3. Click the document request (the one whose Type is document).
  4. In Response Headers, find Content-Security-Policy.
  5. Read the connect-src directive. The full list of allowed destinations is right there. Anything not on that list is browser-blocked.

For the Canva design-partner build, the directive should resolve to:

connect-src 'self'
  <your-supabase-auth-host>
  https://api.anthropic.com
  https://api.openai.com
  https://api.fireworks.ai
  https://generativelanguage.googleapis.com
  ws://localhost:9752 ws://127.0.0.1:9752
  ws://localhost:9753 ws://127.0.0.1:9753

If you see an origin not on that list, the claim is broken — please email security@recense.ai.

Step 2 — Watch the Network tab during a real session

  1. Keep DevTools → Network open and clear it.
  2. Sign in.
  3. Import a .sav file from your machine.
  4. Build a few crosstabs.
  5. Configure a BYOK API key in Account → AI and run an agent prompt.
  6. Save your project locally and export.

Every outbound request you see should be one of:

  • Your Supabase auth host, on a path under /auth/v1/* (sign-in, sign-out, session refresh).
  • Your AI provider's API origin (only the one matching the BYOK key you entered), for the agent's API call.
  • Cloudflare's CDN origin for static assets (HTML, JS, fonts, the WebAssembly engine).

You should not see a request to a Recense-controlled origin carrying a survey payload. AI conversations go directly to the provider, not via a Recense proxy.

Step 3 — Try to break it

From the browser console, in a local-auth session, run:

fetch('https://example.com')

The call should reject synchronously with an error that names the layer that blocked it (network guard) or be blocked by the browser's CSP (which logs to the console). Either way, the request never goes out.

Step 4 — Inspect the bootstrap order

The network guard installs at module top-level in src/hooks.client.ts. Any application code that runs in the browser does so via later imports, so there is no app code that can reach the network before the guard. If you are auditing the source under a design-partner agreement, the relevant entry points are:

  • src/hooks.server.ts — Layer 1 catch-all 403.
  • src/lib/network-guard.ts — Layer 2 monkey patches.
  • src/lib/local-only-policy.ts — single source of truth for allow-lists, also used to render the CSP connect-src.

Two-layer enforcement

The disabled-features list in the Proposal Appendix B names ten flags. Six of them (sentry, builtin-agent, billing-heartbeat, account, support, sharing) are checked directly at the feature surface — search the frontend for isLocalOnlyFeatureDisabled to find the gate. Four (hosted-mcp, cloud-projects, cloud-datasets, marketing-network) have no dedicated check at their feature surfaces; their corresponding network calls are blocked by the server catch-all 403 (Layer 1) and the client network guard (Layer 2) above. We list them in the disabled-features array so the published count stays consistent with the Proposal and so an auditor reading the source sees the intent. A reader grepping for the flag name lands on this comment, not on a dead constant.

What would break the claim

  • An origin appearing in connect-src that isn't on the published list.
  • A successful outbound request to any host other than Supabase auth, your BYOK provider, or Cloudflare CDN, during normal product use.
  • The build flag PUBLIC_LOCAL_ONLY_PROFILE set to anything other than local-auth on the Canva deployment.
  • A new /api/* route landing without an explicit allow-list entry. The repository CI runs an enumeration test that fails when this happens, but you can also confirm in the browser by issuing a request and seeing the 403.

Disclosed exceptions

  • Single GET to /api/v1/local-only-policy. Returns the policy itself so the client can render the same disabled-features list a reader sees here.
  • Single GET / POST to /api/v1/org/byok. Disabled by build flag on the Canva deployment. When enabled, it stores an organisation-shared encrypted BYOK provider key — passphrase-derived AES-GCM ciphertext only, never plaintext.
  • ws://localhost:9752–9753. Local desktop bridge for users who run the optional Recense MCP companion process. The browser will not accept incoming connections from any other origin.

Questions

If anything in your verification doesn't match the published claim, contact security@recense.ai. Reproducible counter-examples are gratefully received.

Recense

AI-native survey analysis.

Product

Home Pricing Documentation

Company

About Contact LinkedIn

Legal

Security Privacy Terms Cookies Manage cookies

© 2026 Recense. All rights reserved.