# The browser extension: the tour

The extension is URnetwork inside the browser, and the ur.io web app is its
control plane: one product, two halves. This page is the deep dive: the
proxy machinery in each browser, the controls with their shipped defaults,
what the kill switch does and does not promise, and what to check when
something breaks. For the network behind it, who the providers are and what
each party can see, read the [overview](/docs/overview). For store links,
sign-in, and first connect, start with
[getting started in the browser](/docs/getting-started-browser).

The framing to keep, always: **this is a browser proxy, not a VPN.** A proxy
is a middleman that fetches sites for the browser, so sites see its address
instead of yours. The extension configures the browser's own proxy settings,
so it governs exactly what that browser sends, no more. Covered: every tab
and window of that browser, incognito too, on Chromium always and on Firefox
once you allow it in Private Windows. Not covered: other browsers, your mail
app, system updates, everything else, unprotected and unbroken alike.
Install it per browser; whole-device coverage is the URnetwork apps' job
(Android, iOS, macOS, Windows, Linux): same account, same kill switch, one
layer down.

![The extension popup](/docs-assets/connect-extension.png)

## Settings at a glance

The extension keeps its surface small on purpose. Two controls, both in the
popup:

| Setting | Default | Effect | Main cost |
|---|---|---|---|
| Kill switch | On | blocks browser traffic when the proxy drops, instead of falling back to your direct connection | tabs error during an outage |
| Geolocation override | Off | the browser's geolocation API reports your exit city instead of your real position | sites you want your real location for need it off; staying current needs an open ur.io tab |

Caveats that go with the table:

- Two app switches have no browser equivalent, by design. There is no
  **Post Quantum Encryption** here, because the extension has no
  client-to-provider session to seal; the full carve-out is under Data
  collection below. And there is no **Strong
  Anonymization** switch, because direct mode is forced off on the hosted
  proxy device the extension runs on: no provider can ever be handed your
  real address.
- The kill switch persists across browser restarts, so an outage keeps you
  blocked, not exposed, until you disconnect or the path recovers.

## How it works

The extension is Manifest V3 on every browser, but the proxy plumbing
differs, because the browsers' APIs do:

- **Chrome and Edge** (and Chromium-family browsers generally) use the
  proxy settings API. The extension installs a generated PAC script, a tiny
  rule file the browser consults to decide where each request goes, that
  sends browser traffic to your provisioned URnetwork proxy endpoints.
  Setting it claims the browser's proxy configuration, which is also why two
  proxy extensions cannot coexist (see troubleshooting). It never touches OS
  settings and undoes cleanly: disconnect reverts to direct, uninstall
  removes the claim.
- **Firefox** has no equivalent settings handoff, so it uses
  `proxy.onRequest`: the extension is consulted per request and answers with
  the whole list of provisioned proxies, so one unreachable proxy does not
  strand the request. `direct` is appended to that list only if you have
  turned the kill switch off; armed, the list ends at the last proxy and a
  full outage fails.

There is no Safari version, because Safari lacks these APIs. On Apple
devices the app covers everything, Safari included.

