Skip to main content
Logo
Explore APIsContact Us
  • Home
  • Match Preview
  • Tournament Preview
  • Virtual Stadium
  1. Resources
  2. Widgets
  3. Widget Integration Best Practices

Widget Integration Best Practices

Widgets, Engagement Tools

#What Are Widget Integration Best Practices?

Professional widget integration goes beyond basic implementation to ensure reliable, performant, and maintainable deployments. This tutorial covers advanced techniques for production-ready widget integration including:

  • Performance optimization - Minimize load times and resource usage
  • Error handling strategies - Graceful degradation and user feedback
  • Production deployment - Monitoring, logging, and maintenance
  • User experience enhancement - Loading states, responsiveness, and accessibility
  • Security considerations - Content Security Policy and safe integration

The practices outlined here build upon fundamental integration knowledge to deliver enterprise-grade widget implementations.

#Intended Audience

This tutorial is designed for:

  • Frontend developers with experience integrating Sportradar widgets
  • Technical leads responsible for production deployments
  • DevOps engineers implementing monitoring and deployment strategies
  • Product managers seeking to understand technical requirements for optimal widget performance

Prerequisites: Basic familiarity with widget integration, JavaScript, and web development concepts.

#Goals

By completing this tutorial, you will:

  • Implement robust error handling and fallback strategies
  • Optimize widget performance for production environments
  • Set up comprehensive monitoring and logging systems
  • Apply security best practices for safe widget integration
  • Create responsive, accessible widget implementations
  • Establish maintenance workflows for long-term reliability

#Environment Specification (Prerequisites)

To complete this tutorial, you will need:

#Required Tools and Access

  • Sportradar Widgets Account with API credentials
  • Development Environment with modern browser (Chrome 90+, Firefox 88+, Safari 14+)
  • Text Editor or IDE (VS Code, WebStorm, or similar)
  • Local Web Server for testing (Live Server, http-server, or similar)
  • Browser Developer Tools for debugging and performance analysis

#Technical Requirements

  • JavaScript Knowledge - ES6+, Promises, async/await
  • HTML/CSS Skills - DOM manipulation, responsive design
  • Basic Node.js (optional) - for build tools and local development
  • Network Access - to Sportradar APIs and CDN resources

#Optional but Recommended

  • Monitoring Tools - Google Analytics, LogRocket, or similar APM solution
  • Build Tools - Webpack, Rollup, or Vite for optimization
  • Testing Framework - Jest, Cypress, or Playwright for automated testing

#Part 1: Advanced Error Handling and Resilience

Professional widget integration requires comprehensive error handling that gracefully manages various failure scenarios.

#Step 1: Implement Widget Load Error Detection

First, let's create a robust widget loader with comprehensive error detection:

html
<!DOCTYPE html>
<html lang="en"













































































#Step 2: Add Comprehensive Script Loading Logic

