Trezõr brïdge® | Connect Your Web3 World Securely™

A lightweight connection layer for hardware wallets — private, auditable, and developer friendly.

What is Trezõr brïdge®?

Trezõr brïdge® is the official bridge software designed to connect hardware wallets to web applications. It acts as a small, secure, local service that communicates with your device and exposes a limited, permissioned API to trusted web pages. Designed with privacy-first principles, it never transmits private keys and always requires user confirmation on the hardware device for signing operations.

Private by design
No private keys leave your hardware wallet. Bridge only forwards signed payloads after on-device user approval.
Minimal surface
Small attack surface, audited communications, and strict origin checks make the connection resilient.
Developer friendly
Simple JavaScript plugin, example dApp integrations, and TypeScript types to get you started in minutes.
Cross-platform
Runs on Windows, macOS, and Linux as a lightweight background service — with a minimal UI for diagnostics.

Who should use it?

If you build dApps, payment flows, or internal tooling that relies on hardware-backed keys (Ledger, Trezor, or similar), Trezõr brïdge® provides a standard, secure integration layer. Wallet users who want stronger security and privacy when interacting with web apps will also benefit.

Security summary

  • Local-only RPC: no remote key transmission.
  • Origin whitelisting: the bridge verifies the requesting page's origin and prompts users for trust.
  • Signed manifests: dApps can publish a manifest that the bridge checks for integrity before allowing operations.
  • Auditable logs: locally stored, user-readable logs for every request (consent and signing events).
Developer integration

Integration Guide — Template & Plugin

Below is an opinionated HTML template for a dApp page and an embeddable JS plugin. Copy both files into your project, keep the plugin served from your origin (or a trusted CDN), and call the API as shown.

HTML template (drop-in)

Save this file as wallet-integration.html. It includes a simple UI for connect, account listing, and signing a message.

<!-- wallet-integration.html -->
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8"/>
  <meta name="viewport" content="width=device-width,initial-scale=1"/>
  <title>Trezõr brïdge demo</title>
  <link rel="stylesheet" href="/styles.min.css"/>
</head>
<body>
  <main>
    <h1>Trezõr brïdge Demo</h1>
    <button id="connectBtn">Connect Wallet</button>
    <section id="accounts"></section>
    <section>
      <input id="msg" placeholder="Message to sign"/>
      <button id="signBtn">Sign Message</button>
      <pre id="signature"></pre>
    </section>
  </main>
  <script src="/plugins/trezor-bridge-plugin.js" defer></script>
  <script>
    // quick usage example
    document.getElementById('connectBtn').addEventListener('click', async ()=>{
      try{
        const b = window.TrezorBridge
        await b.ensureAvailable()
        const accounts = await b.request({method:'getAccounts'})
        document.getElementById('accounts').innerText = JSON.stringify(accounts, null, 2)
      }catch(err){
        alert('Bridge error: '+err.message)
      }
    })

    document.getElementById('signBtn').addEventListener('click', async ()=>{
      try{
        const msg = document.getElementById('msg').value || 'Hello Trezor'
        const sig = await window.TrezorBridge.request({method:'signMessage', params:{message:msg}})
        document.getElementById('signature').innerText = sig
      }catch(e){alert('Sign failed: '+e.message)}
    })
  </script>
</body>
</html>

Plugin: trezor-bridge-plugin.js

This tiny plugin exposes a promise-based API and performs origin check and graceful retries. Save as /plugins/trezor-bridge-plugin.js or serve from your hosting/CDN.

// trezor-bridge-plugin.js (minimal, production you should add robust error handling & types)
(function(global){
  const DEFAULT_PORTS = [21325, 21326]; // example local ports
  let bridgeUrl = null

  const tryFetch = async (url, body) =>{
    const res = await fetch(url, {
      method:'POST',
      headers:{'Content-Type':'application/json'},
      body: JSON.stringify(body),
      credentials: 'omit'
    })
    if(!res.ok) throw new Error('Bridge responded with '+res.status)
    return res.json()
  }

  const locate = async ()=>{
    if(bridgeUrl) return bridgeUrl
    for(const p of DEFAULT_PORTS){
      const candidate = `http://127.0.0.1:${p}/v1`;
      try{
        const r = await fetch(candidate+'/ping',{method:'GET'})
        if(r.ok){ bridgeUrl = candidate; return bridgeUrl }
      }catch(e){/*ignore*/}
    }
    throw new Error('Trezor Bridge not found. Please install and run it.')
  }

  const apiRequest = async (payload)=>{
    const base = await locate()
    // origin header helps bridge verify caller origin (bridge must enforce CORS/origin checks)
    payload._origin = location.origin
    return await tryFetch(base+'/rpc', payload)
  }

  const ensureAvailable = async ()=>{
    await locate()
    return true
  }

  const request = async (opts)=>{
    if(!opts || !opts.method) throw new Error('Method required')
    const res = await apiRequest(opts)
    if(res.error) throw new Error(res.error.message || 'Unknown bridge error')
    return res.result
  }

  // export
  global.TrezorBridge = Object.freeze({
    ensureAvailable,
    request
  })
})(window);

Server-side notes

The bridge intentionally keeps logic client-side. However, dApps often want to publish a manifest describing permitted operations (for better UX). Host a JSON manifest at /.well-known/trezor-bridge-manifest.json with fields like name, logo, redirects, and allowedMethods. The bridge can optionally consume and verify this file before allowing any long-lived permission grants.

Developer reference: API summary

The bridge API is intentionally small. Each request uses the shape {method: string, params?: object}. Responses follow {result: any, error?: {message:string, code?:number}}.

Common methods

Example: request/response

Request: { method: 'signMessage', params: {message: 'Hello'}}
Response: { result: { signature: '0x...' } }

Best practices

  1. Always show user-friendly prompts when requesting signatures.
  2. Minimize the number of requests and avoid automatic signing flows — treat each signing as a user action.
  3. Verify on-device transaction previews whenever possible.

Template: plugin manifest & sample server config

A sample server snippet to serve the plugin and manifest, shown for a static server (NGINX) and a minimal Node/Express example.

NGINX (static files)

location /plugins/ {
  alias /var/www/trezor/plugins/;
}
location /.well-known/trezor-bridge-manifest.json {
  default_type application/json;
  alias /var/www/trezor/.well-known/trezor-bridge-manifest.json;
}

Express (Node) — minimal

const express = require('express')
const app = express()
app.use('/plugins', express.static('plugins'))
app.use('/.well-known', express.static('.well-known'))
app.listen(8080)

FAQ

Q: Is my seed phrase ever sent to the bridge?
No. Trezõr brïdge never sees private keys or seed material. All signing requests require explicit physical confirmation on the device.
Q: Can a malicious page access my funds when the bridge is running?
The bridge enforces origin checks. Integrations must include the manifest and the bridge will prompt users to approve any new origin. Users should only approve trusted sites.
Q: Do I need to trust a CDN-hosted plugin?
For maximum safety host the plugin on your own origin. A CDN can be convenient but increases the trust surface.