Skip to main content

Hum Widget Hook Notifications

The Hum widget provides a universal notification system that works across web browsers, iOS WebViews, and Android WebViews. All hooks use four communication methods for maximum compatibility:
  1. postMessage - Works in web iframes, iOS WKWebView, and Android WebView
  2. iOS WKWebView message handler - Direct communication with iOS native code
  3. Android WebView interface - Direct communication with Android native code
  4. DOM events - Fallback for same-document scenarios

Available Hooks

The widget emits three types of notification hooks:

Order Completion Hook

Triggered when an order is successfully submitted or fails.

Event Data Structure

interface OrderCompletedEventDetail {
  orderId: string;           // Unique order identifier
  success: boolean;          // Whether the order was successful
  message?: string;          // Success/error message
  orderData?: {              // Complete order information (only on success)
    selectedPlan: SelectedPlan;
    selectedInternetAddons: SelectedInternetAddon[];
    selectedTvProducts: SelectedTvProduct[];
    selectedTvAddons: SelectedTvProduct[];
    customerData: CustomerData;
    scheduleData: ScheduleData;
    totalAmount?: {
      amount_cents: number;
      amount_currency: string;
    };
  };
  timestamp: string;         // ISO timestamp of when the order was completed
}

Web Integration (JavaScript)

Use the postMessage method as your primary integration method. It works across all platforms including iframes and WebViews.

Common Use Cases

if (event.data.type === 'humOrderCompleted' && event.data.data.success) {
  const { orderId, orderData } = event.data.data;
  
  // Google Analytics 4
  gtag('event', 'purchase', {
    transaction_id: orderId,
    value: orderData.totalAmount.amount_cents / 100,
    currency: orderData.totalAmount.amount_currency,
    items: [{
      item_name: orderData.selectedPlan.name,
      item_category: 'Internet Service',
      price: orderData.selectedPlan.price
    }]
  });
  
  // Facebook Pixel
  fbq('track', 'Purchase', {
    value: orderData.totalAmount.amount_cents / 100,
    currency: orderData.totalAmount.amount_currency
  });
}
if (event.data.type === 'humOrderCompleted' && event.data.data.success) {
  const { orderId, orderData } = event.data.data;
  
  // Send to your backend
  fetch('/api/orders', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      orderId,
      customer: orderData.customerData,
      plan: orderData.selectedPlan,
      timestamp: event.data.data.timestamp
    })
  })
  .then(response => response.json())
  .then(data => console.log('Order synced to backend:', data))
  .catch(error => console.error('Failed to sync order:', error));
}
// React example
if (event.data.type === 'humOrderCompleted' && event.data.data.success) {
  const { orderId, orderData } = event.data.data;
  
  // Update state
  setOrderStatus('completed');
  setOrderId(orderId);
  setCustomerData(orderData.customerData);
  
  // Navigate to confirmation page
  navigate(`/order-confirmation/${orderId}`);
}

iOS Integration (Swift)

1

Configure WKWebView with Message Handler

import WebKit

class WebViewController: UIViewController, WKScriptMessageHandler {
    var webView: WKWebView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Configure message handler
        let contentController = WKUserContentController()
        contentController.add(self, name: "humWidget")
        
        let config = WKWebViewConfiguration()
        config.userContentController = contentController
        
        // Initialize WebView
        webView = WKWebView(frame: view.bounds, configuration: config)
        view.addSubview(webView)
        
        // Load widget page
        if let url = URL(string: "https://your-widget-url.com") {
            webView.load(URLRequest(url: url))
        }
    }
}
2

Handle Widget Messages

func userContentController(_ userContentController: WKUserContentController, 
                          didReceive message: WKScriptMessage) {
    guard message.name == "humWidget",
          let messageData = message.body as? [String: Any],
          let type = messageData["type"] as? String else {
        return
    }
    
    switch type {
    case "humOrderCompleted":
        handleOrderCompleted(messageData: messageData)
    default:
        break
    }
}
3

Process Order Completion

