Abrova
☰ Docs menu · Web
Coming soon. Abrova Push is coming soon. This page describes how it will work; it can’t be used yet.

Web SDK

Real-time push notifications for browsers via WebSocket + Web Push (VAPID). No Firebase dependency. Works with React, Vue, Angular, vanilla JS.

Web 0.1.12HTTPSChrome 50+Firefox 44+Safari 16+Last updated: 27 Oct 2026
Real-time via WebSocket

A persistent connection over TLS (port 443) delivers messages instantly while the tab is open

Web Push (VAPID)

Background notifications when browser is closed via service worker

Rich Notifications

Images, action buttons, badges, deep links

Topic Subscriptions

Broadcast to interest groups

Auto-reconnect

Exponential backoff handles flaky networks

Badge API + Favicon Fallback

Unified badge count across the platforms that support it

Localization Support

Notification title/body localizations picked by the browser language

Framework-Agnostic

React, Vue, Angular, Svelte, vanilla JS

Installation#

The SDK installs from Abrova Center in two steps.

  1. Point the @abrova scope at Abrova Center in your project's .npmrc:
# .npmrc (in your project root)
@abrova:registry=https://center.abrova.ir/api/packages/abrova/npm/
  1. Install the package:
bash
npm install @abrova/push-web@^0.1.12

Without a bundler

The package also ships a ready-made browser build. Copy it into your public directory and load it from your own site:

bash
cp node_modules/@abrova/push-web/dist/index.umd.js public/abrova-push.umd.js
html
<script src="/abrova-push.umd.js"></script>

Service Worker Setup#

The Web SDK uses a service worker for background notifications (Web Push). Copy it once to your public directory:

bash
cp node_modules/@abrova/push-web/service-worker.js public/abrova-push-sw.js
HTTPS Required.

Web Push requires HTTPS. localhost works for development. Make sure the service worker file is served from the root of your public directory.

Upgrading the SDK.

Copy service-worker.js again whenever you upgrade @abrova/push-web. An older worker keeps working, but misses fixes such as SDK version reporting on re-subscription.

Quick Start#

typescript
import AbrovaPush from '@abrova/push-web';

const abrovaPush = new AbrovaPush({
  apiKey: 'ab_live_your_api_key',
});

abrovaPush.onMessage((message) => {
  // message.title, message.body, message.data
});

abrovaPush.onConnectionState((state) => {
  // 'connecting' | 'connected' | 'disconnected' | 'error'
});

abrovaPush.onRegistered((deviceId) => {
  // Device registered with the Abrova backend
});

// Register the device — this also requests notification permission.
// Once permission is granted, call register() on every page load to keep the
// device's subscription, app version and last-seen time current.
const deviceId = await abrovaPush.register({ userId: 'user_123' });

Callbacks#

All event handlers return an unsubscribe function. Call it on teardown.

typescript
// Foreground messages
const unsub = abrovaPush.onMessage((message) => {
  // message.title, message.body
});

// Connection state changes
abrovaPush.onConnectionState((state) => {
  // 'connecting' | 'connected' | 'disconnected' | 'error'
});

// Notification clicked while the browser was in background
abrovaPush.onNotificationClick((message, action) => {
  if (message.deepLink) {
    window.location.href = message.deepLink;
  }
});

// Action button clicked on a notification
abrovaPush.onActionClicked((actionId, message) => {
  // actionId from the original push payload
});

// Errors
abrovaPush.onError((error) => {});
abrovaPush.onDetailedError((error) => {
  // error.code, error.message
});

// Reconnection attempts
abrovaPush.onReconnecting((state) => {
  // state.retryAttempt, state.nextRetryMs
});

// Network state changes
abrovaPush.onNetworkState((state) => {
  // state.isAvailable, state.networkType
});

// Tab visibility changes
abrovaPush.onAppState((state) => {
  // state.isVisible
});

// Clean up
unsub();

User Identification#

typescript
// Set user ID after login
await abrovaPush.setUserId('user_123');

// Clear user ID on logout — also detaches the user on the server,
// so this browser stops receiving the previous user's notifications
await abrovaPush.clearUserId();

