We’re built not to look.
Neither can they.

§ 00 — Preamble

twiga is the wire under what you already pay for. Your IPTV provider on one end, you on the other, a relay between them. The relay passes your provider’s bytes along without decoding them, and your browser does the decoding. Not a policy on a page. The server has no decoder and no FFmpeg, so there is nothing on it that can read what you watch.

The web player is the first surface, and it's live: a stream you already pay for, playing in a browser tab with no install. The Android TV / Google TV app is in testing, not part of this beta.

How twiga works rev 2026-09-26 uptime

The whole thing, end to end.

§ 01 — In plain words

You already pay an IPTV provider for live channels. Today your TV box, or the app on your TV, talks to that provider directly. The provider sees your home IP. The app on your TV sees the unencrypted stream. Whoever runs the network in between sees the shape of both.

twiga puts a relay in the middle. You talk to the relay. The relay talks to your provider. Bytes pass through; the relay does not decode them, does not log their contents, does not hold a key to read them. The provider sees the relay's exit address, not yours. You see your channel. That is the whole product.

YOU   — browser tab, signed in
  │
  │  ① you ask for a channel
  ▼
twiga relay   — forwards the stream, never decodes it
  │
  │  ② relay opens an upstream connection for you, from twiga's exit
  ▼
YOUR IPTV PROVIDER   — sees the exit IP, not you
  │
  │  ③ provider sends the live stream back through the relay
  ▼
twiga relay   — byte-for-byte forward · 0 bytes decoded · no content logged
  │
  │  ④ stream lands in your tab
  ▼
YOU   — the browser decodes it and plays it
Fig. 0 — End to end, in four steps
  1. Bring your own provider. You hold the subscription. We are not a content service.
  2. The relay forwards bytes. A small Go service with no decoder and no FFmpeg — 0 bytes decoded server-side.
  3. Your IPTV provider sees the relay, never you. The upstream connection leaves from one of twiga's exits; your home IP is not on it.
  4. The browser decodes it in your tab. H.264 everywhere, HEVC natively where the browser supports it — and where it doesn't, we software-decode HEVC and MPEG-2 in the tab ourselves. When 'playing' shows, it's a real frame — never a black card pretending to load.

Same channels. Same provider. Same bill. Different shape of who can see what.

And the lineup tracks what your provider actually offers. New channels appear, dropped ones leave, and you run the update yourself from the menu. Keeping it true takes no notes on you: nothing in our database records what you watch. The channel lists we keep are the ones you make — My Stream, favourites and your own categories — because every screen needs them.

The cell that stayed empty.

§ 02 — The cell

Three disciplines have to meet in one place for this to exist: privacy built into the wire, a player that runs in a browser, and live IPTV that actually plays. Each is its own discipline, with its own people. The overlap stayed empty — not because it was impossible, but because building it asks for all three at once.

twiga sits in that overlap: for the privacy floor, a relay that passes your provider's bytes along without decoding them; for the player, a browser engine that drives the platform's own decoder; and for the content, your own IPTV subscription.

Privacy and good engineering were never the tradeoff. The tradeoff was who would bother.

Five things we hold to be true.

§ 03 — Theses

  1. I.

    Privacy is a property of the wire.

    Not a policy on a page. The relay has no decoder and no FFmpeg; it forwards the stream without decoding it, and 0 bytes are decoded server-side. You can see your end of it yourself: your browser's network tab shows the provider's stream arriving and being decoded in your tab.

  2. II.

    The browser is the right surface.

    Native-app mandates on TV shut out anyone who would rather not install a signed binary on their main screen to watch football. The browser stays the neutral surface — no install, no app-store gatekeeper deciding what plays. The web player is live today.

  3. III.

    The browser is the decoder.

    The engine demuxes the relayed stream, remuxes it, and hands it to the browser's own decoder through Media Source Extensions. No custom GPU pipeline to drift out of spec — the same decode path the browser uses for everything else, driven correctly.

  4. IV.

    A failure is honest, never silent.

    A stall, a gap, a re-tune — they recover without a card. 'Playing' is only ever set on a real, decoded frame read from the platform, so it can't lie over a black screen. And a codec the browser genuinely can't decode says so plainly, instead of spinning forever.

  5. V.

    You bring the stream. We're the wire.

    One source per account, the subscription you already pay for. We don't sell channels, bundle a catalog, or curate a lineup. The stream routes through twiga's exits, and the relay forwards it without decoding it. When the beta ends, you pay us in Monero, from your own wallet — no card, no ID, and nothing on file tying the payment to your account.

