Push Notifications
Enable real-time push notifications in your application using Sphere's notification service. Keep your users informed about transactions, payments, and important account activities through browser push notifications.
Overview
The Sphere notification system provides a seamless integration with Webpushr to deliver push notifications to your users. This feature enables:
- Real-time Updates: Instant notifications for transactions, payments, and account activities
- Multi-device Support: Users can enable notifications on multiple devices
- Simple Integration: Easy-to-use SDK methods for managing notifications
- Flexible Messaging: Send custom notifications with titles, messages, and target URLs
How It Works
The notification system operates through a simple flow:
- Dashboard Configuration: Set up Webpushr credentials in your Sphere Dashboard
- Frontend Integration: Add Webpushr script to your application
- User Permission: Request notification permission from users
- Registration: Register the subscription with Sphere
- Send Notifications: Use SDK methods to send notifications
Prerequisites
Before implementing notifications, ensure you have:
1. Sphere Dashboard Configuration
Configure notifications in your Sphere Dashboard:
-
Navigate to Notification Management
- Log into Sphere Dashboard
- Go to your project → Notification Management
-
Add Webpushr Credentials
- Get your credentials from Webpushr Dashboard
- Enter your Webpushr Key and Auth Token
- Configure target URLs (optional):
- Transaction URL:
https://yourapp.com/transactions
- Account Activity URL:
https://yourapp.com/activity
- Transaction URL:
-
Save and Verify
- Save your configuration
- Verify with OTP
2. Webpushr Account Setup
- Create Webpushr Account: Sign up at Webpushr
- Get Your Credentials:
- Public Key (for frontend)
- API Key and Auth Token (for dashboard)
- Configure Your Domain: Add your application domain in Webpushr settings
3. Frontend Script Installation
Add the Webpushr tracking code to your HTML:
<!DOCTYPE html>
<html>
<head>
<!-- Other head elements -->
<!-- Webpushr Tracking Code -->
<script>
(function (w, d, s, id) {
if (typeof w.webpushr !== "undefined") return;
w.webpushr =
w.webpushr ||
function () {
(w.webpushr.q = w.webpushr.q || []).push(arguments);
};
var js,
fjs = d.getElementsByTagName(s)[0];
js = d.createElement(s);
js.id = id;
js.async = 1;
js.src = "https://cdn.webpushr.com/app.min.js";
fjs.parentNode.insertBefore(js, fjs);
})(window, document, "script", "webpushr-jssdk");
webpushr("setup", {
key: "YOUR-WEBPUSHR-PUBLIC-KEY",
});
</script>
</head>
<body>
<!-- Your app content -->
</body>
</html>
Quick Start
Here's a minimal example to get notifications working:
import Sphere, { Environment } from "@stratosphere-network/wallet";
// 1. Initialize the SDK
const sphere = new Sphere({
apiKey: "sk_your_project_api_key",
environment: Environment.PRODUCTION,
});
// 2. Authenticate user
const loginResponse = await sphere.auth.login({
externalId: "user@example.com",
password: "secure-password",
});
sphere.setBearerToken(loginResponse.accessToken);
// 3. Enable notifications
async function enableNotifications() {
try {
// Request browser permission through Webpushr
await new Promise((resolve) => {
window.webpushr("subscribe", resolve);
});
// Get the Webpushr subscriber ID
const subscriberId = await new Promise<string>((resolve, reject) => {
window.webpushr("fetch_id", function (sid: string) {
if (sid) {
resolve(sid);
} else {
reject(new Error("No subscriber ID available"));
}
});
});
// Register with Sphere
const response = await sphere.notifications.registerSubscription({
subscriberId: subscriberId,
deviceInfo: navigator.userAgent,
platform: "web",
});
if (response.success) {
console.log("Notifications enabled successfully!");
}
} catch (error) {
console.error("Failed to enable notifications:", error);
}
}
// 4. Send a notification
async function sendNotification() {
const response = await sphere.notifications.sendToAllUserSubscribers({
title: "Payment Received",
message: "You've received 100 USDC",
targetUrl: "https://yourapp.com/transactions",
});
if (response.success) {
console.log(`Sent to ${response.data?.summary.sent} devices`);
}
}
Integration Guide
Step 1: Create a Notification Service
Create a dedicated service to manage notifications:
import Sphere from "@stratosphere-network/wallet";
export class NotificationService {
private sphere: Sphere;
private isWebpushrReady = false;
constructor(sphere: Sphere) {
this.sphere = sphere;
this.waitForWebpushr();
}
private async waitForWebpushr(): Promise<void> {
return new Promise((resolve) => {
if (window.webpushr) {
this.isWebpushrReady = true;
resolve();
} else {
window.addEventListener("webpushr-ready", () => {
this.isWebpushrReady = true;
resolve();
});
// Timeout after 5 seconds
setTimeout(() => {
console.warn("Webpushr initialization timeout");
resolve();
}, 5000);
}
});
}
async enableNotifications(): Promise<boolean> {
try {
// Ensure Webpushr is ready
if (!this.isWebpushrReady) {
await this.waitForWebpushr();
}
// Check if already subscribed
const existingSubscriptions = await this.getSubscriptions();
if (existingSubscriptions.activeCount > 0) {
console.log("User already has active subscriptions");
return true;
}
// Request permission
const permission = await this.requestPermission();
if (!permission) {
return false;
}
// Get subscriber ID from Webpushr
const subscriberId = await this.getWebpushrSubscriberId();
// Register with Sphere
const response = await this.sphere.notifications.registerSubscription({
subscriberId,
deviceInfo: this.getDeviceInfo(),
platform: this.getPlatform(),
});
if (response.success) {
this.saveSubscriptionLocally(response.data?.subscription);
return true;
}
return false;
} catch (error) {
console.error("Failed to enable notifications:", error);
return false;
}
}
private async requestPermission(): Promise<boolean> {
return new Promise((resolve) => {
window.webpushr("subscribe", (result: string) => {
resolve(result === "granted");
});
});
}
private getWebpushrSubscriberId(): Promise<string> {
return new Promise((resolve, reject) => {
window.webpushr("fetch_id", (sid: string) => {
if (sid) {
resolve(sid);
} else {
reject(new Error("No subscriber ID available"));
}
});
});
}
private async getSubscriptions() {
const response = await this.sphere.notifications.getUserSubscriptions();
return (
response.data || { subscriptions: [], activeCount: 0, totalCount: 0 }
);
}
private getDeviceInfo(): string {
const ua = navigator.userAgent;
let browser = "Unknown Browser";
let os = "Unknown OS";
// Detect browser
if (ua.includes("Chrome")) browser = "Chrome";
else if (ua.includes("Firefox")) browser = "Firefox";
else if (ua.includes("Safari")) browser = "Safari";
else if (ua.includes("Edge")) browser = "Edge";
// Detect OS
if (ua.includes("Windows")) os = "Windows";
else if (ua.includes("Mac")) os = "macOS";
else if (ua.includes("Linux")) os = "Linux";
else if (ua.includes("Android")) os = "Android";
else if (ua.includes("iOS")) os = "iOS";
return `${browser} on ${os}`;
}
private getPlatform(): string {
return /mobile/i.test(navigator.userAgent) ? "mobile" : "web";
}
private saveSubscriptionLocally(subscription: any) {
if (subscription) {
localStorage.setItem(
"sphereNotificationSubscription",
JSON.stringify({
id: subscription.id,
subscriberId: subscription.subscriberId,
timestamp: new Date().toISOString(),
})
);
}
}
}
Step 2: Implement Permission Request UI
Create a user-friendly permission request flow:
// React component example
import React, { useState, useCallback } from "react";
import { NotificationService } from "./NotificationService";
interface NotificationPromptProps {
notificationService: NotificationService;
onComplete?: (enabled: boolean) => void;
}
export const NotificationPrompt: React.FC<NotificationPromptProps> = ({
notificationService,
onComplete,
}) => {
const [isLoading, setIsLoading] = useState(false);
const [showPrompt, setShowPrompt] = useState(true);
const handleEnable = useCallback(async () => {
setIsLoading(true);
try {
const enabled = await notificationService.enableNotifications();
if (enabled) {
alert("Notifications enabled successfully!");
} else {
alert("Failed to enable notifications. Please try again.");
}
setShowPrompt(false);
onComplete?.(enabled);
} catch (error) {
console.error("Notification error:", error);
alert("An error occurred. Please try again.");
} finally {
setIsLoading(false);
}
}, [notificationService, onComplete]);
const handleDismiss = useCallback(() => {
setShowPrompt(false);
onComplete?.(false);
}, [onComplete]);
if (!showPrompt) {
return null;
}
return (
<div className="notification-prompt">
<div className="prompt-content">
<h3>Stay Updated with Notifications</h3>
<p>Enable push notifications to receive instant updates about:</p>
<ul>
<li>💰 Incoming payments</li>
<li>📊 Transaction confirmations</li>
<li>🔒 Security alerts</li>
<li>📱 Account activities</li>
</ul>
<div className="prompt-actions">
<button
className="btn-primary"
onClick={handleEnable}
disabled={isLoading}
>
{isLoading ? "Enabling..." : "Enable Notifications"}
</button>
<button
className="btn-secondary"
onClick={handleDismiss}
disabled={isLoading}
>
Not Now
</button>
</div>
</div>
</div>
);
};
Step 3: Manage Subscriptions
Provide users with control over their notification preferences:
// Get all user subscriptions
async function getNotificationPreferences() {
const response = await sphere.notifications.getUserSubscriptions();
if (response.success && response.data) {
console.log(`Active subscriptions: ${response.data.activeCount}`);
console.log(`Total subscriptions: ${response.data.totalCount}`);
// Display each subscription
response.data.subscriptions.forEach((subscription) => {
console.log(`
Device: ${subscription.deviceInfo}
Platform: ${subscription.platform}
Active: ${subscription.isActive}
Added: ${new Date(subscription.createdAt).toLocaleDateString()}
`);
});
}
}
// Unsubscribe a specific device
async function unsubscribeDevice(subscriberId: string) {
const response = await sphere.notifications.unsubscribe(subscriberId);
if (response.success) {
console.log("Successfully unsubscribed");
}
}
// Delete all subscriptions
async function deleteAllSubscriptions() {
const response = await sphere.notifications.deleteAllSubscriptions();
if (response.success && response.data) {
console.log(`Deleted ${response.data.deletedCount} subscriptions`);
}
}
Step 4: Send Notifications
Send notifications to users for various events:
// Notification templates for common use cases
class NotificationTemplates {
constructor(private sphere: Sphere) {}
// Payment received notification
async notifyPaymentReceived(
amount: string,
currency: string,
sender: string
) {
return await this.sphere.notifications.sendToAllUserSubscribers({
title: "Payment Received",
message: `You received ${amount} ${currency} from ${sender}`,
targetUrl: "https://yourapp.com/transactions/latest",
});
}
// Transaction confirmation
async notifyTransactionComplete(
txHash: string,
amount: string,
currency: string
) {
return await this.sphere.notifications.sendToAllUserSubscribers({
title: "Transaction Confirmed",
message: `Your transaction of ${amount} ${currency} has been confirmed`,
targetUrl: `https://yourapp.com/transactions/${txHash}`,
});
}
// Security alert
async notifySecurityAlert(alertType: string, details: string) {
return await this.sphere.notifications.sendToAllUserSubscribers({
title: "Security Alert",
message: `${alertType}: ${details}`,
targetUrl: "https://yourapp.com/security",
});
}
// Custom notification
async sendCustomNotification(title: string, message: string, url?: string) {
const response = await this.sphere.notifications.sendToAllUserSubscribers({
title: title || "Notification",
message: message,
targetUrl: url || "https://yourapp.com",
});
// Log delivery results
if (response.success && response.data) {
const { summary } = response.data;
console.log(`Notification delivery:
- Sent: ${summary.sent}
- Failed: ${summary.failed}
- Total: ${summary.total}
`);
// Check failed deliveries
response.data.details
.filter((d) => !d.success)
.forEach((failed) => {
console.error(`Failed for ${failed.subscriberId}: ${failed.error}`);
});
}
return response;
}
}
API Reference
Initialize Notification Service
The notification service is part of the Sphere SDK and is automatically available when you initialize the SDK:
import Sphere, { Environment } from "@stratosphere-network/wallet";
const sphere = new Sphere({
apiKey: "sk_your_api_key",
environment: Environment.PRODUCTION,
});
// Access notification methods
sphere.notifications.registerSubscription(/* ... */);
sphere.notifications.getUserSubscriptions();
// etc.
Methods
registerSubscription
Register or update a notification subscription for the authenticated user.
const response = await sphere.notifications.registerSubscription({
subscriberId: string; // Required: Webpushr subscriber ID
deviceInfo?: string; // Optional: Device/browser information
platform?: string; // Optional: 'web', 'mobile', etc.
});
// Response
{
success: boolean;
message: string;
data?: {
subscription: {
id: string;
subscriberId: string;
isActive: boolean;
}
}
}
getUserSubscriptions
Get all notification subscriptions for the authenticated user.
const response = await sphere.notifications.getUserSubscriptions();
// Response
{
success: boolean;
message: string;
data?: {
subscriptions: Array<{
id: string;
subscriberId: string;
deviceInfo: string;
platform: string;
isActive: boolean;
createdAt: string;
updatedAt: string;
}>;
activeCount: number;
totalCount: number;
}
}
sendToAllUserSubscribers
Send a notification to all of the user's active subscriptions.
const response = await sphere.notifications.sendToAllUserSubscribers({
title?: string; // Optional: Notification title
message: string; // Required: Notification message
targetUrl?: string; // Optional: URL to open when clicked
});
// Response
{
success: boolean;
message: string;
data?: {
summary: {
sent: number;
failed: number;
total: number;
};
details: Array<{
subscriberId: string;
success: boolean;
requestId?: string;
error?: string;
}>;
}
}
sendTestNotification
Send a test notification to a specific subscriber.
const response = await sphere.notifications.sendTestNotification({
subscriberId: string; // Required: Webpushr subscriber ID
title?: string; // Optional: Notification title
message: string; // Required: Notification message
targetUrl?: string; // Optional: URL to open when clicked
});
// Response
{
success: boolean;
message: string;
data?: {
requestId: string;
}
}
unsubscribe
Unsubscribe a specific device from notifications.
const response = await sphere.notifications.unsubscribe(subscriberId: string);
// Response
{
success: boolean;
message: string;
}
deleteAllSubscriptions
Remove all notification subscriptions for the authenticated user.
const response = await sphere.notifications.deleteAllSubscriptions();
// Response
{
success: boolean;
message: string;
data?: {
deletedCount: number;
}
}
Best Practices
1. Progressive Permission Requests
Don't ask for notification permission immediately. Wait for the right context:
class ContextualNotifications {
private hasAskedPermission = false;
async suggestNotificationsAfterPayment() {
if (this.hasAskedPermission) return;
const message =
"Would you like to receive instant notifications when you receive payments?";
const userWants = await this.showCustomPrompt(message);
if (userWants) {
await this.enableNotifications();
}
this.hasAskedPermission = true;
}
async suggestNotificationsForSecurity() {
if (this.hasAskedPermission) return;
const message =
"Enable notifications to receive important security alerts?";
const userWants = await this.showCustomPrompt(message);
if (userWants) {
await this.enableNotifications();
}
this.hasAskedPermission = true;
}
}
2. Error Handling
Implement comprehensive error handling for all notification operations:
async function safeNotificationOperation<T>(
operation: () => Promise<T>,
fallbackMessage: string
): Promise<{ success: boolean; data?: T; error?: string }> {
try {
const result = await operation();
return { success: true, data: result };
} catch (error) {
console.error("Notification operation failed:", error);
// User-friendly error messages
let userMessage = fallbackMessage;
if (error instanceof Error) {
if (error.message.includes("not enabled")) {
userMessage =
"Notifications are not configured. Please contact support.";
} else if (error.message.includes("unauthorized")) {
userMessage = "Please log in to manage notifications.";
} else if (error.message.includes("network")) {
userMessage = "Network error. Please check your connection.";
}
}
return {
success: false,
error: userMessage,
};
}
}
// Usage
const result = await safeNotificationOperation(
() => notificationService.enableNotifications(),
"Failed to enable notifications. Please try again."
);
if (!result.success) {
showErrorToUser(result.error);
}
3. State Persistence
Maintain notification state across sessions:
class NotificationStateManager {
private readonly STORAGE_KEY = "sphere_notification_state";
saveState(state: {
enabled: boolean;
subscriptionId?: string;
lastChecked: Date;
}) {
localStorage.setItem(this.STORAGE_KEY, JSON.stringify(state));
}
loadState(): NotificationState | null {
try {
const saved = localStorage.getItem(this.STORAGE_KEY);
if (saved) {
return JSON.parse(saved);
}
} catch (error) {
console.error("Failed to load notification state");
}
return null;
}
async syncWithServer(sphere: Sphere) {
const response = await sphere.notifications.getUserSubscriptions();
if (response.success && response.data) {
this.saveState({
enabled: response.data.activeCount > 0,
subscriptionId: response.data.subscriptions[0]?.id,
lastChecked: new Date(),
});
}
}
}
4. Testing Notifications
Always test notifications during development:
// Development notification tester
class NotificationTester {
constructor(private sphere: Sphere) {}
async runTests() {
console.log("🧪 Starting notification tests...");
// Test 1: Check subscriptions
const subs = await this.testGetSubscriptions();
// Test 2: Send test notification
if (subs.length > 0) {
await this.testSendNotification(subs[0].subscriberId);
}
// Test 3: Test error handling
await this.testErrorHandling();
console.log("✅ Notification tests complete");
}
private async testGetSubscriptions() {
console.log("Test 1: Getting subscriptions...");
const response = await this.sphere.notifications.getUserSubscriptions();
if (response.success && response.data) {
console.log(`Found ${response.data.totalCount} subscriptions`);
return response.data.subscriptions;
}
return [];
}
private async testSendNotification(subscriberId: string) {
console.log("Test 2: Sending test notification...");
const response = await this.sphere.notifications.sendTestNotification({
subscriberId,
title: "Test Notification",
message: "This is a test from the notification tester",
targetUrl: window.location.href,
});
if (response.success) {
console.log("Test notification sent successfully");
} else {
console.error("Test notification failed:", response.message);
}
}
private async testErrorHandling() {
console.log("Test 3: Testing error handling...");
try {
// Test with invalid subscriber ID
await this.sphere.notifications.unsubscribe("invalid-id");
} catch (error) {
console.log("Error handling works correctly");
}
}
}
Troubleshooting
Common Issues and Solutions
"Notifications not enabled for this project"
Problem: Your project hasn't been configured for notifications in the Sphere Dashboard.
Solution:
- Log into the Sphere Dashboard
- Navigate to your project → Notification Management
- Add your Webpushr credentials
- Save and verify with OTP
"No subscriber ID available"
Problem: Webpushr hasn't been initialized or the user hasn't granted permission.
Solution:
// Ensure Webpushr is loaded
if (!window.webpushr) {
console.error("Webpushr not loaded. Check your script tag.");
return;
}
// Check if user has granted permission
window.webpushr("fetch_id", function (sid: string) {
if (!sid) {
console.log("User has not granted permission yet");
// Request permission
window.webpushr("subscribe");
}
});
Notifications not being received
Debugging steps:
-
Check browser permissions:
if ("Notification" in window) {
console.log("Browser permission:", Notification.permission);
} -
Verify subscriptions:
const response = await sphere.notifications.getUserSubscriptions();
console.log("Active subscriptions:", response.data?.activeCount); -
Send test notification:
if (response.data?.subscriptions[0]) {
await sphere.notifications.sendTestNotification({
subscriberId: response.data.subscriptions[0].subscriberId,
message: "Debug test notification",
});
} -
Check Webpushr dashboard for delivery status
Error Reference
Error | Cause | Solution |
---|---|---|
Notifications not enabled for this project | No dashboard configuration | Configure in Sphere Dashboard |
Invalid subscriber ID | Wrong or expired subscriber ID | Re-subscribe the user |
Unauthorized | Missing or invalid auth token | Ensure user is logged in |
Rate limit exceeded | Too many requests | Implement request throttling |
No active subscriptions | User has no active devices | Guide user to enable notifications |
Security Considerations
Authentication
- Always authenticate users before managing notifications
- Store authentication tokens securely (use sessionStorage over localStorage)
- Clear tokens on logout
// Secure token handling
class SecureAuth {
setToken(token: string) {
sessionStorage.setItem("sphere_token", token);
this.sphere.setBearerToken(token);
}
clearToken() {
sessionStorage.removeItem("sphere_token");
this.sphere.clearBearerToken();
}
setupAutoCleanup() {
window.addEventListener("beforeunload", () => {
this.clearToken();
});
}
}
Input Validation
Always validate notification content:
function validateNotificationContent(data: {
title?: string;
message: string;
targetUrl?: string;
}): ValidationResult {
const errors: string[] = [];
// Message validation
if (!data.message || data.message.trim().length === 0) {
errors.push("Message cannot be empty");
}
if (data.message.length > 500) {
errors.push("Message too long (max 500 characters)");
}
// Title validation
if (data.title && data.title.length > 100) {
errors.push("Title too long (max 100 characters)");
}
// URL validation
if (data.targetUrl) {
try {
const url = new URL(data.targetUrl);
if (!["http:", "https:"].includes(url.protocol)) {
errors.push("Target URL must use HTTP or HTTPS");
}
} catch {
errors.push("Invalid target URL");
}
}
return {
valid: errors.length === 0,
errors,
};
}
Examples
Complete React Integration
Here's a full example of integrating notifications in a React application:
// NotificationProvider.tsx
import React, { createContext, useContext, useState, useEffect } from "react";
import Sphere from "@stratosphere-network/wallet";
import { NotificationService } from "./NotificationService";
interface NotificationContextType {
isEnabled: boolean;
isLoading: boolean;
subscriptionCount: number;
enableNotifications: () => Promise<boolean>;
disableNotifications: () => Promise<boolean>;
sendNotification: (
title: string,
message: string,
url?: string
) => Promise<boolean>;
}
const NotificationContext = createContext<NotificationContextType | null>(null);
export const useNotifications = () => {
const context = useContext(NotificationContext);
if (!context) {
throw new Error(
"useNotifications must be used within NotificationProvider"
);
}
return context;
};
interface NotificationProviderProps {
sphere: Sphere;
children: React.ReactNode;
}
export const NotificationProvider: React.FC<NotificationProviderProps> = ({
sphere,
children,
}) => {
const [isEnabled, setIsEnabled] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [subscriptionCount, setSubscriptionCount] = useState(0);
const [notificationService] = useState(() => new NotificationService(sphere));
// Check notification status on mount
useEffect(() => {
checkNotificationStatus();
}, []);
const checkNotificationStatus = async () => {
setIsLoading(true);
try {
const response = await sphere.notifications.getUserSubscriptions();
if (response.success && response.data) {
setIsEnabled(response.data.activeCount > 0);
setSubscriptionCount(response.data.activeCount);
}
} catch (error) {
console.error("Failed to check notification status:", error);
} finally {
setIsLoading(false);
}
};
const enableNotifications = async (): Promise<boolean> => {
setIsLoading(true);
try {
const success = await notificationService.enableNotifications();
if (success) {
await checkNotificationStatus();
}
return success;
} finally {
setIsLoading(false);
}
};
const disableNotifications = async (): Promise<boolean> => {
setIsLoading(true);
try {
const response = await sphere.notifications.deleteAllSubscriptions();
if (response.success) {
setIsEnabled(false);
setSubscriptionCount(0);
return true;
}
return false;
} finally {
setIsLoading(false);
}
};
const sendNotification = async (
title: string,
message: string,
url?: string
): Promise<boolean> => {
try {
const response = await sphere.notifications.sendToAllUserSubscribers({
title,
message,
targetUrl: url,
});
return response.success;
} catch (error) {
console.error("Failed to send notification:", error);
return false;
}
};
const value: NotificationContextType = {
isEnabled,
isLoading,
subscriptionCount,
enableNotifications,
disableNotifications,
sendNotification,
};
return (
<NotificationContext.Provider value={value}>
{children}
</NotificationContext.Provider>
);
};
// Usage in your app
function App() {
const sphere = new Sphere({
/* ... */
});
return (
<NotificationProvider sphere={sphere}>
<YourAppComponents />
</NotificationProvider>
);
}
// Using the hook in a component
function NotificationToggle() {
const { isEnabled, isLoading, enableNotifications, disableNotifications } =
useNotifications();
const handleToggle = async () => {
if (isEnabled) {
await disableNotifications();
} else {
await enableNotifications();
}
};
return (
<button onClick={handleToggle} disabled={isLoading}>
{isLoading
? "Loading..."
: isEnabled
? "Disable Notifications"
: "Enable Notifications"}
</button>
);
}
Next Steps
Now that you've integrated notifications:
- Test thoroughly: Use the test notification methods to ensure delivery
- Monitor performance: Check delivery rates in your Webpushr dashboard
- Customize messages: Create notification templates for your use cases
- Handle edge cases: Implement proper error handling and fallbacks
- Gather feedback: Ask users about their notification experience
For more advanced features and integrations, explore:
Support
If you encounter issues:
- Check the Troubleshooting section
- Verify your dashboard configuration
- Review browser console for errors
- Contact support with:
- Your project ID
- Error messages
- Browser/device information
- Steps to reproduce
For additional help: