Truthbeam docs
v1.0.0
Get help
● Ship

Deployment
your server, then the stores.

Run the server on a Linux VPS with glibc, behind https, then build the app with your server's address and publish it on Google Play and the App Store.

DockerDebian (glibc)httpsapp storesPro

01Option A: Docker

The server folder has a Dockerfile based on Debian (Node.js 26, glibc). It builds the TypeScript, keeps only what production needs, runs as the unprivileged node user, stores its data in the volume /app/data, and checks /healthz every 30 seconds.

cd server
docker build -t truthbeam-server .
docker run -d --name truthbeam --restart unless-stopped \
  -p 127.0.0.1:8787:8787 \
  -v truthbeam-data:/app/data \
  --env-file .env \
  truthbeam-server

The build needs internet access: npm ci downloads the Content Credentials reader for Linux and checks its fingerprint.

Add ffmpeg for audio and video

The shipped image does not install ffmpeg. Without ffprobe the server refuses every audio and video upload ("The length of this file could not be read"); images, links, texts and e-mails work. To check audio and video, put this line in the second stage of the Dockerfile, before USER node, and build again:

RUN apt-get update && apt-get install -y --no-install-recommends ffmpeg && rm -rf /var/lib/apt/lists/*

02Option B: Node.js directly

  1. Install Node.js 26 on a Debian or Ubuntu server (not Alpine).
  2. Install ffmpeg for audio and video checks: sudo apt-get install ffmpeg.
  3. Copy the server folder to the server and run npm ci, then npm run build.
  4. Create .env with at least ADMIN_SECRET_KEY, PUBLIC_BASE_URL and TRUST_PROXY_HOPS (see Configuration).
  5. Keep it running with your process manager, for example a systemd service that runs npm start in the server folder as an unprivileged user.

The server sweeps old uploads at start and every hour, and runs its own maintenance (expired results, shared pages, counters, caches) every 5 minutes. It closes cleanly on SIGTERM.

03https in front

Put a reverse proxy such as Caddy or nginx in front of port 8787 on its own subdomain, for example checks.yourcompany.com, and set TRUST_PROXY_HOPS=1. The app needs the server at the root of that address, not under a path. A Caddy example:

checks.yourcompany.com {
  reverse_proxy 127.0.0.1:8787
}

The proxy must accept request bodies of your largest file cap plus 1 MB (about 101 MB with the defaults, see Uploads). Caddy sets no body limit by default; nginx allows 1 MB unless you raise it, for example client_max_body_size 110m;.

04Backups

Back up the data folder (the two SQLite files) and your ADMIN_SECRET_KEY. Without the key, saved provider keys cannot be read after a restore. The upload folder needs no backup: it holds files only while they are checked.

05Building the app for the stores

  1. Rename first: your name, Android application id, iOS bundle id, RC_HOST_BUNDLE_ID, App Group, icons and release signing (Rename guide).
  2. Build with your server's https address:
cd app
flutter build appbundle --release --dart-define=API_BASE_URL=https://checks.yourcompany.com
flutter build ipa --release --dart-define=API_BASE_URL=https://checks.yourcompany.com

Flutter's guides cover uploading: Android and iOS. The version comes from version: in app/pubspec.yaml (1.0.0+1); the Share Extension carries the same version.

06Privacy answers in the stores

Both stores ask what the app collects. Base your answers on what you switched on, and on these facts of the app:

  • Collected for app functionality only, not linked to the person, not used for tracking (as declared in the app's PrivacyInfo.xcprivacy): e-mails or text messages, photos or videos, audio, other user content (what the person chooses to check), a device id (the random install id) and purchase history (Pro).
  • Shared with third parties: content goes to the outside services you switched on (listed on the consent screen). Name them in your answers and your privacy policy.
  • Retention: uploads are deleted when the check ends; results after your Privacy setting (24 hours by default).
  • No accounts: no name, e-mail or phone number is collected; there is no sign-in.
  • Permissions: camera (QR codes and photos to check), photo library through the system picker, Face ID or fingerprint for the app lock.

Apple asks for clear consent before content goes to a third-party AI service. The consent screen does this and names the AI assistant's vendor or host (see Consent).

07Pro subscriptions

Pro is optional. Leave Plans → Pro plan off to ship a free app.

Google Play

  1. In Play Console, create a subscription with a base plan. Note its product id.
  2. In Google Cloud, create a service account and download its JSON key. In Play Console, Users and permissions, invite it with "View app information" and "Manage orders and subscriptions" (add "View financial data" for amounts on the Revenue page).
  3. Optional, for real-time updates: create a Pub/Sub topic for real-time developer notifications in Play Console and an authenticated push subscription to https://checks.yourcompany.com/v1/store/google-rtdn. Note its audience and service account e-mail (Google's guide).
  4. Console, Store: the product id under Pro product ids (Google Play), your Android package name, the service account JSON and, if set up, the two push fields.

App Store

  1. In App Store Connect, create an auto-renewable subscription in a subscription group. Note its product id.
  2. Optional, for real-time updates: set the App Store Server Notifications URL (version 2) to https://checks.yourcompany.com/v1/store/apple-notifications (Apple's documentation).
  3. Optional, for a second confirmation of every purchase: create an In-App Purchase key in App Store Connect and note its key id, issuer id and the .p8 file.
  4. Console, Store: the product id under Pro product ids (App Store), your iOS bundle id and, if set up, the three App Store Server API fields.

Then turn on Plans → Pro plan. The app shows Pro on a platform only when the switch is on and that platform's product ids are set. It reads the price and period from the store, shows the store's subscription terms with links to your privacy policy and terms (console, Legal; on iOS without a terms link, Apple's standard licence agreement), and offers Restore purchases. The server verifies every purchase with Google or Apple before Pro counts; the Status page shows a blocker while Pro is on without store verification.