Skip to content

Privacy and Telemetry

GiftWrapt is built for families running it for themselves. The default posture is nothing leaves your server unless you turned it on. No analytics, no usage telemetry, no error reporting, no anonymous pings.

  • No third-party error tracker is integrated. Not Sentry, not LogRocket, not Bugsnag, not Datadog, not Highlight. Errors land in your server logs (stdout, accessible via docker logs / Vercel logs / your runtime’s log viewer) and stay there.
  • No analytics SDK. No Google Analytics, no Plausible, no Posthog, no Vercel Web Analytics, not even a hit counter.
  • No “anonymous metrics” backchannel. The app does not check in with us to report version numbers, deploy counts, or anything else.

This is a deliberate design choice, not an oversight. Reporting errors to an external service is a useful operator convenience that we trade away because the cost - exfiltrating fragments of user data through stack traces, payload dumps, breadcrumbs, and source maps - isn’t justified for a family-scale wish-list app. Self-hosters running this for their household shouldn’t have to audit a telemetry config to be confident their data stays local.

When something blows up in production:

  • The error is logged to stdout via pino (src/lib/logger.ts) with the surrounding context (request id, user id where applicable, never session tokens or PII bodies).
  • The web app’s ErrorBoundary renders a generic fallback page. Server-side handlers return sanitized JSON (the mobile API uses a coded envelope, the web side returns Nitro’s generic 500 shape with no stack trace).
  • Nothing is transmitted to anyone but you.

If you hit a bug worth reporting, the manual path is the only path: grab the relevant log lines, screenshot the UI if applicable, and open an issue at github.com/shawnphoffman/giftwrapt. That’s a feature, not a bug.

There are a small number of outbound network calls. All of them are explicitly opt-in by the operator (configured via env or admin UI) and serve a feature the operator chose to enable. None are telemetry.

DestinationWhenWhatToggle
Your AI provider (Anthropic / OpenAI / etc.)Only when Intelligence / scraping features runItem titles, URLs, scraped page contentAdmin UI: AI provider settings; env AI_*
ResendOnly when email features are enabledRecipient address, email bodyAdmin UI: email settings; env RESEND_API_KEY
Your scraper provider (browserless / FlareSolverr / etc.)Only when scraping a URLThe URL being fetchedAdmin UI: scraper settings; env BROWSERLESS_URL / FLARESOLVERR_URL
Your object storage (R2 / AWS / your Garage cluster)Always, for image uploadsThe image bytes themselvesenv STORAGE_*
Vercel live.vercel.com scriptOnly on Vercel preview builds (VERCEL_ENV=preview)The page URL (for preview-comment overlay)Use a different host, or build with VERCEL_ENV unset

Notably not in the list: WebAuthn / passkey registration. Passkeys are negotiated between the browser and your operating system’s authenticator (Touch ID, Windows Hello, a YubiKey); the only network traffic is between the user’s browser and your own GiftWrapt server. No external “passkey provider” is involved.

Source of truth for outbound calls is the CSP connect-src directive in vite.config.ts. If a new dependency tries to phone home, that’s where it surfaces. As of mid-2026 the production CSP under self-host / Docker / Vercel-production is 'self'-only with frame-src 'none' - no third-party origin is allowlisted at all. Vercel preview builds open up https://vercel.live and the matching pusher WSS so the preview-comments overlay still works, and only those.

  • Session cookie (better-auth.session_token) is httpOnly, Secure over HTTPS, SameSite=Lax. Set by your own server.
  • localStorage holds UI preferences only (theme, list-view density, etc.). Never tokens. Never analytics IDs.
  • No third-party cookies. The app never embeds an external <iframe> or <script> that could set one.

Production builds do not ship source maps to the client. Stack traces in your server logs reference minified line numbers; rebuild with maps locally if you need to deobfuscate.

What if a Contributor Proposes Adding Telemetry?

Section titled “What if a Contributor Proposes Adding Telemetry?”

The position is “no, by default.” A contributor PR that wires in error tracking, analytics, or any other phone-home gets:

  • Rejected outright if it’s enabled by default.
  • Considered for inclusion only if (a) it’s strictly opt-in via env, (b) it ships with a PII-scrubbing config that’s enabled by default, (c) the docs are updated to describe what’s collected and where it goes.

Even then, the bar is high. The simple absence of telemetry is a feature this project commits to.