private func handleOrderCompleted(messageData: [String: Any]) {
    guard let data = messageData["data"] as? [String: Any],
          let orderId = data["orderId"] as? String,
          let success = data["success"] as? Bool else {
        return
    }
    
    if success {
        print("✅ Order \(orderId) completed successfully!")
        
        // Access order data
        if let orderData = data["orderData"] as? [String: Any] {
            let customerData = orderData["customerData"] as? [String: Any]
            let firstName = customerData?["firstName"] as? String
            let lastName = customerData?["lastName"] as? String
            let email = customerData?["email"] as? String
            
            print("Customer: \(firstName ?? "") \(lastName ?? "")")
            print("Email: \(email ?? "")")
            
            // Save to Core Data, update UI, track in analytics
            DispatchQueue.main.async {
                self.showOrderConfirmation(orderId: orderId)
            }
        }
        
        if let totalAmount = (data["orderData"] as? [String: Any])?["totalAmount"] as? [String: Any] {
            let cents = totalAmount["amount_cents"] as? Int ?? 0
            let currency = totalAmount["amount_currency"] as? String ?? "USD"
            let dollars = Double(cents) / 100.0
            print("Total: \(dollars) \(currency)")
        }
    } else {
        let errorMessage = data["message"] as? String ?? "Unknown error"
        print("❌ Order failed: \(errorMessage)")
        
        DispatchQueue.main.async {
            self.showError(message: errorMessage)
        }
    }
}

private func showOrderConfirmation(orderId: String) {
    let alert = UIAlertController(
        title: "Order Completed",
        message: "Your order \(orderId) has been submitted successfully!",
        preferredStyle: .alert
    )
    alert.addAction(UIAlertAction(title: "OK", style: .default))
    present(alert, animated: true)
}

Android Integration (Kotlin)

1

Define Data Classes

import com.google.gson.annotations.SerializedName

data class OrderCompletedMessage(
    val type: String,
    val data: OrderCompletedData
)

data class OrderCompletedData(
    val orderId: String,
    val success: Boolean,
    val message: String?,
    val orderData: OrderData?,
    val timestamp: String
)

data class OrderData(
    val selectedPlan: SelectedPlan,
    val customerData: CustomerData,
    val totalAmount: TotalAmount?
)

data class SelectedPlan(
    val id: String,
    val name: String,
    val providerName: String,
    val price: Double
)

data class CustomerData(
    val firstName: String,
    val lastName: String,
    val email: String,
    val phoneNumber: String
)

data class TotalAmount(
    @SerializedName("amount_cents") val amountCents: Int,
    @SerializedName("amount_currency") val amountCurrency: String
)
2

Setup WebView with JavaScript Interface

import android.webkit.JavascriptInterface
import android.webkit.WebView
import com.google.gson.Gson

class WebViewActivity : AppCompatActivity() {
    private lateinit var webView: WebView
    private val gson = Gson()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_webview)
        
        webView = findViewById(R.id.webview)
        setupWebView()
    }
    
    private fun setupWebView() {
        webView.settings.apply {
            javaScriptEnabled = true
            domStorageEnabled = true
        }
        
        // Add JavaScript interface for widget communication
        webView.addJavascriptInterface(
            WebAppInterface(this),
            "AndroidInterface"
        )
        
        // Load widget page
        webView.loadUrl("https://your-widget-url.com")
    }
    
    inner class WebAppInterface(private val context: WebViewActivity) {
        
        @JavascriptInterface
        fun onOrderCompleted(jsonMessage: String) {
            try {
                val message = gson.fromJson(jsonMessage, OrderCompletedMessage::class.java)
                
                runOnUiThread {
                    handleOrderCompleted(message)
                }
            } catch (e: Exception) {
                Log.e("WebAppInterface", "Error parsing order completion message", e)
            }
        }
    }
}
3

Handle Order Completion