// Register with user ID in one call
await abrovaPush.register({ userId: 'user_123' });

Topics#

typescript
await abrovaPush.subscribeTopic('news');
await abrovaPush.subscribeTopic('promotions');

await abrovaPush.unsubscribeTopic('promotions');

Badge Management#

Unified badge API — uses the native Badge API where available and falls back to drawing on the favicon.

typescript
abrovaPush.setBadgeCount(5);
abrovaPush.clearBadge();
const count = abrovaPush.getBadgeCount();

Message Inbox#

Server-stored messages users can revisit, with live updates and an offline cache (0.1.6+). See the Inbox guide.

typescript
abrovaPush.inbox.onMessage((message) => render(message));
abrovaPush.inbox.onUnreadCountChange((count) => setBadge(count));

const { messages, unreadCount } = await abrovaPush.inbox.getMessages({ status: 'unread' });
await abrovaPush.inbox.markAsRead(messages[0].id);
await abrovaPush.inbox.markAllAsRead();

Analytics#

Forward SDK events to your analytics service:

typescript
abrovaPush.setAnalyticsHandler((event, properties) => {
  analytics.track(`abrova_push_${event}`, properties);
});

// Disable if needed (e.g. for GDPR)
abrovaPush.disableAnalytics();

Log Levels#

typescript
import { AbrovaPushLogLevel } from '@abrova/push-web';

abrovaPush.setLogLevel(AbrovaPushLogLevel.DEBUG);   // Development
abrovaPush.setLogLevel(AbrovaPushLogLevel.ERROR);   // Production

Available levels: NONE, ERROR, WARNING, INFO, DEBUG, VERBOSE.

Utilities#

typescript
const connected = abrovaPush.isConnected();
const deviceId = abrovaPush.getDeviceId();
const network = abrovaPush.getNetworkState();
const appState = abrovaPush.getAppState();
const initialMessage = abrovaPush.getInitialMessage();

// Static checks
AbrovaPush.isSupported();
AbrovaPush.getPermissionStatus();

// Unregister the device
await abrovaPush.unregister();

Configuration Options#

typescript
const abrovaPush = new AbrovaPush({
  apiKey: 'ab_live_your_api_key',
  serviceWorkerPath: '/abrova-push-sw.js',
  autoRegisterServiceWorker: true,
  maxReconnectAttempts: 0,
  logLevel: AbrovaPushLogLevel.ERROR,
  appVersion: '2.0.0',
  autoRefresh: true,
});
OptionTypeRequiredDescription
apiKeystringYesYour project API key (`ab_live_...`) from Abrova Console
serviceWorkerPathstringNoPath to the service worker file (default: "/abrova-push-sw.js")
autoRegisterServiceWorkerbooleanNoAuto-register the service worker (default: true)
maxReconnectAttemptsnumberNoMax reconnect attempts after the connection drops; 0 = no limit, backing off up to 60 s (default: 0)
logLevelAbrovaPushLogLevelNoNONE / ERROR / WARNING / INFO / DEBUG / VERBOSE (default: ERROR)
appVersionstringNoYour web app version, shown per device and usable as a segment filter
vapidPublicKeystringNoFallback VAPID public key for Web Push; the key fetched from the server takes precedence, so normally leave unset
autoRefreshbooleanNoOn page load, silently re-register a browser that registered before, at most once every 24h or sooner when the push subscription, appVersion, SDK version or user changed. Never prompts for permission (default: true)
inAppInAppConfigNoIn-app message options: enabled, display ('auto' | 'manual'), autoTrigger, bannerPosition, locale. The in-app API is on `abrovaPush.inApp`

The installed SDK version is exported as SDK_VERSION:

typescript
import { SDK_VERSION } from '@abrova/push-web';

Delivery Tracking

Notifications are confirmed as delivered automatically: Web Push arrivals by the service worker, and messages received over the real-time connection while the page is open by the SDK. No code needed. See Delivery Receipts.

Usage Without a Bundler#

For sites that don't use a bundler, load the browser build you copied in step 1:

html
<!DOCTYPE html>
<html>
<head>
  <title>My App</title>