Browsing exits through a small window of providers at once: member devices
whose owners opted in and participate in the
[UR protocol](https://ur.xyz). "Your exit IP" is plural, and per-site
affinity keeps each site on one exit, so your bank sees one consistent
address.

The URnetwork SDK ships as WebAssembly inside the extension package.
Provisioning, location listing, and API calls all run locally. Nothing
executable is fetched at runtime; what the store reviewed is what runs.

**The web app is the extension's control plane; they are one product.** Sign
in once at [ur.io](https://ur.io) and the page and the extension talk over a
documented bridge: a short verb protocol (`SETUP`, `CONNECT`, `DISCONNECT`,
`SET_LOCATION`, kill switch, geo sync) carried by `window.postMessage`, the
only channel that works on Chrome, Edge, Brave and Firefox alike. `SETUP`
hands the signed-in session straight over, which is why setting up from the
app never asks you for an auth code. The split of labour is real: the
extension mints the proxy session and installs the browser proxy, while the
app holds the live device. Changing location in the app re-routes it with no
browser reconnect, and each surface shows what you did in the other.

**The bridge is deliberately narrow.** It runs only on `ur.io` and
`app.ur.network` pages; no other site can talk to the extension. One other
script does load on every page, the geolocation override, and it stays
inert, natives untouched, unless you turn it on (below).

Signing in requires an account, since usage is metered per account: an email
or phone code, one of ur.io's SSO options, a wallet signature, or an auth
code generated on a device you are already signed in on. The email-free
routes here are the wallet and the auth code; the one-tap email-free Instant
Account is created in the phone and desktop apps, and the extension picks
that account up like any other. Free is a daily data allowance; Pro a large
monthly one ($5/month or $40/year; current numbers at ur.io/products).

## Kill switch semantics

What it does: if the proxy connection drops while the kill switch is on, the
extension blocks the browser's traffic instead of letting the browser
quietly fall back to your direct connection and expose your real address
mid-session.

- It is **on by default**, the one URnetwork surface that ships armed.
- Enforcement is the browser's own proxy rule: armed, it has no "otherwise
  go direct" escape hatch, so requests fail rather than fall back. It
  persists across browser restarts. You come back blocked, not exposed.
- If it triggers, only this browser stops (tabs error; the popup shows why).
  The rest of your computer never went through it.
- Turning it off means failing open: a dropped connection reverts you to
  direct browsing, visibly in the popup but silently in your tabs.
  Acceptable only where a leak is an inconvenience, not a harm.
- Scope limit: it blocks *browser* traffic, which is all an extension can
  govern; it is not a system firewall. Local addresses (localhost, printers)
  bypass on purpose, and WebRTC (in-browser voice/video) can open
  connections that ignore proxy settings, a gap in every proxy extension;
  browsers can restrict it.

## Geolocation override

Two signals: your IP address now says Amsterdam, but the browser's
geolocation API, answered from OS signals like nearby Wi-Fi, still reports
where your body is. Sites that compare the two see the contradiction. The
override fixes the second signal so both stories agree:

- **Off by default.** Nothing changes until you enable it in the popup.
- Enabled, it answers at `document_start` **in all frames**, so the
  geolocation API gives your exit location before any page script can ask,
  including in iframes trying to race it. The coordinates are the city of
  your oldest connected provider, and they reach the extension over the app
  bridge: the extension holds no device of its own, so an open ur.io tab is
  what keeps the position current.
- Disabled, it says nothing at all: the page keeps its native geolocation
  and no site is handed a fresh signal that you run an extension. Flip it
  off when you *want* sites to see your real location (maps, delivery).

## Health pings and the degraded state

While connected, the extension fetches a lightweight endpoint (`my-ip-info`
on the URnetwork API) through the proxy every five minutes, negligible even
against the free allowance. That proves the path works end to end, not just
that the settings applied:

- **Two consecutive failures**: status becomes **degraded**. You are still
  configured, but traffic is not confirmed flowing. The popup shows an
  instability indicator.
- **Three consecutive failures**: automatic reconnect, with backoff (2s
  doubling to 30s, five attempts), re-provisioning proxies as needed.
- A success at any point snaps the status back to connected. A grace period
  after connecting avoids flapping while the first connection settles.

Degraded is not a leak. You are still pointed at the proxy, and armed, a
dead path blocks rather than exposes. It is not an error to fix; it is the
extension telling you early, usually about a flaky network between you and
the proxy.

## Data collection: none

- The Firefox listing declares it in the manifest, machine-readably:
  `data_collection_permissions` is **none**. That is a store-enforced
  statement, not a privacy-page promise.
- The extension talks only to the URnetwork API to provision your proxies,
  the same calls any client makes. No analytics, no telemetry, no browsing
  history collection anywhere.
- **Host permissions differ by browser, for a reason.** On Chrome the
  extension requests access only to the URnetwork API hosts
  (`api.bringyour.com`, `api-v4.bringyour.com`); the PAC-based proxy API
  does not need to see your requests. On Firefox the extension needs
  `<all_urls>`: `proxy.onRequest` consults the extension for every request
  it might route, and Firefox requires host access for that to work. Broader
  permission there is the cost of Firefox's proxy API, not a data grab.
- **No third party has assessed the extension.** URnetwork's Android app
  passed a Leviathan Security Group MASA AL2 assessment in May 2025,
  Google's fixed security checklist for mobile apps, and an independent firm
  penetration-tested the web application and API in April–May 2025; neither covers
  the extension, and no independent audit covers the protocol or the
  operator's server code. What this page offers instead is falsifiable:
  those permissions are readable in your own installed copy, nothing is
  fetched at runtime, and the source is public. Claims you can check, not a
  certificate.

What the service keeps: your account and a per-device byte-count ledger
(that is allowances and provider metering), never destinations or URLs; a
client address held as a keyed one-way hash of your IP block rather than the
address itself; and an approximate city from a geographic lookup. Providers
egress without learning your real address, seeing only ISP-grade metadata
(site names, never pages or passwords, which stay HTTPS-sealed); websites
see only the exit.

Be exact about the middle, though. The network has three modes, and the
browser only ever occupies one of them:

| Mode | Operator sees | Provider sees | Available here |
|---|---|---|---|
| **Relayed standard** | your account and source connection, which providers you are on, and the destinations and packet bytes inside | destinations it egresses and a device/contract id, **not** your real IP | **yes: the only browser mode** |
| **Relayed sealed** | the same, but ciphertext with its timing and volume in place of destinations | as above | no: the apps' encrypt-to-the-provider session, on by default there, has no browser equivalent |
| **Direct** | less relay involvement | **your real IP** and the destinations it egresses | no: forced off on the hosted proxy device the extension runs on |

That first row is the browser position, and the contrast with the apps is
sharp rather than soft: they seal the client↔provider session by default,
and the browser has no session there to seal. It cannot have one. A browser
speaks its own proxy protocol and cannot run the network's engine, so your
client device runs remotely inside the operator, which translates between
the two protocols — a seal started from that device would begin at the
operator, the party a seal exists to blind. The implementation traded the
seal for reaching the browser at all. The guarantee here is a
storage one rather than an encryption one. Any browser proxy hands each
destination to the endpoint it dials, so the operator handles yours in
transit; what stands behind that is a proxy data path that writes no log at
all, pinned by a regression test in the open source, and a ledger with
nowhere to put a destination. The apps' **Strong Anonymization** switch is
likewise absent and likewise unneeded: with direct mode forced off, no
provider can ever be handed your real address.

For what the network itself can and cannot see once your traffic is flowing,
read [the overview](/docs/overview). The
[threat model](/docs/threat-model) goes further and names the browser path's
missing seal as one of its own failures.

## Troubleshooting

### "Failed to provision any proxy connections. Check your account."

The extension asked the API for proxy credentials and none were granted.
Almost always an account condition:

1. Confirm you can sign in at [ur.io](https://ur.io) and check your plan.
   An exhausted free daily allowance is the usual cause (it refreshes
   daily).
2. Check whether your plan's concurrent client limit is used up by other
   devices; disconnect one.
3. Sign out of the extension and back in to refresh credentials.

### "Connection lost. Please reconnect."

The health checks failed repeatedly and automatic reconnection ran out of
attempts. Your underlying network likely changed (moved networks, laptop
slept, hostile Wi-Fi). Reconnect from the popup; if it recurs on one
network, that network may be blocking the proxy ports.

### Another extension is fighting over the proxy

Only one extension can control the browser's proxy settings at a time (on
Chrome, the most recently installed one wins). Run another VPN or proxy
extension and they trade the setting back and forth, both looking broken.
The popup says so when it loses control, and `chrome://settings` names the
current holder; disable the other one. On Firefox, check for other installed
add-ons with proxy permission.

### Captive portals

Hotel and airport Wi-Fi needs you to sign in through a portal page *before*
the internet works, and with the proxy up (especially armed), the portal
cannot load. You cannot get wedged: disconnecting is local and needs no
network. Disconnect the extension, complete the portal sign-in, then
reconnect. Inherent to every proxy and VPN, not an extension bug.

### Reading the status

The popup's state indicator is the fastest diagnosis:

- **Idle**: signed in, not connected. Browsing is direct.
- **Connecting** (spinner): provisioning proxies and applying settings.
- **Connected**: configured and recently health-checked.
- **Degraded** (instability icon): configured, but health pings are
  failing; expect a reconnect if it persists.
- **Reconnecting**: automatic recovery in progress; leave it be.
- **Error**: one of the messages above, with the fix listed here.

## Where to go next

- [Getting started in the browser](/docs/getting-started-browser): store
  links, sign-in, and first connect, including the private-window note.
- [How URnetwork works](/docs/overview): the network behind the popup and
  where the providers come from.
- [FAQ](/docs/faq): plans, allowances, and account questions.