Where your provider login lives.

§ 04 — The vault

To relay your channels, the relay has to reach your provider — which means your provider login has to exist somewhere. The lazy version keeps it in plaintext, or under a key the server holds at rest. Those are the same thing: a key sitting on our servers is a key that can be leaked, subpoenaed, or turned. Here is what twiga does instead.

Your provider login is sealed in your browser with your key. The server stores ciphertext and opens it in memory while you’re signed in, then wipes it 30 minutes after your session goes quiet.

YOU   — your browser, adding a source
  │
  │  your provider login, typed once
  ▼
THE SEAL   — happens in your browser, not on our servers
  ├─ a key is derived from a secret you hold
  ├─ your login is encrypted locally         AES-256-GCM
  └─ the secret stays on your device
  │
  │  what reaches us at rest
  ▼
twiga   — stores ciphertext; opens it in memory only while you're signed in
  ├─ sealed blob   ciphertext at rest · opened in RAM while you're signed in
  └─ a public key  checks it's you · never decrypts

  ◆ sealed at rest, wiped on idle   ◆ a signature we can only verify
Fig. 1 — Where the seal is made, and what we keep

You enter your login once. Lose your key and your recovery code and there’s no way back in, not for you, not for us.

A media engine for the browser.

§ 05 — The player engine

The browser ships <video>, Media Source Extensions, and on iOS ManagedMediaSource. None of these is a player. They are surfaces a player has to drive.

The engine relays the live MPEG-TS stream into a worker, demuxes it, and remuxes it into fragmented MP4, which it hands to the browser through MSE. From there the browser's own decoder takes over — decode, A/V sync, present. For H.264, and HEVC the browser can play, there is no custom video decoder, no canvas, and no GPU pipeline on the path. MPEG-2, and HEVC the browser can't, take one detour: the tab decodes the video in software and re-encodes it to H.264 before the browser sees it. Still no canvas, and still nothing on the server. The engine's job is to feed the platform correctly and get out of the way.

BROWSER TAB
  │
  │  persistent HTTP GET · relayed MPEG-TS bytes
  ▼
mpegts.js   — in a Web Worker
  ├─ demux                        PAT, PMT, PES
  ├─ audio plan                   passthrough · transcode · strip
  └─ remux → fragmented MP4
  │
  ▼
MSE / ManagedMediaSource
  │
  │  the browser decodes, A/V-syncs, presents
  ▼
<video>
Fig. 2 — Where the engine sits in the page

The audio problem

Video is the easy half — H.264 plays everywhere, HEVC where the browser supports it. Audio is where IPTV gets awkward: a lot of channels ship AC-3, E-AC-3, or MP2, which most browsers won't decode. The two industry workarounds are dropping the audio entirely, or routing the stream through a server-side transcoder.

twiga does neither. When the browser can't decode the audio, the engine decodes it in the tab in WebAssembly, re-encodes it to AAC, and muxes the new audio and the original video into one fragmented MP4 on a single clock. The server still never touches the stream. When no decoder is available at all, it keeps the video and drops the audio — never a silent black screen.

AUDIO CODEC   from the demuxed stream
  │
  ▼
audio-plan( )
  ├─ AAC — or AC-3 / E-AC-3 where the platform decodes it
  │      →  PASSTHROUGH   the browser decodes it natively
  ├─ AC-3 · E-AC-3 · MP2 elsewhere
  │      →  TRANSCODE     WASM-decode → AAC → muxed into the same MP4, one clock
  └─ no decoder for it
         →  STRIP         keep the video, drop the audio — never a silent black

Video: H.264 everywhere; HEVC natively where the browser has it.
MPEG-2, and HEVC your browser can't, we software-decode in your tab.
What still can't be decoded fails honestly — it never loops.
Fig. 3 — The audio plan, per channel