</head>
<body>
  <script src="/abrova-push.umd.js"></script>
  <script>
    const abrovaPush = new AbrovaPush.default({
      apiKey: 'ab_live_your_api_key',
    });

    abrovaPush.onMessage(function(message) {
      // message.title, message.body
    });

    abrovaPush.register().then(function(deviceId) {
      // Device registered
    });
  </script>
</body>
</html>

API Reference#

AbrovaPush — Initialization & Lifecycle

OptionTypeRequiredDescription
constructor(config)--Create the SDK instance
register(options?)--Register the device + request notification permission. Call on every page load once permission is granted
unregister()--Unregister the device
isConnected()--Check whether the WebSocket connection is open
getDeviceId()--Get the current device identifier
getNetworkState()--Get the current network availability + type
getAppState()--Get the current tab visibility state
getInitialMessage()--Get the message that opened the page from a notification tap

abrovaPush.inbox — Message Inbox (0.1.6+)

OptionTypeRequiredDescription
getMessages(filter?)--Fetch messages (status, category, limit, offset, locale)
getMessage(id)--Fetch one message
getCachedMessages()--Cached messages, no network
getUnreadCount()--Unread count from the cache
fetchUnreadCount()--Unread count from the server
markAsRead(id)--Mark one message read
archiveMessage(id)--Archive one message
deleteMessage(id)--Delete one message
markMultiple(ids, status)--Set status on several messages ('read' | 'archived' | 'deleted')
markAllAsRead()--Mark every message read
clearCache()--Drop the local cache
onMessage(cb)--New inbox message; returns an unsubscribe function
onStatusChange(cb)--A message status changed
onUnreadCountChange(cb)--Unread count changed — use it for a badge

Static methods

OptionTypeRequiredDescription
AbrovaPush.isSupported()--Check whether the browser supports notifications + service workers
AbrovaPush.getPermissionStatus()--Current Notification.permission value

Callbacks

All callbacks return an unsubscribe function.

OptionTypeRequiredDescription
onMessage(callback)--Foreground push received
onConnectionState(callback)--WebSocket connection state changed
onRegistered(callback)--Device registration completed
onNotificationClick(callback)--User clicked a background notification
onActionClicked(callback)--User clicked an action button
onError(callback)--Error object
onDetailedError(callback)--Structured error with code + message
onReconnecting(callback)--Reconnection attempt state
onNetworkState(callback)--Network availability changed
onAppState(callback)--Tab visibility changed

User & Topics

OptionTypeRequiredDescription
setUserId(id)--Set the current user identifier
clearUserId()--Async. Clear the user identifier and detach the user on the server
subscribeTopic(topic)--Subscribe to a topic
unsubscribeTopic(topic)--Unsubscribe from a topic

Badge + Analytics + Logs

OptionTypeRequiredDescription
setBadgeCount(count)--Set the app badge count
clearBadge()--Clear the app badge
getBadgeCount()--Get the current badge count
setAnalyticsHandler(callback)--Forward SDK events to your analytics service
disableAnalytics()--Stop forwarding SDK events
setLogLevel(level)--Set the SDK log verbosity

Browser Support#

  • Chrome 50+ (Desktop & Android)
  • Firefox 44+
  • Edge 17+
  • Safari 16+ (macOS only — iOS does not support Web Push)
  • Opera 37+

Requirements#

  • HTTPS required (localhost works for development)
  • Service worker file must be in the public root directory
  • User must grant notification permission via the browser's permission prompt

Best Practices#

Initialize Once Per Page Load

Create one AbrovaPush instance per page — re-creating it on every render leaks listeners

Request Permission in Context

The first time, call register() from a UI affordance where the user understands why notifications matter. After permission is granted, call it on every page load

Check Static Support First

Call AbrovaPush.isSupported() before showing notification UI — some browsers / private modes don't support Web Push

Set User ID After Login

Call setUserId() once authentication completes so notifications target the right account across devices

Unsubscribe Listeners on Teardown

Every callback returns an unsubscribe function — call it when components unmount to prevent stale handlers

Handle the Initial Message

When the user clicks a notification while the tab is closed, getInitialMessage() returns the payload on page load — use it for deep linking

Was this page helpful?
Report a problem