@beacio/detect
Detect the WebBLE Safari Web Extension on iOS and guide users through install — extension state checks, an install banner, and a React provider.
Requires iOS 26.0+ Safari with the WebBLE app for the extension path. On browsers with native Web Bluetooth (Chrome, Edge) detection is a no-op.
Install
npm install @beacio/detect
Zero-config auto mode
Import once in your browser entry file. It detects the extension and, when missing on iOS Safari, shows a guided install prompt:
import '@beacio/detect/auto';
The auto entry reads an optional API key from <meta name="ioswebble-key" content="wbl_xxxxx"> or window.__IOSWEBBLE_KEY__.
Manual detection
import {
getExtensionInstallState,
isExtensionInstalled,
isIOSSafari,
} from '@beacio/detect';
if (isIOSSafari()) {
const state = await getExtensionInstallState();
if (state !== 'active') {
}
}
Install banner
import { showInstallBanner, removeInstallBanner } from '@beacio/detect';
showInstallBanner({
mode: 'sheet',
operatorName: 'FitTracker',
dismissDays: 14,
});
The banner's default CTA opens the guided setup flow at https://ioswebble.com/setup (install → enable the Safari extension → return to your page). Override with startOnboardingUrl or appStoreUrl.
Full init
import { initBeacio } from '@beacio/detect';
await initBeacio({
operatorName: 'FitTracker',
banner: { mode: 'sheet' },
onReady: () => console.log('extension active'),
onInstalledInactive: () => console.log('installed, needs Safari activation'),
onNotInstalled: () => console.log('not installed'),
});
State changes also dispatch a ioswebble:statechange CustomEvent on window.
React
import { BeacioProvider, useBeacio } from '@beacio/detect/react';
export default function Layout({ children }) {
return <BeacioProvider>{children}</BeacioProvider>;
}
function Status() {
const { state } = useBeacio();
return <span>{state}</span>;
}
Related packages
Docs: https://ioswebble.com/docs.md · Setup guide: https://ioswebble.com/setup
License
MIT