Skip to main content
Most Floe transfers just work. When something goes wrong, it is almost always one of the cases below.

Sending and receiving

Floe needs WebRTC, which is unavailable in some in-app browsers (the web views embedded in Facebook, Instagram, TikTok, and similar apps). Open the link in a real browser instead: Chrome, Safari, Edge, or Firefox. Floe detects these in-app browsers and prompts you to switch.
Both peers must be present at the same time, and the connection is direct, so a few things can hold it up:
  • The sender must keep their browser tab open for the entire transfer. If the sender closes the tab, the session ends.
  • The recipient must actually open the shared link (or run floe receive). The transfer begins automatically once both sides connect.
  • On strict networks, a direct path may not be possible. Make sure Network Relay Fallback is enabled (it is on by default) so Floe can route through the encrypted relay.
Relay connections are capped at 2 GB per session to keep the service free. Direct connections have no size limit. To get a direct connection:
  • Use a standard home or personal Wi-Fi network.
  • Disconnect from any VPN.
  • Avoid strict corporate or university networks.
  • Try a personal mobile hotspot.
See The 2 GB Relay Limit for the details.
Check the connection indicator. Green (Direct) is as fast as the slower of the two connections. Amber (Relay) routes through a TURN server, so speed depends on relay load and network conditions. To force the faster direct path, follow the steps above to obtain a direct connection.
On iOS, use Download ZIP rather than downloading files individually. It is the most reliable option on Safari and iOS web views.
Short codes expire 10 minutes after the sender starts the session. After that, only the full link works, and only while the sender is still connected. Ask the sender to start a new session for a fresh code.

CLI

The CLI connects to https://api.floe.one by default. If you are using a self-hosted instance, pass --server with your signaling server URL, and make sure both the sender and receiver use the same value. See Against a Self-Hosted Server.
A browser can only join by opening the link, not by entering a short code (there is no code field in the web UI). Share the link printed by floe send with browser recipients, and the code with CLI recipients.
A VPN (such as Tailscale) or virtualization software (VMware, VirtualBox, WSL, Hyper-V) adds extra network interfaces. The CLI probes each one while establishing the connection, so a machine with several of them can spend longer on “Connecting…” before settling on the working path. The transfer still completes, and the browser app is unaffected.The CLI already skips dead auto-config interfaces automatically. If you still see slow connects, pin the CLI to your real interface by name:
Pass --iface more than once to allow several interfaces. Temporarily quitting the VPN during a transfer also resolves it.
Peers on different floe versions normally transfer fine, so a small version difference (for example v1.5.4 and v1.5.5) is never a problem. This message only appears if a release changed the transfer protocol in a way the two versions cannot bridge. Whichever side is older should update:
If you are receiving from a browser, refresh the page to load the latest web client. See Updating.

Self-hosting

Set NEXT_PUBLIC_SOCKET_URL in .env and recreate the container. No rebuild is needed, because the client reads its server address at runtime:
Check what the client is actually resolving:
An empty socketUrl means the browser will use its own origin, which is correct only when both services sit behind one reverse proxy. Otherwise confirm the URL is reachable from the end user’s browser: http://localhost:3001 only works when the browser runs on the same machine as the server. See how the client finds the server.
Set CLIENT_URL to your client’s public origin (e.g. https://app.your-domain.com). It is added to the server’s CORS allow-list. http://localhost:3000 is already allowed by default. See Production Deployment.
The server allows 30 connections per IP per 60 seconds (Socket.IO and WebSocket), 20 requests per IP per 60 seconds for TURN credentials, and 60 reports per IP per 60 seconds for the global stats counter. Behind a reverse proxy, set TRUSTED_PROXY_COUNT to the number of proxy hops so the server reads real client IPs instead of the proxy IP. See Configuration.
First check which relay option your instance uses.Managed Cloudflare TURN: confirm both CLOUDFLARE_TURN_KEY_ID and CLOUDFLARE_TURN_KEY_API_TOKEN are set in .env, then run curl http://localhost:3001/api/turn-credentials. A working setup returns turn.cloudflare.com entries with a username and credential. If it returns STUN servers only, one of the two variables is missing or the API token is invalid (roll it in the Cloudflare dashboard under Realtime, then TURN Server).Self-hosted coturn: the bundled coturn service uses host networking, so it runs on a Linux host with a public IP, a domain, and TLS certificates. On macOS or Windows with Docker Desktop, run coturn separately or on a Linux VM. Confirm that TURN_SECRET and TURN_DOMAIN in .env match coturn’s static-auth-secret and realm, then start the stack with docker compose --profile turn up -d. See TURN Relay.

Still stuck?

If none of the above helps, open an issue on GitHub with your browser and OS, whether the connection was direct or relay, and any error message you saw.