Category: Website Integrations

Learn how to configure features that integrate with the website to provide a better in-app experience

  • Trigger Push Prompt Programmatically | vendrux Docs

    This guide explains how to implement smart push notification prompts in Vendrux apps using the available APIs and best practices. For the purpose of this guide, we will create a button that is only displayed under the correct conditions, and that when clicked, triggers the push notification prompt.

    Setup Flow Overview

    Here’s the basic flow for implementing a push notification button:

    1. Configure your app to disable automatic prompts (iOS_Enable_Push_Notifications: false)
    2. Wait for page load and Vendrux APIs to be ready
    3. Check if button should be shown (user in app + notifications disabled)
    4. Display button with appropriate text
    5. Set up real-time listener for subscription status changes
    6. Handle button clicks to trigger push prompt
    7. Update button text based on subscription status changes

    App Configuration

    To have full control over when push prompts appear, you should configure your Vendrux app to disable the default push prompt that shows immediately when the app opens. Add these parameters to your app configuration:

    {
      "App_Permissions": {
        "iOS_Enable_Push_Notifications": false,
        "Android_Enable_Location": false
      }
    }

    Setting iOS_Enable_Push_Notifications to false disables the automatic push prompt that Vendrux normally shows on app launch. This gives you complete control over when and how to present the push notification request to your users.

    Vendrux APIs & Objects

    1. App Detection

    Check if user is in Vendrux app:

    function isInApp() {    
    	return navigator.userAgent.toLowerCase().includes('canvas');
    }

    Vendrux apps inject “canvas” into the user agent string. This is how we determine if the user is accessing your website from within the app or from a regular browser. Push prompts should only appear when users are in the app context, since regular browsers don’t have access to the native push notification functionality.

    2. Push Subscription Status

    Get current status:

    function isPushEnabled() {
        try {
            return !!(window.mobiloudAppInfo && window.mobiloudAppInfo.pushSubscribed);
        } catch (e) {
            return false; // Assume disabled if can't read
        }
    }

    Vendrux injects an object called mobiloudAppInfo into the DOM that allows you to pull certain details about the user, including their current push notification subscription status. The pushSubscribed property is a boolean that tells you whether the user has already enabled push notifications for your app. This is super useful because you don’t want to keep asking users who have already subscribed!

    Object: window.mobiloudAppInfo.pushSubscribed

    • Type: Boolean
    • Purpose: Current push notification subscription status

    3. Real-time Status Changes

    Listen for status changes:

    // Override the global callback
    window.mlPushStatusChanged = function(isSubscribed) {
        console.log('Push status changed:', isSubscribed);
        // Update your UI here
        updatePromptVisibility(isSubscribed);
    };

    Here’s the thing – we can’t update that mobiloudAppInfo object in real-time when the user’s subscription status changes. This is due to limitations in the WebView. So instead, Vendrux triggers a global function called mlPushStatusChanged whenever the subscription status changes. This makes it super easy for you to update your UI elements immediately when the user enables or disables notifications, giving them a much smoother user experience. No need to constantly check the status or refresh the page!

    Function: window.mlPushStatusChanged(isSubscribed)

    • Type: Global callback function
    • Parameter: isSubscribed (boolean)
    • Triggered: When user enables/disables notifications
    • Use: Real-time UI updates without polling

    4. Trigger Push Prompt

    Show native permission dialog:

    function triggerPushPrompt() {
        // Only trigger if in app context
        if (isInApp()) {
            nativeFunctions.triggerPushPrompt();
        }
    }

    This function triggers the native OS-level permission dialog that asks the user to enable push notifications. It’s the actual system prompt that appears on iOS and Android devices.

    Function: nativeFunctions.triggerPushPrompt()

    • Purpose: Shows OS-level permission dialog or settings redirect
    • Automatic fallback: Handles platform limits automatically

    API Availability & Timing

    Waiting for APIs to Load

    The nativeFunctions object and mobiloudAppInfo are not available immediately when the page loads. The app needs time to initialize and inject these APIs into your webpage. Here’s how to handle this:

    Option 1: Polling Method

    function waitForNativeFunctions(callback, maxAttempts = 50) {
        let attempts = 0;
        
        function check() {
            attempts++;
            
            // Check if APIs are ready
            if (typeof nativeFunctions !== 'undefined' && window.mobiloudAppInfo) {
                callback(); // APIs ready, proceed
            } else if (attempts             setTimeout(check, 100); // Try again in 100ms
            }
            // Stop after 5 seconds (50 × 100ms)
        }
        
        check();
    }

    Option 2: Event-based approach

    // Wait for page to load, then start checking
    document.addEventListener('DOMContentLoaded', function() {
        waitForNativeFunctions(() => {
            setupPushPrompt();
        });
    });

    This ensures your code doesn’t try to access APIs before they’re available, which would cause errors.

    Platform Limitations & Automatic Fallback

    How Platform Limits Work

    Both iOS and Android have built-in restrictions on how many times an app can show the push notification permission prompt:

    • iOS: Allows only a limited number of permission requests per app installation
    • Android: Similar restrictions that vary by Android version

    Automatic Fallback Handling

    The good news is that nativeFunctions.triggerPushPrompt() handles these limits automatically! When the platform limits are reached, instead of showing the native system dialog, it will automatically display a different prompt that directs users to manually enable notifications through their device settings.

    You don’t need to detect or handle this yourself – just call triggerPushPrompt() and the function will either show the native dialog or the settings redirect as appropriate.

    Complete Implementation Example

    class PushNotificationButton {
        constructor() {
            this.button = null;
            this.init();
        }
        
        init() {
            // Wait for page to load
            document.addEventListener('DOMContentLoaded', () => {
                this.setup();
            });
        }
        
        setup() {
            // Wait for Vendrux APIs to be available
            this.waitForNativeFunctions(() => {
                // Set up the button if conditions are met
                this.updateButton();
                // Listen for real-time status changes
                this.setupStatusListener();
            });
        }
        
        updateButton() {
            const shouldShow = this.isInApp();
            const isSubscribed = this.isPushEnabled();
            
            if (shouldShow) {
                if (!this.button) {
                    // Create button if it doesn't exist
                    this.createButton();
                }
                
                // Update button text based on subscription status
                if (isSubscribed) {
                    this.button.textContent = '✅ Notifications Enabled';
                    this.button.disabled = true;
                } else {
                    this.button.textContent = '🔔 Enable Notifications';
                    this.button.disabled = false;
                }
            } else {
                // Hide button if not in app
                this.hideButton();
            }
        }
        
        createButton() {
            // Create the button element
            this.button = document.createElement('button');
            this.button.style.cssText = `
                padding: 12px 24px;
                background-color: #007AFF;
                color: white;
                border: none;
                border-radius: 8px;
                font-size: 16px;
                cursor: pointer;
                margin: 10px;
            `;
            
            // Handle button clicks
            this.button.onclick = () => this.handleClick();
            
            // Add button to page (you can change this to any container)
            document.body.appendChild(this.button);
        }
        
        handleClick() {
            // Only trigger if user is in app and not subscribed
            if (this.isInApp() && !this.isPushEnabled()) {
                // This will show native prompt or settings redirect automatically
                nativeFunctions.triggerPushPrompt();
            }
        }
        
        isInApp() {
            // Check if user is in Vendrux app
            return navigator.userAgent.toLowerCase().includes('canvas');
        }
        
        isPushEnabled() {
            // Check current subscription status
            try {
                return !!(window.mobiloudAppInfo && 
                         window.mobiloudAppInfo.pushSubscribed);
            } catch (e) {
                return false;
            }
        }
        
        setupStatusListener() {
            // Store any existing callback
            const original = window.mlPushStatusChanged;
            
            // Override with our handler
            window.mlPushStatusChanged = (isSubscribed) => {
                // Call original callback if it existed
                if (typeof original === 'function') original(isSubscribed);
                
                // Update button based on new status
                this.updateButton();
            };
        }
        
        hideButton() {
            // Remove button if it exists
            if (this.button) {
                this.button.remove();
                this.button = null;
            }
        }
        
        waitForNativeFunctions(callback, maxAttempts = 50) {
            let attempts = 0;
            
            function check() {
                attempts++;
                
                // Check if both APIs are available
                if (typeof nativeFunctions !== 'undefined' && window.mobiloudAppInfo) {
                    callback(); // Ready to go!
                } else if (attempts                 setTimeout(check, 100); // Try again in 100ms
                }
                // Stop after 5 seconds total
            }
            
            check();
        }
    }
    
    // Initialize the notification button
    new PushNotificationButton();

    Button Behavior Summary

    The button will automatically:

    • Show when user is in the app
    • Hide when user is in a regular browser
    • Display “🔔 Enable Notifications” when push notifications are disabled
    • Display “✅ Notifications Enabled” when push notifications are enabled
    • Become disabled when notifications are already enabled
    • Update in real-time when subscription status changes
    • Handle clicks by triggering the push prompt or settings redirect

  • Tab refresh in background | vendrux Docs

    If you have a “Cart” tab in your app, you might want to refresh it in the background when the user adds or removes a product to the cart, so the next time the user goes to that tab it will be up-to-date with the latest products.

    To do this, you will need to trigger a nativeFunction when a product gets added or removed from the cart.

    The nativeFunction that we will use looks like this:

    // Updates all tabs in the app, except the current one
    nativeFunctions.updateTabs()
      
    // Updates the tab(s) in the declared position(s)
    // In this example we are updating the 2nd and the 3rd tab in the bottom navigation
    nativeFunctions.updateTab([2, 3])

    The first step is to determine the best way to identify that action on your website.

    If your website has a cart icon that displays the number of products in it, that would be a smart way to do it.

    You can use Javascript code to monitor that icon and identify changes in the number of items.

    Imagine that your cart icon HTML code looks like this:\

    div class="cart-icon">
        span class="product-count">1span>
    div>

    We could use the following Javascript snippet to update the cart tab when the number of products in the cart changes:

    // Check if the user agent contains 'canvas' (case insensitive)
    if (navigator.userAgent.toLowerCase().indexOf('canvas') !== -1) {
        // Select the element that displays the number of products in the cart.
        var cartCountElement = document.querySelector('.product-count');
    
        // Define the function that triggers when there is a change in the cart.
        function handleCartChange() {
            nativeFunctions.updateTab([2]);
        }
    
        // Check if the cart count element exists to avoid errors
        if (cartCountElement) {
            // Create a new MutationObserver instance and provide a callback function that will be executed when mutations are observed.
            var observer = new MutationObserver(function(mutations) {
                mutations.forEach(function(mutation) {
                    if (mutation.type === 'childList' || mutation.type === 'characterData') {
                        handleCartChange();
                    }
                });
            });
    
            // Start observing the target element for configured mutations. Observe for changes in children (e.g., text changes) and character data.
            observer.observe(cartCountElement, { childList: true, characterData: true, subtree: true });
        }
    } 
    

  • Open settings screen using native functions

    If you are not using the native bottom navigation in your app, you might still want to open the “Settings” screen, where users can easily adjust their push notification settings.

    You can integrate website elements with the app for this, using native functions.

    Here is a simple code sample that shows how you can achieve this:

    "nativeFunctions.settingsOpen();">Open Settings Screen

    Since native functions will only work in the app, you might want to wrap your web element with a conditional, so it only shows up in the app.

  • Integrating ecommerce features to your app

    Vendrux allows you to use a native API to integrate your website with native features of your app.

    Cart Abandonment and Cart Badge features rely on the number of products in the user’s cart to work, integrating them directly with your website is the most reliable way to ensure that you are passing the right information to the app.

    When integrating these features into your website, you will always want to make sure they are wrapped in a conditional to ensure that they will only be triggered when your website is displayed inside the app, to do this we can use the user agent, as follows:

    >
      function isApp() {
      	// Get the browser user agent and convert it to lower case
        const userAgent = navigator.userAgent.toLowerCase();
        
        // Return true if the user agent includes the "canvas" string
        return userAgent.includes("canvas"); 
      }
    

    You can now trigger the native API functions when the user browses your website in the app, by wrapping the code with the isApp() function.

    Cart Badge

    The Cart Badge feature should be triggered whenever the number of products in the user cart changes, this is how you should use it:

    >
    	nativeFunctions.updateBadge($tabIndex, $badgeValue);
    

    The tabIndex refers to the position of the tab where the cart badge should be displayed. If your app displays the “Cart” tab as the second tab in the bottom navigation, then you will want to use “2” as the value for that parameter.

    The badgeValue refers to the number that should be displayed in the badge, and it should be updated as the user adds or removes products from his cart.

    The final code should look like this:

    >
      function isApp() {
      	// Get the browser user agent and convert it to lower case
        const userAgent = navigator.userAgent.toLowerCase();
        
        // Return true if the user agent includes the "canvas" string
        return userAgent.includes("canvas"); 
      }
      
      if(isApp) {
      	// Get actual cart item count using code from your website, here we are using 3 as a placeholder
        let cartItems = 3;
    
        // Call updateBadge only if the count has changed, again you will want to use your website code to determine when to trigger the following code
        if (cartItems !== previousCartItemCount) { 
        	// Update the badge in the second tab of your app's bottom navigation
            nativeFunctions.updateBadge(2, cartItems);
            
            // Update for next comparison
            previousCartItemCount = cartItems;
        }
      }
    

    Tab Refresh

    When updating the badge with the number of products in the cart, you will also want to trigger a page refresh on the tab that displays the cart page, so the next time the user goes to that tab he can see all the latest products in it.

    For this, we can use the nativeFunctions.updateTab($tabIndex) function, as follows:

    >
      function isApp() {
      	// Get the browser user agent and convert it to lower case
        const userAgent = navigator.userAgent.toLowerCase();
        
        // Return true if the user agent includes the "canvas" string
        return userAgent.includes("canvas"); 
      }
      
      if(isApp) {
      	// Get actual cart item count using code from your website, here we are using 3 as a placeholder
        let cartItems = 3;
    
        // Call updateBadge only if the count has changed, again you will want to use your website code to determine when to trigger the following code
        if (cartItems !== previousCartItemCount) { 
        	// Update the badge in the second tab of your app's bottom navigation
            nativeFunctions.updateBadge(2, cartItems);
            
            // Triggers a refresh on the second tab of your app's bottom navigation
            nativeFunctions.updateTab(2);
            
            // Update for next comparison
            previousCartItemCount = cartItems;
        }
      }
    

    Cart Abandonment

    The Cart Abandonment feature also integrates with the number of products in the user’s cart, so you can use a similar piece of code to configure it.

    The specifics of the Cart Abandonment notifications (title, message, link, delay) must be adjusted directly in the app configuration, but scheduling the notifications is something that must happen on the website side.

    The logic we will use for this is very simple, when there is one or more products in the cart we will schedule the notifications, when there are no products we will cancel any scheduled notifications. The idea is to schedule the notifications whenever the user adds something to his cart, and cancel any scheduled notifications when he removes all products or completes a purchase.

    >
      function isApp() {
      	// Get the browser user agent and convert it to lower case
        const userAgent = navigator.userAgent.toLowerCase();
        
        // Return true if the user agent includes the "canvas" string
        return userAgent.includes("canvas"); 
      }
      
    if (isApp) {
    	// Get actual cart item count (replace this placeholder)
        let cartItems = 3;
    
        // Call the following functions only if the cart item count has changed, again you will want to use your website code to determine when to trigger the following code
        
        // If there is 1 or more products in the cart, schedule the notifications
        if (cartItems > 0) {
            nativeFunctions.scheduleLocalNotifications();
        }
    
        // If there are no products in the cart, cancel all scheduled notifications
        if (cartItems === 0) {
            nativeFunctions.cancelLocalNotifications();
        }
    }
    

    Integrating With Your Website

    Collaborate with your website developer to implement the provided code snippets into your site’s codebase.

    You will want to get his assistance to determine the best way to get the number of products in the user cart, and also to use events to trigger the badge and notification logic whenever the number of products in the cart changes.

  • Haptic Feedback | vendrux Docs

    The Haptic Feedback feature provides tactile confirmation for user interactions through device vibration. This native function enhances user experience by delivering immediate physical feedback when actions are performed, creating a more engaging and responsive interface.

    This guide helps you add satisfying vibration feedback to user actions in your Vendrux app, making interactions feel more responsive and engaging.

    What is Haptic Feedback?

    Haptic feedback refers to the use of touch sensations, particularly vibration, to communicate with users through their sense of touch. In mobile and touch-enabled applications, haptic feedback provides:

    • Action confirmation: Immediate response that an action has been registered
    • Enhanced user satisfaction: Tactile feedback creates a more engaging interaction
    • Accessibility benefits: Additional sensory confirmation for users with visual impairments

    When to Use Haptic Feedback

    Haptic feedback is most effective in these scenarios:

    • Button presses and tap interactions
    • Form submissions and confirmations
    • Toggle switches and checkboxes
    • Swipe gestures and drag-and-drop actions
    • Success confirmations (save, send, complete)
    • Navigation transitions

    Implementation

    Basic Usage

    The haptic feedback function is straightforward to implement:

    if (navigator.userAgent.toLowerCase().includes('canvas')) {
        // Trigger haptic feedback
        nativeFunctions.hapticFeedback();
    } else {
        // Web fallback - no haptic feedback available
        console.log('Haptic feedback not available in web environment');
    }

    Button Click Confirmation

    function handleButtonClick() {
        // Perform the primary action
        submitForm();
        
        // Provide haptic confirmation
        if (navigator.userAgent.toLowerCase().includes('canvas')) {
            nativeFunctions.hapticFeedback();
        }
    }
    
    // Attach to button element
    document.getElementById('submit-btn').addEventListener('click', handleButtonClick);

    Best Practices

    User Experience Guidelines

    Timing and Responsiveness:

    • Trigger haptic feedback immediately when the action occurs
    • Don’t delay the feedback – users expect instant response
    • Ensure the haptic feedback doesn’t interfere with the primary action

    Consistency:

    • Use haptic feedback consistently across similar interactions
    • Establish clear patterns for when feedback occurs
    • Document your haptic feedback strategy for team consistency