Stable origin and current desktop are different addresses
Installed application origin != current desktop network address.Three browser rules
A service worker needs a secure context. No worker means no cached shell, which means an offline launch shows the browser’s own cannot connect to server page instead of Crosslink’s reconnect screen. Secure meanshttps://, or
localhost / 127.0.0.1.
crypto.subtle needs a secure context too. On an insecure origin Crosslink
cannot wrap this device’s identity in a non-extractable key and falls back to
storing it in the clear.
An https:// page cannot open a ws:// socket. Browsers block it as mixed
content. So the origin that can cache an offline shell is exactly the origin
that cannot take the LAN shortcut.
That last one is the awkward part, and Crosslink does not paper over it: a
blocked route is reported as blocked rather than retried until it times out.
The two delivery modes
LAN HTTP
LAN HTTP is for local development and direct browser access while the phone can reach the desktop’s LAN address. It provides direct LAN communication, pairing, trust, and development without publishing a site. It is not a secure-context installation origin: there is no Service Worker, durable offline PWA, stable HTTPS identity, or reliable Add to Home Screen lifecycle.Secure published bootstrap
A published bootstrap is the stable HTTPS application origin. It can register the Service Worker, cache the offline shell, support installation where the browser allows it, and reopen independently of today’s desktop address. It still needs a browser-permitted route to the desktop:wss:// via a secure
tunnel or relay. An HTTPS page cannot generally connect directly to
ws://192.168.x.x because that is mixed content.
The deployment-level host diagnostic and browser runtime diagnostic answer
different questions:
sw.js; only the browser runtime can confirm registration and install support.
Capability comparison
The default LAN setup is fine for development and for a companion app used while
the desktop is running. It is not enough for an installed app that must open
when the desktop is off.
Your host tells you which row you are in:
Getting a durable origin for free
Publish Crosslink’s bootstrap as a static site. It can use ordinary static hosting and needs no application server. The host must be reachable for the first load and updates; after the Service Worker has successfully cached the shell, an installed launch can render that shell while the host is offline.https://you.github.io/your-app/) works unchanged:
The output is a self-contained static application shell. It embeds no desktop
endpoint, signaling/relay token, pairing code, device private key, trusted-device
record, or application RPC data. Publishing a new build is how bootstrap asset
updates are delivered. The writer creates/updates the listed files but does not
delete unrelated files already in the output directory. It rejects a requested
asset whose basename would overwrite a generated file (for example
sw.js) or
collide with another requested asset.
Publish it once, then point your host at it:
The catch, stated plainly
A publishedhttps origin cannot use ws://, so it cannot take the direct LAN
route. For those installs the host needs a wss:// route:
- a relay (
relayUrl) — Crosslink ships one you can self-host, and it only ever sees ciphertext; or - a tunnel (
tunnelUrl) you already run.
describeMobileDelivery() says so:
Choosing
- Building or demoing? Use the defaults. Open the mobile page on
127.0.0.1in a same-machine browser for a quick secure-context check; use a real HTTPS origin for phone installation testing. - Companion app used while the desktop is running, same Wi-Fi? The LAN origin is fine. Expect a bookmark rather than an install, and say so to users.
- Installed app that must open when the desktop is off? Publish the static bootstrap and configure a relay. This is the configuration the promise at the top of this page describes.
Static-host traffic and trust boundary
The first pairing payload is carried in the URL fragment (#pair=…), which
browsers do not send in the HTTP request. The static host receives normal asset
requests and their usual metadata (for example IP address, user agent, referrer
policy output, and requested paths). During the iOS install handoff it may also
receive an opaque, short-lived crosslink_install id and credential-free public
target metadata in same-origin cookies/requests. It does not receive the
nine-digit pairing code, trusted-device private keys, or plaintext RPC frames.
RPC travels from the installed app to the selected desktop transport. A relay,
when used, forwards Crosslink ciphertext; the static asset host is not on that
path unless the operator deliberately deploys another service at the same
domain.
The static host is not the authority that approves devices and it cannot forge
the desktop’s pinned cryptographic identity. It is part of the mobile code
supply chain: whoever can replace crosslink-sdk.js, crosslink-boot.js, or the
Service Worker can run code under the installed application’s origin and act as
that mobile client while the code runs. Host the files somewhere whose content
integrity and account access you trust. Non-extractable browser keys protect
stored ciphertext from copy-and-leave theft; they do not protect against
malicious same-origin JavaScript using the key in place.
No Crosslink-operated service is mandatory. The generated directory works on
ordinary static hosting. Runtime dependencies are selected by deployment:
A secure published bootstrap without a WSS route is installable in origin terms
but unable to reach the desktop. A deployment without signaling may reconnect
through stored stable routes, but it must not be described as dynamically
discovering a changed desktop endpoint.