javascript
class WidgetManager {
    constructor(containerId



































































#Step 3: Implement Widget Initialization With Fallbacks

javascript
class WidgetManager {
    // ... previous methods

    async initializeWidget

































































#Part 2: Performance Optimization Strategies

#Step 4: Implement Lazy Loading and Resource Optimization

javascript

#Part 3: Production Monitoring and Maintenance

#Step 5: Implement Comprehensive Monitoring

javascript

#Part 4: Security and Accessibility Best Practices

#Step 6: Implement Security Hardening

html

#Part 5: Production Deployment and Maintenance

#Step 7: Create Deployment Checklist and Monitoring

javascript

#Further Reading

#Official Documentation

  • Widget Integration Getting Started Guide
  • Scoreboard Widget Integration Example
  • Widget Theming and Customization Tutorial

#Performance Resources

  • Web Performance Best Practices - Google's comprehensive performance guide
  • Intersection Observer API - MDN documentation for lazy loading
  • Performance API - Timing and metrics collection

#Security Guidelines

  • Content Security Policy - MDN CSP implementation guide
  • OWASP Frontend Security - Industry security standards
  • Web Security Essentials - Google's security best practices

#Accessibility Standards

  • WCAG 2.1 Guidelines - Web accessibility standards
  • ARIA Authoring Practices - Screen reader compatibility guide
  • Accessibility Testing Tools - Testing and validation resources

#Monitoring and Analytics

  • Google Analytics 4 - Event tracking implementation
  • Sentry Error Tracking - Error monitoring setup
  • Web Vitals - User experience metrics

info

This tutorial provides production-ready patterns for professional widget integration. Always test thoroughly in staging environments before deploying to production, and monitor performance metrics continuously to ensure optimal user experience.

AccessibilityTroubleshooting
Last updated 14 days ago
Is this site helpful?
On this page
  • What Are Widget Integration Best Practices?
  • Intended Audience
  • Goals
  • Environment Specification (Prerequisites)
  • Required Tools and Access
  • Technical Requirements
  • Optional but Recommended
  • Part 1: Advanced Error Handling and Resilience
  • Step 1: Implement Widget Load Error Detection
  • Step 2: Add Comprehensive Script Loading Logic
  • Step 3: Implement Widget Initialization With Fallbacks
  • Part 2: Performance Optimization Strategies
  • Step 4: Implement Lazy Loading and Resource Optimization
  • Part 3: Production Monitoring and Maintenance
  • Step 5: Implement Comprehensive Monitoring
  • Part 4: Security and Accessibility Best Practices
  • Step 6: Implement Security Hardening
  • Part 5: Production Deployment and Maintenance
  • Step 7: Create Deployment Checklist and Monitoring
  • Further Reading
  • Official Documentation
  • Performance Resources
  • Security Guidelines
  • Accessibility Standards
  • Monitoring and Analytics
>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Production Widget Integration</title>
<style>
.widget-container {
position: relative;
min-height: 200px;
background: #f5f5f5;
border-radius: 8px;
overflow: hidden;
}
.widget-loading {
display: flex;
align-items: center;
justify-content: center;
height: 200px;
color: #666;
}
.widget-error {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 200px;
color: #d32f2f;
text-align: center;
padding: 20px;
}
.retry-button {
margin-top: 10px;
padding: 8px 16px;
background: #1976d2;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>
</head>
<body>
<div id="scoreboard-widget" class="widget-container">
<div class="widget-loading">Loading match data...</div>
</div>
<script>
class WidgetManager {
constructor(containerId, widgetConfig) {
this.container = document.getElementById(containerId);
this.config = widgetConfig;
this.retryCount = 0;
this.maxRetries = 3;
this.retryDelay = 2000;
this.loadTimeout = 15000;
}
async loadWidget() {
try {
await this.loadWidgetScript();
await this.initializeWidget();
this.onSuccess();
} catch (error) {
this.handleError(error);
}
}
}
// Initialize widget manager
const widgetManager = new WidgetManager('scoreboard-widget', {
widget: 'sr:match:scoreboard',
matchId: 12345678
});
</script>
</body>
</html>
,
widgetConfig
)
{
this.container = document.getElementById(containerId);
this.config = widgetConfig;
this.retryCount = 0;
this.maxRetries = 3;
this.retryDelay = 2000;
this.loadTimeout = 15000;
this.scriptLoadPromise = null;
}
async loadWidgetScript() {
if (this.scriptLoadPromise) {
return this.scriptLoadPromise;
}
this.scriptLoadPromise = new Promise((resolve, reject) => {
// Check if widget script is already loaded
if (window.SRWidgets) {
resolve();
return;
}
const script = document.createElement('script');
script.src = 'https://widgets.sir.sportradar.com/js/api/widgets.js';
script.async = true;
script.crossOrigin = 'anonymous';
// Set up timeout
const timeout = setTimeout(() => {
reject(new Error('Widget script load timeout'));
}, this.loadTimeout);
script.onload = () => {
clearTimeout(timeout);
// Wait for widget API to be ready
this.waitForWidgetAPI().then(resolve).catch(reject);
};
script.onerror = () => {
clearTimeout(timeout);
reject(new Error('Widget script failed to load'));
};
document.head.appendChild(script);
});
return this.scriptLoadPromise;
}
async waitForWidgetAPI() {
return new Promise((resolve, reject) => {
let attempts = 0;
const maxAttempts = 50;
const checkAPI = () => {
if (window.SRWidgets && typeof window.SRWidgets.render === 'function') {
resolve();
} else if (attempts >= maxAttempts) {
reject(new Error('Widget API not available after loading'));
} else {
attempts++;
setTimeout(checkAPI, 100);
}
};
checkAPI();
});
}
}
()
{
return new Promise((resolve, reject) => {
const initTimeout = setTimeout(() => {
reject(new Error('Widget initialization timeout'));
}, this.loadTimeout);
try {
const widgetConfig = {
...this.config,
onload: () => {
clearTimeout(initTimeout);
console.log('Widget loaded successfully');
resolve();
},
onerror: (error) => {
clearTimeout(initTimeout);
reject(new Error(`Widget initialization failed: ${error.message || error}`));
},
ontrack: (event) => {
this.trackWidgetEvent(event);
}
};
// Clear loading state
this.container.innerHTML = '';
// Initialize widget
window.SRWidgets.render(this.container, widgetConfig);
} catch (error) {
clearTimeout(initTimeout);
reject(error);
}
});
}
trackWidgetEvent(event) {
// Integration with analytics
if (window.gtag) {
gtag('event', 'widget_interaction', {
'event_category': 'widget',
'event_label': event.type,
'custom_parameter': event.data
});
}
// Custom logging
console.log('Widget event:', event);
}
handleError(error) {
console.error('Widget error:', error);
// Show user-friendly error message
this.showErrorState(error);
// Attempt retry if within limits
if (this.retryCount < this.maxRetries) {
this.scheduleRetry();
} else {
this.showFallbackContent();
}
// Report error to monitoring service
this.reportError(error);
}
}
class PerformantWidgetManager extends WidgetManager {
    constructor(containerId, widgetConfig) {
        super(containerId, widgetConfig);
        this.intersectionObserver = null;
        this.isVisible = false;
        this.resourcesPreloaded = false;
    }

