We believe that everyone has the right to communicate privately. Anonymous, no logs, no servers
SocialTypeScript · CSSGitHub @jermaineeOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
A secure peer-to-peer chat in your web browser
Translation pending
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
We believe that everyone has the right to communicate privately.
That's why we provide otr.to, a tool that allows you to chat P2P.
In the project directory, you can run:
The page will reload if you make edits.\
You will also see any lint errors in the console.
Launches the test runner in the interactive watch mode.\
See the section about running tests for more information.
Runs the Jest test suite once.\
Use npm run test:watch while editing, or npm run test:coverage for a coverage report.Read the full README ↗Peer-to-peer chat in your web browser. Open otr.to, send the link it gives you to one person or several, and you talk over direct connections between your browsers, end-to-end encrypted. There is no account, nothing you have to install, and no history: the conversation is gone when the tab is closed.
https://otr.to/#<peer-id>.<secret>.#. If nobody answers within 15 seconds, the page says the chat
is no longer open and offers to start a new one. A link without a valid
secret, for example one that was cut off when it was shared, is refused
straight away.# to a server, so neither the signalling server
nor a TURN relay learns the key, and neither could read or forge messages
even if it got between two peers. A connection only counts as part of the
chat once its first packet decrypts.public/sw.js) keeps a copy of the page,
the script and the stylesheet, so the app opens without a connection and
browsers offer to install it. It always asks the network first, so an
online visit gets the current version, and it files every chat link under
the plain address, so the key after the # never ends up on disk.The chat itself never touches a server, but a few are needed to set it up:
0.peerjs.com) brokers the
connections. It sees the peer IDs and IP addresses and who connects to whom,
but never the secret, so it cannot read the messages.stun.cloudflare.com, stun.l.google.com) tell each browser its address
on the internet, so that devices on different networks can find a direct
route to each other. They see the IP address of whoever asks, not the chat.turn.otr.to (turn/). It sees the
IP addresses and how much is sent, but only ever relays encrypted packets,
and keeps no log of who used it.Whoever has the link can join the chat and read it. That includes the service it was shared through, such as Telegram, WhatsApp or an email provider, so share it somewhere you trust.
src/bulma.scss listsYou need Node.js 22 or newer.
git clone https://github.com/jermainee/otr.to.git
cd otr.to
npm install
npm run dev
npm run dev writes the script and the stylesheet to public/dist and
rebuilds them on every change. Serve the public folder with any static file
server to open the app, for example the one the end-to-end tests use:
node e2e/static-server.js
It listens on http://127.0.0.1:4173 (set PORT to change that). To try a
conversation, open the app in one tab and the chat link it shows in another.
| Command | What it does |
|---|---|
npm run dev | Builds in development mode and rebuilds on every change. |
npm run icons | Draws the app icons in public from the logo. |
npm run build | Builds the minified script and stylesheet in public/dist. |
npm test | Runs the Jest suite once. |
npm run test:watch | Runs Jest in watch mode. |
npm run test:coverage | Runs Jest with a coverage report in coverage/. |
npm run test:e2e | Builds the site and runs the Playwright suite against it. |
Unit tests live in src/__tests__ and run in jsdom. PeerJS is replaced by
a mock (src/__mocks__/peerjs.ts), so they never open a network connection.
End-to-end tests live in e2e and drive browser tabs through real chats
over WebRTC: the share link and its buttons, messages in both directions, a
stale link, file transfers down to the downloaded bytes, group chats of three
and four, and checks that nothing readable crosses a data channel and that the
signalling server never sees the secret. Another test holds the script back to
check that the page is styled without it, and the last ones check that Chrome
would install the app, that it opens offline, and that the secret stays out of
its cache. Only the PeerJS signalling server is stubbed
(e2e/support/signalling.ts), so the suite needs no internet connection.
Install the browser once before the first run:
npx playwright install chromium
GitHub Actions runs on every push to main and
on every pull request, in two jobs:
Deploy TURN relay runs the same checks
after every merge to main that changes turn/, then installs the relay on
the VPS.
Dependabot checks the npm packages and the GitHub Actions weekly.
index.tsx Entry point: mounts the app and the router
src/Chat.tsx Connection states, notices, file transfer and share link
src/Messages.tsx The conversation: messages, names, notices and files
src/InstallButton.tsx The navbar's install button, while the browser offers to install
src/Icons.tsx Inline SVG icons that take the text colour
src/bulma.scss The Bulma modules the app uses
src/theme.css Colour tokens and Bulma overrides for light and dark mode
src/chat.css Layout of the start page and the conversation
src/Service/Group.ts The peers of a chat and how they find and greet each other
src/Service/RoomKey.ts The chat's key: the link's secret, encryption, decryption
src/Service/ChatHelper.ts Peer IDs, chat links, nicknames, file sizes
src/Struct/ Message, packet and file transfer models
src/__tests__/ Jest tests
e2e/ Playwright tests and the static server they use
public/ Static site: index.html, manifest, service worker, icons and the bundle
scripts/icons.js Draws the app icons from the logo
turn/ The TURN relay: coturn configuration and its deploy
npm run build produces a fully static site in public. Upload that folder
to any static host. The app only uses the root path, so no rewrite rules are
needed.
The TURN relay deploys itself to its VPS from GitHub Actions; the one-time
setup is in turn/README.md.