private fun handleOrderCompleted(message: OrderCompletedMessage) {
    val data = message.data
    
    if (data.success) {
        Log.i("HumWidget", "✅ Order ${data.orderId} completed at ${data.timestamp}")
        
        // Access order data
        data.orderData?.let { orderData ->
            val customer = orderData.customerData
            val plan = orderData.selectedPlan
            
            Log.i("HumWidget", "Customer: ${customer.firstName} ${customer.lastName}")
            Log.i("HumWidget", "Email: ${customer.email}")
            Log.i("HumWidget", "Plan: ${plan.name} from ${plan.providerName}")
            
            orderData.totalAmount?.let { amount ->
                val dollars = amount.amountCents / 100.0
                Log.i("HumWidget", "Total: $$dollars ${amount.amountCurrency}")
            }
            
            // Save to Room database, track in Firebase, update UI
            showOrderConfirmation(data.orderId, orderData)
            
            // Track in Firebase Analytics
            val bundle = Bundle().apply {
                putString("order_id", data.orderId)
                putString("provider", plan.providerName)
                putDouble("value", orderData.totalAmount?.amountCents?.div(100.0) ?: 0.0)
            }
            FirebaseAnalytics.getInstance(this)
                .logEvent("hum_order_completed", bundle)
        }
        
    } else {
        val errorMessage = data.message ?: "Unknown error"
        Log.e("HumWidget", "❌ Order failed: $errorMessage")
        
        showError(errorMessage)
    }
}

private fun showOrderConfirmation(orderId: String, orderData: OrderData) {
    AlertDialog.Builder(this)
        .setTitle("Order Completed")
        .setMessage(
            "Your order $orderId has been submitted successfully!\n\n" +
            "Plan: ${orderData.selectedPlan.name}\n" +
            "Provider: ${orderData.selectedPlan.providerName}"
        )
        .setPositiveButton("OK") { dialog, _ ->
            dialog.dismiss()
        }
        .show()
}
Always handle both success and failure cases in the order completion hook. Network issues or validation errors can cause order submission to fail.

Plan Save Hook

Triggered when a user saves an internet plan for later.

Event Data Structure

interface SavePlanEventDetail {
  planId: string;           // Unique plan identifier
  success: boolean;         // Whether the save was successful
  message?: string;         // Success/error message
  timestamp: string;        // ISO timestamp of when the plan was saved
}

Web Integration (JavaScript)

Store saved plan IDs in your database or local storage to enable features like “My Saved Plans” or filtering widget results to show only saved plans.

iOS Integration (Swift)

if type == "humPlanSaved" {
    handlePlanSaved(messageData: messageData)
}

private func handlePlanSaved(messageData: [String: Any]) {
    guard let data = messageData["data"] as? [String: Any],
          let planId = data["planId"] as? String,
          let success = data["success"] as? Bool,
          let timestamp = data["timestamp"] as? String else {
        return
    }
    
    if success {
        print("✅ Plan \(planId) saved at \(timestamp)")
        
        // Save to Core Data or UserDefaults
        savePlanToStorage(planId: planId, timestamp: timestamp)
        
        // Track in analytics
        Analytics.logEvent("plan_saved", parameters: [
            "plan_id": planId,
            "timestamp": timestamp
        ])
        
        // Update UI
        DispatchQueue.main.async {
            self.showSaveConfirmation(planId: planId)
            self.updateSavedPlansUI()
        }
    } else {
        let errorMessage = data["message"] as? String ?? "Unknown error"
        print("❌ Failed to save plan: \(errorMessage)")
        
        DispatchQueue.main.async {
            self.showError(message: "Failed to save plan: \(errorMessage)")
        }
    }
}

private func savePlanToStorage(planId: String, timestamp: String) {
    var savedPlans = UserDefaults.standard.stringArray(forKey: "savedPlans") ?? []
    if !savedPlans.contains(planId) {
        savedPlans.append(planId)
        UserDefaults.standard.set(savedPlans, forKey: "savedPlans")
    }
}

private func showSaveConfirmation(planId: String) {
    let alert = UIAlertController(
        title: "Plan Saved",
        message: "Plan has been saved to your favorites!",
        preferredStyle: .alert
    )
    alert.addAction(UIAlertAction(title: "OK", style: .default))
    present(alert, animated: true)
}

Android Integration (Kotlin)

data class PlanSavedMessage(
    val type: String,
    val data: PlanSavedData
)

data class PlanSavedData(
    val planId: String,
    val success: Boolean,
    val message: String?,
    val timestamp: String
)

