JavaScript integration
This guide walks you through wiring ReachBell into a plain HTML or JavaScript site — no framework, no build step. By the end you'll have an opt-in prompt, a registered subscriber, and a working prompt()/identify()/tag() flow.
What you'll need
- An HTTPS site. Service workers refuse to register on plain HTTP, so localhost is fine for development but production must be served over TLS.
- Your project's API key from the dashboard's integration page (it looks like
rb_live_…). - The
reachbell-sw.jsservice worker file, downloadable from the same integration page.
1. Add the SDK script
Drop the loader into the <head> of every page you want push enabled on. The defer attribute keeps it from blocking render.
<script src="https://app.reachbell.com/reachbell.js" defer></script>The script registers a global ReachBell object once it parses. Anything you call before DOMContentLoaded should be queued inside a listener so the global is guaranteed to exist.
2. Initialize the SDK
ReachBell.init() configures the SDK and registers the service worker. Call it once per page load, as early as you can after DOMContentLoaded.
<script>
window.addEventListener("DOMContentLoaded", () => {
ReachBell.init({
apiKey: "rb_live_yourkey",
apiUrl: "https://api.reachbell.com",
autoPrompt: true,
});
// init() returns immediately and bootstraps (config + service worker) in
// the background. If you need to wait for that to finish, await the promise:
// await ReachBell.ready;
});
</script>Init options
apiKey— required. Identifies your project.apiUrl— optional. Defaults tohttps://api.reachbell.com. Override only if you're on a self-hosted or regional deployment.autoPrompt— optional boolean. Whentrue, the SDK arms a one-shot user-gesture listener and triggers the soft prompt on the user's first click, tap, or keypress. Chrome 80+ and other Chromium browsers refuse to show the native permission dialog without a user gesture, so this is the safest default.
The SDK doesn't throw for expected failures.
init()returnsvoidand bootstraps in the background — awaitReachBell.readyif you need to know it finished. The methods that hit the network resolve with a structured result instead of throwing:prompt()→{ success, token?, reason? }, andidentify()/tag()→{ ok, reason? }. Inspect those and log failures rather than wrapping every call in try/catch.
3. Drop the service worker at the root
Download reachbell-sw.js from the dashboard's integration page and place it at the root of your site:
https://yoursite.com/reachbell-sw.js
This is non-negotiable. A service worker's scope is bound to the path it's served from. Serving the file from /static/sw/reachbell-sw.js would scope it to that subfolder, and push subscriptions registered under that scope would not fire for pages outside it. Root placement gives the SW scope over your entire origin.
Confirm it's reachable by visiting the URL directly in your browser before going further.
4. Trigger the prompt manually
If autoPrompt is too aggressive for your UX, set it to false and trigger the prompt yourself — typically from a "Get notified" button.
document.querySelector("#enable-push").addEventListener("click", async () => {
const result = await ReachBell.prompt();
if (result.success) {
console.log("Subscribed. Token:", result.token);
} else {
console.warn("Prompt declined or failed:", result.reason);
}
});ReachBell.prompt() shows the soft prompt configured in the dashboard, then escalates to the browser's native permission dialog if the user accepts. On success it resolves { success: true, token }; on failure { success: false, reason } — common reason values are permission_denied, push_not_supported, sdk_not_initialized, user_declined_soft_prompt, and push_subscribe_failed_*.
You can also check the current permission state directly off the Notification API before calling prompt():
if (Notification.permission === "granted") {
// Already subscribed — skip the soft prompt.
} else if (Notification.permission === "denied") {
// User blocked us. The native dialog will not re-prompt.
} else {
await ReachBell.prompt();
}5. Identify the subscriber
When a user logs in, link their device subscription to your internal user ID. This lets you target sends by user ID instead of by raw subscription endpoint.
const result = await ReachBell.identify("user_4827");
if (!result.ok) {
console.warn("identify failed:", result.reason);
}Calling identify() is idempotent. The same external ID across multiple devices links them all to one logical subscriber in the dashboard.
6. Tag the subscriber
Tags are flat string labels used for segmentation. Pass an array — tags are additive, so each call adds these labels to the device's existing tag set rather than replacing it.
await ReachBell.tag(["premium", "beta-tester"]);To remove a tag, call POST /subscribers/untag (see the Subscribers API). The dashboard's segment builder reads these tags directly. See the Segments guide for the targeting rules they unlock.
Full working example
A minimal but complete HTML page with init, a manual prompt button, and identify on login.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>ReachBell demo</title>
<script src="https://app.reachbell.com/reachbell.js" defer></script>
<script>
window.addEventListener("DOMContentLoaded", async () => {
ReachBell.init({
apiKey: "rb_live_yourkey",
autoPrompt: false,
});
document
.querySelector("#enable")
.addEventListener("click", async () => {
const r = await ReachBell.prompt();
document.querySelector("#status").textContent = r.success
? "Subscribed"
: `Failed: ${r.reason}`;
});
document.querySelector("#login").addEventListener("click", async () => {
const id = document.querySelector("#user-id").value.trim();
if (!id) return;
const r = await ReachBell.identify(id);
if (!r.ok) console.warn("identify failed:", r.reason);
});
});
</script>
</head>
<body>
<h1>Notifications demo</h1>
<button id="enable">Get notified</button>
<p id="status"></p>
<hr />
<input id="user-id" placeholder="Your internal user ID" />
<button id="login">Link this device</button>
</body>
</html>What's next?
- Read the Concepts page for the org/project/subscriber data model the SDK maps to.
- Manage the same audience server-side with the Server SDK (
@reachbell/node) on Node backends — it wraps the Subscribers API, which you can also call directly from any language. - Build a welcome flow with the Automation guide.