Skip to main content
The Quickstart gets a connection working. This page builds the thing you would actually ship, and shows how little of it is Crosslink-specific: a host, a list of capabilities, and a phone page that starts at crosslink.onConnected(rpc).

1. Project

One dependency. The browser SDK is served to your pages by the host, so there is no bundler and nothing to build.

2. Capabilities first

Decide what a paired phone may do before writing a handler. Every capability is a promise to the user in the pairing prompt, so name them for what they let someone do, not for the function they call.
risk drives the default policy: low may be auto-granted, medium and above require a human decision. See Capabilities and RPC.

3. The host

host.mjs:
lan.bind: "all" matters: the phone dials the address in the QR, and loopback on the phone means the phone itself.

4. The phone page

mobile/index.html is your UI and one callback. No pairing screen, no SAS prompt, Service Worker, or manifest belongs in this file — Crosslink owns those pieces wherever the browser/deployment supports them. By the time onConnected fires, pairing and authorization are complete; it fires again after every reconnect.

5. Run it

Show the pairing QR on a desktop page with createPairingCard, scan it with a phone on the same Wi-Fi, and Crosslink runs pairing and the handoff into your page. This default plain-HTTP LAN path is direct development access, not the installed-PWA mode.

Serving the client from the host

The single-port arrangement above is deliberate, and worth keeping even as the app grows:
  • One mapping. Remote access forwards exactly one port. A page on port 3000 and a socket on port 54676 needs two, and the second one is the one people forget.
  • One development origin. The host-served page and socket need no cross-origin exceptions. That convenient LAN origin is still today’s desktop address, not a durable installed-app identity.
  • No route mismatch. A page that loads cannot then fail to reach the socket, because they are the same listener.
If your UI is served by a dev server during development (Vite, for example), add its origin to lan.allowedOrigins rather than moving the socket.

Making it installable

Your mobile application code does not change: Crosslink already generates the manifest, Service Worker, and icons from application metadata. The deployment does change: use a stable HTTPS bootstrap origin and a permitted WSS route. The QR points at an https/http page rather than a crosslink:// URI because an iPhone camera has no handler for a custom scheme. What decides whether an install actually behaves like an app is the origin the phone loaded. On a plain-HTTP LAN address the browser will not register a service worker, so Add to Home Screen produces a bookmark with no cached offline screen. Your host says which case you are in:
To make installs durable, publish Crosslink’s static bootstrap once and point pairing.bootstrapUrl at it:
Durable Origins covers the trade-offs, including the one that matters most: a published https origin cannot use ws://, so it needs a relay or a tunnel to reach your machine.

Next

Capabilities and RPC

Designing the permission surface and the method surface

Connection Modes

Same Wi-Fi, relayed, or reachable from anywhere

Production Checklist

What to fix before other people run this