    initLazyLoading() {
        if (!('IntersectionObserver' in window)) {
            // Fallback for older browsers
            this.loadWidget();
            return;
        }

        this.intersectionObserver = new IntersectionObserver(
            (entries) => {
                entries.forEach(entry => {
                    if (entry.isIntersecting && !this.isVisible) {
                        this.isVisible = true;
                        this.preloadResources();
                        setTimeout(() => this.loadWidget(), 100);
                        this.intersectionObserver.disconnect();
                    }
                });
            },
            {
                rootMargin: '100px',
                threshold: 0.1
            }
        );

        this.intersectionObserver.observe(this.container);
    }

    async preloadResources() {
        if (this.resourcesPreloaded) return;
        
        const resources = [
            'https://widgets.sir.sportradar.com/css/api/widgets.css',
            'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap'
        ];

        const preloadPromises = resources.map(url => {
            return new Promise((resolve) => {
                const link = document.createElement('link');
                link.rel = 'preload';
                link.as = url.includes('.css') ? 'style' : 'script';
                link.href = url;
                link.onload = resolve;
                link.onerror = resolve; // Don't fail on preload errors
                document.head.appendChild(link);
            });
        });

        await Promise.allSettled(preloadPromises);
        this.resourcesPreloaded = true;
    }

    async loadWidget() {
        // Show skeleton loading instead of basic loading
        this.showSkeletonLoader();
        
        try {
            await super.loadWidget();
        } catch (error) {
            this.handleError(error);
        }
    }

    showSkeletonLoader() {
        this.container.innerHTML = `
            <div class="skeleton-loader">
                <div class="skeleton-header"></div>
                <div class="skeleton-content">
                    <div class="skeleton-team">
                        <div class="skeleton-logo"></div>
                        <div class="skeleton-name"></div>
                    </div>
                    <div class="skeleton-score"></div>
                    <div class="skeleton-team">
                        <div class="skeleton-logo"></div>
                        <div class="skeleton-name"></div>
                    </div>
                </div>
            </div>
        `;
    }
}

// Usage with performance monitoring
const performantManager = new PerformantWidgetManager('scoreboard-widget', {
    widget: 'sr:match:scoreboard',
    matchId: 12345678
});

// Start performance monitoring
performance.mark('widget-init-start');
performantManager.initLazyLoading();
class MonitoredWidgetManager extends PerformantWidgetManager {
    constructor(containerId, widgetConfig) {
        super(containerId, widgetConfig);
        this.metrics = {
            loadStartTime: null,
            scriptLoadTime: null,
            widgetRenderTime: null,
            totalLoadTime: null,
            errorCount: 0,
            retryCount: 0
        };
        this.setupGlobalErrorHandling();
    }

