Chat that feels alive
Text, photos, videos and files, voice notes with waveforms, emoji, reactions, swipe to reply, read ticks, pinned messages, 24-hour stories, and Bubu the mascot who reacts to your group.
Papote is a playful messenger for family, friends and flatmates. An Android app, an installable web app for iPhone and computers, and a single Docker container you run at home. Messages, photos, voice notes and drawings never leave it.
Built from a complete Claude Design mockup: every screen is in the apps.
Text, photos, videos and files, voice notes with waveforms, emoji, reactions, swipe to reply, read ticks, pinned messages, 24-hour stories, and Bubu the mascot who reacts to your group.
A real drawing tool, a shared live canvas everyone paints on at once, timelapse replays, “draw over” any picture, and stickers made from drawings.
Tic-tac-toe, Connect 4, Rock-paper-scissors, Hangman, “Who said that?” from your old messages, and a live Pictionary.
Polls, location sharing without any map service, birthday confetti, a gallery with “one year ago today”, and a monthly recap with medals.
Playback speed, funny voice filters, walkie-talkie mode, and optional transcription by a Whisper container running on your machine.
A username and a password, the same on every device. Add a contact to a group in one tap, or anyone by their username; invitation codes and QR codes too. Sharing from other apps, in French or English.
Seven themes (Pastel, Starry night, Notebook, Neo-pop, Plain, Arcade, Forest) with their own fonts and shapes, colours of your choice, light or dark, and a background for each group: patterns or a photo.
Android keeps its own connection (no Firebase) and shows conversations like the other messengers: pop-up at the top of the screen and bubbles to answer anywhere. Browsers and the iPhone PWA get encrypted Web Push.
Admin with 2FA, IP allowlist, journal, automatic backups with one-click restore, 30-day trash for groups, open or invitation-only sign-up with links and QR codes, temporary passwords, new version check — and no access to group content.
Real screenshots of the web app with made-up friends. The Android app looks the same.






All you need is a machine with Docker. A reverse proxy with HTTPS is recommended (needed for the installable web app and notifications).
docker-compose.ymlservices:
papote:
image: ghcr.io/mrddream/papote:latest
container_name: papote
restart: unless-stopped
ports:
- "${BIND_ADDRESS:-127.0.0.1}:${PORT:-3000}:3000"
env_file: .env # every setting comes from .env
environment:
PORT: 3000 # inside the container
BACKUP_DIR: /backups
PAPOTE_PROFILES: ${COMPOSE_PROFILES:-}
volumes:
- ./data:/data
- ${BACKUP_HOST_DIR:-./backups}:/backups
# Optional: voice note transcription (COMPOSE_PROFILES=whisper)
whisper:
image: onerahmet/openai-whisper-asr-webservice:v1.9.1
container_name: papote-whisper
profiles: ["whisper"]
restart: unless-stopped
environment:
ASR_MODEL: ${WHISPER_MODEL:-small}
ASR_ENGINE: faster_whisper
volumes:
- ./whisper-cache:/root/.cache.env next to itADMIN_PASSWORD=a-long-password-of-your-own
PORT=3000 # 3080… if 3000 is taken
BIND_ADDRESS=127.0.0.1 # 0.0.0.0 if the proxy is elsewhere
TRUST_PROXY=loopback, uniquelocal
SECURE_COOKIES=true
TZ=Europe/Paris
GIPHY_API_KEY= # optional: GIFs
COMPOSE_PROFILES=whisper # optional: transcription
MAX_UPLOAD_MB=20
UPDATE_CHECK=trueEvery variable is explained in the README. Empty COMPOSE_PROFILES = no Whisper.
docker compose up -dOpen http://your-server:3000/web/ or the Android app, enter the server address, then a display name, a username and a password. Sign-up is open by default; in /admin you can make it invitation-only and share sign-up links or QR codes.
Download the APK from the latest release and install it. Android 8 or newer. No Google services needed. New versions install over it, and the app tells you when one is out.
Open https://your-server/web/ in Safari, Chrome, Firefox or Edge. Add it to the home screen to install it and get notifications.
GIFs through GIPHY (relayed by your server) and voice transcription with Whisper: one line each in .env (GIPHY_API_KEY, COMPOSE_PROFILES=whisper).
Browsers need HTTPS to install the web app and show notifications. Put Caddy or nginx in front of Papote: it must keep the Host header, pass WebSockets on /ws, accept uploads a bit larger than MAX_UPLOAD_MB, and connect from an address listed in TRUST_PROXY.
The certificate, WebSockets and headers are handled on their own. /etc/caddy/Caddyfile, then sudo systemctl reload caddy:
papote.example.com {
# Optional: the admin only from your local network
@admin_outside {
path /admin /admin/*
not remote_ip 192.168.0.0/16 10.0.0.0/8
}
respond @admin_outside 404
reverse_proxy 127.0.0.1:3000
}Caddy in Docker next to Papote, in the same compose file: reverse_proxy papote:3000.
/etc/nginx/sites-available/papote, with a certificate from certbot (sudo certbot certonly --nginx -d papote.example.com):
# WebSocket (/ws): upgrade only when the browser asks for it
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
listen [::]:80;
server_name papote.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on; # nginx < 1.25.1: "listen 443 ssl http2;" instead
server_name papote.example.com;
ssl_certificate /etc/letsencrypt/live/papote.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/papote.example.com/privkey.pem;
client_max_body_size 25m; # a bit more than MAX_UPLOAD_MB (20)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host; # sign-up links, QR codes, WebSocket origin check
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 1h; # the WebSocket stays open
# Optional: the admin only from your local network
location /admin {
allow 192.168.0.0/16;
allow 10.0.0.0/8;
deny all;
proxy_pass http://127.0.0.1:3000;
}
location / {
proxy_pass http://127.0.0.1:3000;
}
}Then link it into sites-enabled and run sudo nginx -t && sudo systemctl reload nginx.
To check: in /admin, the sign-up link must start with https://papote.example.com/. If it shows http:// or 127.0.0.1, the proxy isn’t passing Host or X-Forwarded-Proto, or its address isn’t in TRUST_PROXY. Nginx Proxy Manager, Docker and more in the README.
One SQLite file and a media folder on your disk. Back it up, restore it, take it elsewhere.
No analytics, no ads, no third-party scripts. GIPHY never sees your members, maps open only when you tap.
The admin page shows counts and names, never messages, photos or drawings.