Three minimal pages demonstrating the three integration shapes from docs/EMBED_BUTTON_STRATEGY.md:
| File | Pattern |
|---|---|
vanilla.html |
One-line custom element |
custom-styled.html |
JS API + your own button |
react-host.html |
React app using <sendbsv-pay> |
Each page expects the wallet to be reachable at
https://wallet.sendbsv.com. To smoke-test against a local dev
wallet, override via the wallet-origin attribute (custom element) or
the walletOrigin option (JS API):
<sendbsv-pay to="alice@sendbsv.com" amount="100" wallet-origin="http://localhost:5173"></sendbsv-pay>await window.SendBSV.pay(
{ to: "alice@sendbsv.com", amount: 100 },
{ walletOrigin: "http://localhost:5173" }
);- Host page → button (yours or
<sendbsv-pay>). - Click → a popup opens at
wallet.sendbsv.com/send?widget=1&to=…&amount=…. - User reviews the send in the wallet popup, approves with biometrics.
- Popup signs, broadcasts, posts the result back, closes itself.
- Host page gets
sendbsv-success(or-declined/-error) + the JS Promise resolves.
- The host never sees or touches keys.
- Keys live only in the wallet popup origin (
wallet.sendbsv.com). postMessagebetween popup and host is verified by origin + source- canonical envelope version. See
src/widget/protocol.ts.
- canonical envelope version. See
- The host can simulate user-cancel by closing the popup; the
Promise resolves
{ status: "declined", reason: "user_cancelled" }. - Popup blockers: when
window.openreturnsnull, the result is{ status: "declined", reason: "popup_blocked" }— surface "please allow popups for this site" to the user.
| Browser | Status |
|---|---|
| Chrome 90+, Edge 90+ | ✅ |
| Safari 14+ (macOS / iOS) | ✅ |
| Firefox 79+ | ✅ |
| Opera, Brave (Chromium) | ✅ |
| Older browsers | Custom element / popup APIs may degrade; the |
JS API surfaces an error result rather than throwing. |
The wallet repo's pnpm embed:build outputs dist-embed/embed.js
(~4 KB minified, ~2 KB gzipped). The deploy pipeline copies it to
https://wallet.sendbsv.com/embed.js. Host pages reference that URL
directly — the wallet origin is the source of truth, so an upgrade
on the wallet side propagates to every host on next page-load.