    setupGlobalErrorHandling() {
        // Capture unhandled widget errors
        window.addEventListener('error', (event) => {
            if (event.filename && event.filename.includes('widgets.sir.sportradar.com')) {
                this.reportError({
                    type: 'script_error',
                    message: event.message,
                    filename: event.filename,
                    lineno: event.lineno,
                    colno: event.colno
                });
            }
        });

        // Capture promise rejections
        window.addEventListener('unhandledrejection', (event) => {
            if (event.reason && event.reason.toString().includes('widget')) {
                this.reportError({
                    type: 'promise_rejection',
                    message: event.reason.toString(),
                    stack: event.reason.stack
                });
            }
        });
    }

    async loadWidget() {
        this.metrics.loadStartTime = performance.now();
        performance.mark('widget-load-start');
        
        try {
            await super.loadWidget();
            this.recordSuccessMetrics();
        } catch (error) {
            this.metrics.errorCount++;
            this.handleError(error);
        }
    }

    recordSuccessMetrics() {
        const endTime = performance.now();
        this.metrics.totalLoadTime = endTime - this.metrics.loadStartTime;
        
        performance.mark('widget-load-end');
        performance.measure('widget-total-load', 'widget-load-start', 'widget-load-end');
        
        // Report metrics to analytics
        this.reportMetrics({
            widget_load_time: this.metrics.totalLoadTime,
            widget_type: this.config.widget,
            match_id: this.config.matchId,
            retry_count: this.retryCount,
            success: true
        });
        
        // Log to console for debugging
        console.log('Widget Metrics:', this.metrics);
    }

    reportMetrics(metrics) {
        // Google Analytics 4
        if (window.gtag) {
            gtag('event', 'widget_performance', {
                custom_map: { metric_1: 'load_time' },
                metric_1: Math.round(metrics.widget_load_time)
            });
        }
        
        // Custom analytics endpoint
        if (this.config.analyticsEndpoint) {
            fetch(this.config.analyticsEndpoint, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    timestamp: new Date().toISOString(),
                    page_url: window.location.href,
                    user_agent: navigator.userAgent,
                    ...metrics
                })
            }).catch(err => console.warn('Analytics reporting failed:', err));
        }
    }

    reportError(error) {
        const errorReport = {
            timestamp: new Date().toISOString(),
            page_url: window.location.href,
            user_agent: navigator.userAgent,
            widget_type: this.config.widget,
            match_id: this.config.matchId,
            error_type: error.type || 'unknown',
            error_message: error.message,
            stack_trace: error.stack,
            retry_count: this.retryCount,
            metrics: this.metrics
        };

        // Log to console
        console.error('Widget Error Report:', errorReport);

        // Send to error tracking service
        if (window.Sentry) {
            Sentry.captureException(error, {
                tags: {
                    component: 'widget',
                    widget_type: this.config.widget
                },
                extra: errorReport
            });
        }

        // Custom error endpoint
        if (this.config.errorEndpoint) {
            fetch(this.config.errorEndpoint, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(errorReport)
            }).catch(err => console.warn('Error reporting failed:', err));
        }
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Secure Widget Integration</title>
    
    <!-- Content Security Policy -->
    <meta http-equiv="Content-Security-Policy" content="
        default-src 'self';
        script-src 'self' 'unsafe-inline' https://widgets.sir.sportradar.com;
        style-src 'self' 'unsafe-inline' https://widgets.sir.sportradar.com https://fonts.googleapis.com;
        font-src 'self' https://fonts.gstatic.com;
        img-src 'self' data: https://widgets.sir.sportradar.com https://*.sportradar.com;
        connect-src 'self' https://api.sportradar.com https://widgets.sir.sportradar.com;
        frame-src 'none';
        object-src 'none';
    ">
    
    <!-- Additional security headers -->
    <meta http-equiv="X-Content-Type-Options" content="nosniff">
    <meta http-equiv="X-Frame-Options" content="DENY">
    <meta http-equiv="Referrer-Policy" content="strict-origin-when-cross-origin">