The plan is decided once per channel and remembered, so a known-transcode channel skips the doomed native attempt on the next zap — which matters when a provider allows only one upstream connection at a time.

How to check the numbers

The engine is its own truth source: it reports playing only on a real decoded frame, sampled from the platform itself, so it can't claim a picture that isn't there. The live numbers — which exits are up, the Tor path, relay health — are on the status page, read straight from the relay, not cached or polished. The cold-zap target is ≤1.2 s at the 95th percentile; the floor is provider-side, since one upstream connection has to release before the next can open.

The wire that cannot read itself.

§ 06 — The blind relay

The relay is the other half. The player is browser-side; the relay is server-side. An edge network carries all twiga.tv traffic, the relay’s included. It terminates TLS at the edge, so it processes your IP address and the requests you send under its own terms as a processor — including, while you're signed in, the session copy of your vault key, and your provider login when you add a source. The relay itself has no decoder for what it forwards.

YOU   — browser, signed in
  │
  │  request a channel
  ▼
twiga relay   — Go, single service
  ├─ no decoder · no FFmpeg
  ├─ reads 4 framing bytes per TS packet   sync · adaptation flag · adaptation length · RAI
  ├─ payload never parsed, never decoded
  └─ no stream content in the access log
  │
  │  opaque bytes · whatever shape the provider speaks
  ▼
UPSTREAM PROVIDER   — sees twiga's exit IP, never you

  ◆ never decoded   ◆ only packet headers read   ◆ no content logged
Fig. 4 — The relay path
  • Relayone Go service · no decoder · no FFmpeg
  • Server-side decodenone · 0 bytes decoded
  • Frame inspectionfour framing bytes per MPEG-TS packet · payload never parsed
  • Provider seestwiga's exit address, never your home IP
  • Logging on the byte pathno access-log line for a stream URL · the relay's working log names the channel it dials, size-capped and overwritten · nothing in the database

Two paths out. Neither leads back.

§ 07 — twiga's exits & Tor

A relay that forwards blind still has to reach the outside world: for the live stream, to refresh your channel list, and to pull the guide. Each is a chance to leave a trail. We route them so the trails don't meet.

The stream and the channel-list refresh leave from one of twiga's exits. Your provider sees that exit address and nothing behind it — never your home IP. The guide goes out over Tor, from a different address again, so the request that pulls your listings never comes from your home or from your stream's exit. Your provider still knows it's your account asking; the login is in the request.

twiga relay
  │
  ├─ live stream   ──▶  TWIGA'S EXIT  ──▶  YOUR PROVIDER
  │        the provider sees the exit IP, never your home IP
  │
  └─ guide        ──▶  TOR          ──▶  GUIDE SOURCE
           guide data (EPG)
           no path back · nothing to line up against you

Two doors on purpose: the video and the data about it
never share a return address.
Fig. 5 — Two paths out of the relay

It is a deliberately boring arrangement. The interesting privacy work already happened one section up, in a relay that can't read what it forwards; this is just making sure the envelope and the postmark don't quietly undo it.

The parts we haven't finished.

§ 08 — What's not done

A manifesto that only lists what works is just marketing. Here is what doesn't, yet — said plainly, because you'd find it anyway.

  • AV1 only plays where the browser can decode it. H.264 plays everywhere; HEVC plays natively where the browser supports it, and where it doesn't, the tab decodes HEVC and MPEG-2 in software. That costs your machine more: one too slow to keep up gets an honest error instead of a stutter. AV1 has no software path, so a browser without a decoder for it gets the same honest error, not a picture.
  • There's no iPhone app, and we won't pretend one is around the corner. The web player runs today; the Android TV / Google TV app is in testing, not part of this beta. That's the list.
  • It doesn’t play your movies or series. twiga is a live-TV player; the VOD half of your line stays in your provider's app.
  • We check that audio is decoding, not how loud it is. A channel that comes through too quiet or too hot won't be caught automatically yet — loudness measurement isn't in the engine.

How to check.

§ 09 — Receipts

live infrastructure/uptime
privacy & data handling/privacy
terms — relay, not provider/terms
changelog — the honest version/journal
support & security[email protected]

You’ve seen how to check. When you’re ready, bring the line you already pay for — get started, or see the player first.