inner class WebAppInterface(private val context: WebViewActivity) {
    
    @JavascriptInterface
    fun onPlanSaved(jsonMessage: String) {
        try {
            val message = gson.fromJson(jsonMessage, PlanSavedMessage::class.java)
            
            runOnUiThread {
                handlePlanSaved(message)
            }
        } catch (e: Exception) {
            Log.e("WebAppInterface", "Error parsing plan save message", e)
        }
    }
}

private fun handlePlanSaved(message: PlanSavedMessage) {
    val data = message.data
    
    if (data.success) {
        Log.i("HumWidget", "✅ Plan ${data.planId} saved at ${data.timestamp}")
        
        // Save to SharedPreferences or Room database
        savePlanToStorage(data.planId, data.timestamp)
        
        // Track in Firebase Analytics
        val bundle = Bundle().apply {
            putString("plan_id", data.planId)
            putString("timestamp", data.timestamp)
        }
        FirebaseAnalytics.getInstance(this)
            .logEvent("plan_saved", bundle)
        
        // Update UI
        showSaveConfirmation(data.planId)
        updateSavedPlansUI()
        
    } else {
        val errorMessage = data.message ?: "Unknown error"
        Log.e("HumWidget", "❌ Failed to save plan: $errorMessage")
        
        showError("Failed to save plan: $errorMessage")
    }
}

private fun savePlanToStorage(planId: String, timestamp: String) {
    val sharedPrefs = getSharedPreferences("HumWidget", Context.MODE_PRIVATE)
    val savedPlans = sharedPreefs.getStringSet("savedPlans", mutableSetOf())?.toMutableSet() ?: mutableSetOf()
    
    savedPlans.add(planId)
    
    sharedPrefs.edit()
        .putStringSet("savedPlans", savedPlans)
        .apply()
}

private fun showSaveConfirmation(planId: String) {
    Snackbar.make(
        findViewById(R.id.root),
        "Plan saved to your favorites!",
        Snackbar.LENGTH_SHORT
    ).show()
}

Plan Unsave Hook

Triggered when a user removes a saved plan.

Event Data Structure

interface UnsavePlanEventDetail {
  planId: string;           // Unique plan identifier
  success: boolean;         // Whether the unsave was successful
  message?: string;         // Success/error message
  timestamp: string;        // ISO timestamp of when the plan was unsaved
}

Web Integration (JavaScript)

iOS Integration (Swift)

if type == "humPlanUnsaved" {
    handlePlanUnsaved(messageData: messageData)
}

private func handlePlanUnsaved(messageData: [String: Any]) {
    guard let data = messageData["data"] as? [String: Any],
          let planId = data["planId"] as? String,
          let success = data["success"] as? Bool else {
        return
    }
    
    if success {
        print("✅ Plan \(planId) unsaved")
        
        // Remove from storage
        removePlanFromStorage(planId: planId)
        
        // Track in analytics
        Analytics.logEvent("plan_unsaved", parameters: ["plan_id": planId])
        
        // Update UI
        DispatchQueue.main.async {
            self.updateSavedPlansUI()
            self.showNotification(message: "Plan removed from favorites")
        }
    }
}

private func removePlanFromStorage(planId: String) {
    var savedPlans = UserDefaults.standard.stringArray(forKey: "savedPlans") ?? []
    savedPlans.removeAll { $0 == planId }
    UserDefaults.standard.set(savedPlans, forKey: "savedPlans")
}

Android Integration (Kotlin)

@JavascriptInterface
fun onPlanUnsaved(jsonMessage: String) {
    try {
        val message = gson.fromJson(jsonMessage, PlanUnsavedMessage::class.java)
        
        runOnUiThread {
            handlePlanUnsaved(message)
        }
    } catch (e: Exception) {
        Log.e("WebAppInterface", "Error parsing plan unsave message", e)
    }
}