</head>
<body>
    <main>
        <h1>Live Match Scoreboard</h1>
        <div 
            id="scoreboard-widget" 
            class="widget-container"
            role="region"
            aria-label="Live match scoreboard"
            aria-live="polite"
            aria-busy="true"
        >
            <div class="widget-loading" aria-label="Loading match data">
                <span class="sr-only">Loading match data, please wait...</span>
                <div class="spinner" aria-hidden="true"></div>
                Loading match data...
            </div>
        </div>
    </main>

    <script>
        class SecureWidgetManager extends MonitoredWidgetManager {
            constructor(containerId, widgetConfig) {
                super(containerId, widgetConfig);
                this.validateConfiguration();
                this.setupSecurityHeaders();
            }

            validateConfiguration() {
                // Validate required parameters
                if (!this.config.matchId || typeof this.config.matchId !== 'number') {
                    throw new Error('Invalid or missing matchId');
                }
                
                if (!this.config.widget || typeof this.config.widget !== 'string') {
                    throw new Error('Invalid or missing widget type');
                }
                
                // Sanitize string inputs
                if (this.config.title) {
                    this.config.title = this.sanitizeString(this.config.title);
                }
                
                // Validate numeric inputs
                if (this.config.seasonId && !Number.isInteger(this.config.seasonId)) {
                    throw new Error('Invalid seasonId - must be an integer');
                }
            }

            sanitizeString(input) {
                if (typeof input !== 'string') return '';
                
                // Remove potentially dangerous characters
                return input
                    .replace(/[<>]/g, '') // Remove angle brackets
                    .replace(/javascript:/gi, '') // Remove javascript: protocol
                    .replace(/on\w+=/gi, '') // Remove event handlers
                    .trim()
                    .substring(0, 200); // Limit length
            }

            setupSecurityHeaders() {
                // Verify CSP is in place
                const metaCSP = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
                if (!metaCSP) {
                    console.warn('Content Security Policy not found - consider adding CSP headers');
                }
                
                // Check for secure context
                if (!window.isSecureContext) {
                    console.warn('Insecure context detected - widgets should be served over HTTPS');
                }
            }

            async loadWidgetScript() {
                // Verify script integrity
                const expectedOrigin = 'https://widgets.sir.sportradar.com';
                
                if (!this.config.allowInsecure && !window.location.protocol.startsWith('https')) {
                    throw new Error('Widgets require HTTPS in production');
                }

                return super.loadWidgetScript();
            }

            initializeWidget() {
                // Add accessibility attributes
                this.container.setAttribute('aria-busy', 'false');
                this.container.setAttribute('aria-live', 'polite');
                
                return super.initializeWidget();
            }

            onSuccess() {
                // Update accessibility state
                this.container.setAttribute('aria-busy', 'false');
                this.container.removeAttribute('aria-label');
                
                // Announce success to screen readers
                this.announceToScreenReader('Match data loaded successfully');
                
                super.onSuccess();
            }

            announceToScreenReader(message) {
                const announcement = document.createElement('div');
                announcement.setAttribute('aria-live', 'assertive');
                announcement.setAttribute('aria-atomic', 'true');
                announcement.style.position = 'absolute';
                announcement.style.left = '-10000px';
                announcement.style.width = '1px';
                announcement.style.height = '1px';
                announcement.style.overflow = 'hidden';
                
                document.body.appendChild(announcement);
                announcement.textContent = message;
                
                setTimeout(() => {
                    document.body.removeChild(announcement);
                }, 1000);
            }
        }

        // Initialize secure widget manager
        const secureManager = new SecureWidgetManager('scoreboard-widget', {
            widget: 'sr:match:scoreboard',
            matchId: 12345678,
            allowInsecure: false // Enforce HTTPS in production
        });

        secureManager.initLazyLoading();
    </script>
    
    <style>
        .sr-only {
            position: absolute !important;
            width: 1px !important;
            height: 1px !important;
            padding: 0 !important;
            margin: -1px !important;
            overflow: hidden !important;
            clip: rect(0, 0, 0, 0) !important;
            border: 0 !important;
        }
        
        .spinner {
            width: 20px;
            height: 20px;
            border: 2px solid #f3f3f3;
            border-top: 2px solid #1976d2;
            border-radius: 50%;
            animation: spin 1s linear infinite;
            display: inline-block;
            margin-right: 10px;
        }
        
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        
        .widget-container {
            border: 1px solid #e0e0e0;
            border-radius: 8px;
            padding: 16px;
            background: white;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        
        .widget-container:focus-within {
            outline: 2px solid #1976d2;
            outline-offset: 2px;
        }
    </style>
</body>
</html>
class ProductionWidgetManager extends SecureWidgetManager {
    constructor(containerId, widgetConfig) {
        super(containerId, widgetConfig);
        this.deploymentChecks = [];
        this.healthCheckInterval = null;
        this.performanceObserver = null;
        this.runDeploymentChecks();
    }

    async runDeploymentChecks() {
        console.log('🚀 Running production deployment checks...');
        
        const checks = [
            { name: 'HTTPS', check: () => window.location.protocol === 'https:' },
            { name: 'CSP', check: () => document.querySelector('meta[http-equiv="Content-Security-Policy"]') },
            { name: 'Error Handling', check: () => typeof this.reportError === 'function' },
            { name: 'Analytics', check: () => window.gtag || this.config.analyticsEndpoint },
            { name: 'Accessibility', check: () => this.container.hasAttribute('aria-label') },
            { name: 'Performance Monitoring', check: () => 'PerformanceObserver' in window },
            { name: 'Valid Configuration', check: () => this.validateProductionConfig() }
        ];

        for (const check of checks) {
            try {
                const passed = await check.check();
                this.deploymentChecks.push({
                    name: check.name,
                    status: passed ? 'PASS' : 'FAIL',
                    timestamp: new Date().toISOString()
                });
                console.log(`${passed ? '✅' : '❌'} ${check.name}`);
            } catch (error) {
                this.deploymentChecks.push({
                    name: check.name,
                    status: 'ERROR',
                    error: error.message,
                    timestamp: new Date().toISOString()
                });
                console.log(`❌ ${check.name}: ${error.message}`);
            }
        }

        this.reportDeploymentStatus();
    }

    validateProductionConfig() {
        const requiredFields = ['widget', 'matchId'];
        const missingFields = requiredFields.filter(field => !this.config[field]);
        
        if (missingFields.length > 0) {
            throw new Error(`Missing required fields: ${missingFields.join(', ')}`);
        }

        // Check for development-only settings
        if (this.config.debug && window.location.hostname !== 'localhost') {
            console.warn('Debug mode enabled in production environment');
        }

        return true;
    }

    async loadWidget() {
        // Start health monitoring
        this.startHealthMonitoring();
        
        // Initialize performance monitoring
        this.initPerformanceMonitoring();
        
        try {
            await super.loadWidget();
            this.reportDeploymentSuccess();
        } catch (error) {
            this.reportDeploymentFailure(error);
            throw error;
        }
    }

    startHealthMonitoring() {
        // Periodic health checks
        this.healthCheckInterval = setInterval(() => {
            this.performHealthCheck();
        }, 60000); // Check every minute

        // Clean up on page unload
        window.addEventListener('beforeunload', () => {
            if (this.healthCheckInterval) {
                clearInterval(this.healthCheckInterval);
            }
            if (this.performanceObserver) {
                this.performanceObserver.disconnect();
            }
        });
    }

    performHealthCheck() {
        const healthMetrics = {
            timestamp: new Date().toISOString(),
            widget_responsive: this.isWidgetResponsive(),
            memory_usage: this.getMemoryUsage(),
            error_rate: this.calculateErrorRate(),
            load_time: this.metrics.totalLoadTime
        };

        // Report to monitoring service
        if (this.config.healthCheckEndpoint) {
            fetch(this.config.healthCheckEndpoint, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(healthMetrics)
            }).catch(err => console.warn('Health check reporting failed:', err));
        }

        // Log locally for debugging
        console.log('Health Check:', healthMetrics);
    }

    isWidgetResponsive() {
        try {
            // Check if widget container has content
            const hasContent = this.container.children.length > 0;
            
            // Check if widget is visible
            const rect = this.container.getBoundingClientRect();
            const isVisible = rect.width > 0 && rect.height > 0;
            
            return hasContent && isVisible;
        } catch (error) {
            return false;
        }
    }

    getMemoryUsage() {
        if ('memory' in performance) {
            return {
                used: Math.round(performance.memory.usedJSHeapSize / 1048576), // MB
                total: Math.round(performance.memory.totalJSHeapSize / 1048576), // MB
                limit: Math.round(performance.memory.jsHeapSizeLimit / 1048576) // MB
            };
        }
        return null;
    }

    calculateErrorRate() {
        const totalAttempts = this.retryCount + 1;
        return totalAttempts > 0 ? (this.metrics.errorCount / totalAttempts) * 100 : 0;
    }

    initPerformanceMonitoring() {
        if ('PerformanceObserver' in window) {
            this.performanceObserver = new PerformanceObserver((list) => {
                for (const entry of list.getEntries()) {
                    if (entry.name.includes('widget')) {
                        this.reportPerformanceEntry(entry);
                    }
                }
            });

            this.performanceObserver.observe({ entryTypes: ['measure', 'navigation', 'resource'] });
        }
    }

    reportPerformanceEntry(entry) {
        const performanceData = {
            name: entry.name,
            duration: entry.duration,
            startTime: entry.startTime,
            entryType: entry.entryType,
            timestamp: new Date().toISOString()
        };

        console.log('Performance Entry:', performanceData);
        
        // Report to analytics
        this.reportMetrics(performanceData);
    }

    reportDeploymentStatus() {
        const report = {
            timestamp: new Date().toISOString(),
            page_url: window.location.href,
            user_agent: navigator.userAgent,
            checks: this.deploymentChecks,
            overall_status: this.deploymentChecks.every(check => check.status === 'PASS') ? 'HEALTHY' : 'ISSUES_DETECTED'
        };

        console.log('📊 Deployment Status Report:', report);
        
        if (this.config.deploymentReportEndpoint) {
            fetch(this.config.deploymentReportEndpoint, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(report)
            }).catch(err => console.warn('Deployment reporting failed:', err));
        }
    }

    reportDeploymentSuccess() {
        performance.mark('widget-deployment-success');
        console.log('🎉 Widget deployment successful');
        
        this.reportMetrics({
            deployment_status: 'success',
            deployment_time: performance.now(),
            environment: this.getEnvironment()
        });
    }

    reportDeploymentFailure(error) {
        performance.mark('widget-deployment-failure');
        console.error('💥 Widget deployment failed:', error);
        
        this.reportError({
            type: 'deployment_failure',
            message: error.message,
            stack: error.stack,
            environment: this.getEnvironment(),
            deployment_checks: this.deploymentChecks
        });
    }

    getEnvironment() {
        const hostname = window.location.hostname;
        if (hostname === 'localhost' || hostname === '127.0.0.1') return 'development';
        if (hostname.includes('staging') || hostname.includes('test')) return 'staging';
        return 'production';
    }
}

// Production deployment with comprehensive configuration
const productionManager = new ProductionWidgetManager('scoreboard-widget', {
    widget: 'sr:match:scoreboard',
    matchId: 12345678,
    
    // Analytics endpoints
    analyticsEndpoint: 'https://analytics.yoursite.com/api/events',
    errorEndpoint: 'https://monitoring.yoursite.com/api/errors',
    healthCheckEndpoint: 'https://monitoring.yoursite.com/api/health',
    deploymentReportEndpoint: 'https://monitoring.yoursite.com/api/deployment',
    
    // Security settings  
    allowInsecure: false,
    
    // Performance settings
    maxRetries: 3,
    loadTimeout: 15000,
    
    // Feature flags
    debug: false,
    enableHealthChecks: true,
    enablePerformanceMonitoring: true
});

// Initialize with full monitoring
productionManager.initLazyLoading();