private fun handlePlanUnsaved(message: PlanUnsavedMessage) {
    val data = message.data
    
    if (data.success) {
        Log.i("HumWidget", "✅ Plan ${data.planId} unsaved")
        
        // Remove from storage
        removePlanFromStorage(data.planId)
        
        // Track in Firebase
        val bundle = Bundle().apply {
            putString("plan_id", data.planId)
        }
        FirebaseAnalytics.getInstance(this)
            .logEvent("plan_unsaved", bundle)
        
        // Update UI
        updateSavedPlansUI()
        showNotification("Plan removed from favorites")
    }
}

private fun removePlanFromStorage(planId: String) {
    val sharedPrefs = getSharedPreferences("HumWidget", Context.MODE_PRIVATE)
    val savedPlans = sharedPrefs.getStringSet("savedPlans", mutableSetOf())?.toMutableSet()
    
    savedPlans?.remove(planId)
    
    sharedPrefs.edit()
        .putStringSet("savedPlans", savedPlans)
        .apply()
}

React Native Integration

For React Native applications using WebView:
import { WebView } from 'react-native-webview';
import AsyncStorage from '@react-native-async-storage/async-storage';

function HumWidgetScreen() {
  const handleMessage = (event) => {
    try {
      const message = JSON.parse(event.nativeEvent.data);
      
      switch (message.type) {
        case 'humOrderCompleted':
          handleOrderCompleted(message.data);
          break;
          
        case 'humPlanSaved':
          handlePlanSaved(message.data);
          break;
          
        case 'humPlanUnsaved':
          handlePlanUnsaved(message.data);
          break;
      }
    } catch (error) {
      console.error('Failed to parse widget message:', error);
    }
  };
  
  const handleOrderCompleted = (data) => {
    const { orderId, success, orderData } = data;
    
    if (success) {
      console.log(`✅ Order ${orderId} completed`);
      
      // Navigate to confirmation screen
      navigation.navigate('OrderConfirmation', { orderId, orderData });
      
      // Track in analytics
      analytics().logEvent('purchase', {
        transaction_id: orderId,
        value: orderData.totalAmount.amount_cents / 100,
        currency: orderData.totalAmount.amount_currency
      });
    } else {
      Alert.alert('Order Failed', data.message);
    }
  };
  
  const handlePlanSaved = async (data) => {
    if (data.success) {
      console.log(`✅ Plan ${data.planId} saved`);
      
      // Save to AsyncStorage
      const savedPlans = await AsyncStorage.getItem('savedPlans');
      const plans = savedPlans ? JSON.parse(savedPlans) : [];
      plans.push(data.planId);
      await AsyncStorage.setItem('savedPlans', JSON.stringify(plans));
      
      // Show toast
      Toast.show('Plan saved to favorites!');
    }
  };
  
  const handlePlanUnsaved = async (data) => {
    if (data.success) {
      console.log(`✅ Plan ${data.planId} unsaved`);
      
      // Remove from AsyncStorage
      const savedPlans = await AsyncStorage.getItem('savedPlans');
      const plans = savedPlans ? JSON.parse(savedPlans) : [];
      const updated = plans.filter(id => id !== data.planId);
      await AsyncStorage.setItem('savedPlans', JSON.stringify(updated));
      
      Toast.show('Plan removed from favorites');
    }
  };
  
  return (
    <WebView
      source={{ uri: 'https://your-widget-url.com' }}
      onMessage={handleMessage}
      javaScriptEnabled={true}
    />
  );
}
React Native’s WebView component automatically handles postMessage communication between the web content and native code.

Browser Compatibility

All hooks work in:
  • ✅ Chrome, Firefox, Safari, Edge (all modern versions)
  • ✅ iOS WKWebView (iOS 11+)
  • ✅ Android WebView (Android 5.0+)
  • ✅ React Native WebView
  • ✅ Cordova/PhoneGap WebView

Summary

All hooks use the same four communication methods for universal compatibility across platforms. Choose the integration method that best fits your application architecture.
HookEvent TypeTriggerKey Data
Order CompletedhumOrderCompletedOrder submission success/failureorderId, success, orderData, timestamp
Plan SavedhumPlanSavedUser saves a planplanId, success, timestamp
Plan UnsavedhumPlanUnsavedUser removes saved planplanId, success, timestamp

Next Steps