Widget Customization
Customize the ExperienceLocal booking widget to match your brand. From simple color changes to advanced JavaScript integration, make the widget uniquely yours.
Overview
The ExperienceLocal widget is designed to be flexible and customizable. Whether you're a marketing team member looking to match brand colors or a developer building a deep integration, this guide covers everything you need.
Visual Styling
Colors, fonts, themes
Layout Options
Templates, columns, spacing
Responsive
Mobile-optimized design
JavaScript API
Programmatic control
No-Code Customization
Most customization options can be configured directly in your dashboard without writing any code. Go to Dashboard → Properties → [Your Property] → Widget Settingsto use the visual customization tools.
Embedding Options
Choose the right embedding approach for your use case.
Single Widget Instance
The most common approach. Embed one widget showing all your experiences and resources.
<!-- Basic Widget Embed -->
<div id="el-widget"></div>
<script
src="https://widget.experiencelocal.io/v1/widget.js"
data-property="YOUR_PROPERTY_KEY">
</script>Best for:
- • Single experiences/activities page
- • Simple website structure
- • All content types shown together
- • Most hotels start here
Visual Customization
Make the widget match your brand identity with colors, fonts, and themes.
Primary Color
Your brand's primary color for buttons, links, and accents
data-primary-colordata-primary-color="#8b5cf6"Theme
Overall color scheme of the widget
data-themedata-theme="dark"Font FamilyScale+
Typography to match your website
data-font-familydata-font-family="Inter, sans-serif"Border Radius
Roundness of buttons and cards
data-border-radiusdata-border-radius="large"Show Powered ByGrowth+
Display or hide the ExperienceLocal badge
data-show-powered-bydata-show-powered-by="false"Example: Custom Branding
<!-- Customized Widget with Brand Colors -->
<div id="el-widget"></div>
<script
src="https://widget.experiencelocal.io/v1/widget.js"
data-property="YOUR_PROPERTY_KEY"
data-theme="light"
data-primary-color="#2563eb">
</script>This example sets a custom blue theme color to match your brand. The widget will use this color for all interactive elements, CTAs, and highlights.
White-Label Branding
Remove ExperienceLocal branding and make the widget fully your own. Available on paid plans.
Free Plan
- Small "Powered by ExperienceLocal" badge
- Basic color customization
- All core booking features
Paid Plans (Growth+)
- Remove "Powered by" badge completely
- Full color customization
- Custom fonts (Scale+)
- Custom CSS (Enterprise)
How to Enable White-Label
- 1. Upgrade to Growth, Scale, or Enterprise plan
- 2. Go to Dashboard → Properties → [Property] → Widget Settings
- 3. Toggle off "Show Powered By Badge"
- 4. Changes apply immediately—no code changes needed
Layout Options & Templates
Choose from pre-built templates optimized for different use cases. Each template provides a unique user experience while maintaining consistent booking functionality.
Classic Grid
Card-based grid layout
Best for:
- General-purpose experiences
- Visual browsing
- Multiple categories
Luxury Carousel
Full-width carousel with autoplay
Best for:
- Hero section embedding
- Showcasing featured experiences
- High-end properties
Compact List
Dense information display
Best for:
- Mobile-first design
- Quick availability checking
- Resource booking (gym, spa)
Magazine Masonry
Pinterest-style layout
Best for:
- Visual storytelling
- Diverse content types
- Lifestyle/boutique hotels
Timeline Calendar
Calendar-based view
Best for:
- Event booking
- Date-specific activities
- Workshop scheduling
Minimal Cards
Clean, text-focused design
Best for:
- Modern, minimalist brands
- Typography-focused sites
- Professional services
Choosing a Template
Templates can be configured per widget instance in your dashboard. Most hotels use Classic Grid for experiences and Compact List for amenity bookings. Preview all templates at experiencelocal.io/demos.
Mobile Optimization
The widget is fully responsive and mobile-optimized out of the box. Here's how it adapts to different screen sizes.
Desktop (1200px+)
- • Multi-column grid layouts
- • Hover interactions
- • Side-by-side comparison
- • Full detail visibility
Tablet (768px - 1199px)
- • 2-column layouts
- • Touch-optimized buttons
- • Collapsible filters
- • Readable text sizes
Mobile (< 768px)
- • Single-column stacking
- • Large tap targets (44px+)
- • Swipe gestures
- • Optimized images
Mobile Best Practices
- Test on real devices: Use your phone to test the booking flow, not just browser dev tools.
- Ensure parent containers are responsive: The widget adapts to its container's width, so make sure the container is fluid.
- Use appropriate templates: Compact List and Minimal Cards work best on mobile.
- Avoid horizontal scrolling: Let the widget handle its own responsive layout.
Mobile Performance
On mobile devices with slower connections, the widget loads progressively. A loading skeleton appears immediately while content fetches in the background. Optimize your site's overall mobile performance for the best user experience.
Advanced JavaScript API
For developers: programmatically control the widget, listen to events, and integrate with your PMS, CRM, or analytics systems.
Widget API Methods
All methods are available on the global window.ExperienceLocalWidget object after the widget loads.
// Advanced JavaScript API Usage
// Update stay dates dynamically (useful for PMS integration)
window.ExperienceLocalWidget.updateStayDates('2026-06-15', '2026-06-20');
// Update specific instance only
window.ExperienceLocalWidget.updateStayDates(
'2026-06-15',
'2026-06-20',
'pool-amenities' // instance key
);
// Switch between browse and during-stay mode
window.ExperienceLocalWidget.setMode('during-stay');
// Get current widget configuration
const config = window.ExperienceLocalWidget.getConfig();
console.log('Current theme:', config.theme);
console.log('Stay dates:', config.stayStart, config.stayEnd);
// Get all active instances
const instances = window.ExperienceLocalWidget.getInstances();
instances.forEach((instance, key) => {
console.log('Instance:', key, instance);
});Event Listeners
Listen for widget lifecycle and booking events to integrate with your systems.
// Listen for Widget Events
// Widget ready event
document.querySelector('#el-widget')
.addEventListener('el-widget-ready', (event) => {
console.log('Widget loaded:', event.detail.instanceKey);
// Initialize analytics, tracking, etc.
});
// Booking completed event
document.querySelector('#el-widget')
.addEventListener('el-booking-complete', (event) => {
console.log('Booking completed!');
console.log('Booking #:', event.detail.bookingNumber);
console.log('Booking ID:', event.detail.bookingId);
// Track conversion in analytics
gtag('event', 'purchase', {
transaction_id: event.detail.bookingId,
// Add more tracking data
});
});
// Widget error event
document.querySelector('#el-widget')
.addEventListener('el-widget-error', (event) => {
console.error('Widget error:', event.detail.instanceKey);
// Handle error, show fallback UI, etc.
});PMS Integration Example
Automatically update the widget based on PMS check-in/check-out dates and post bookings back to the guest folio.
// PMS Integration Example (Opera, Mews, Cloudbeds, etc.)
// Listen for check-in date changes in your PMS
pms.on('reservation.selected', (reservation) => {
const checkIn = reservation.checkInDate; // '2026-06-15'
const checkOut = reservation.checkOutDate; // '2026-06-20'
// Update widget to show experiences during guest stay
window.ExperienceLocalWidget.updateStayDates(checkIn, checkOut);
window.ExperienceLocalWidget.setMode('during-stay');
});
// Clear dates when reservation is deselected
pms.on('reservation.deselected', () => {
window.ExperienceLocalWidget.updateStayDates(null, null);
window.ExperienceLocalWidget.setMode('browse');
});
// Track bookings back to guest folio
document.querySelector('#el-widget')
.addEventListener('el-booking-complete', (event) => {
// Post booking to PMS folio
pms.addFolioCharge({
guestId: reservation.guestId,
amount: event.detail.amount,
description: 'Experience Booking: ' + event.detail.bookingNumber,
externalReference: event.detail.bookingId
});
});API Stability
The JavaScript API is stable and versioned. We maintain backward compatibility and provide deprecation notices at least 6 months before removing any methods. Check the API Changelog for updates.
Testing Your Customizations
Before deploying to production, thoroughly test your widget customizations.
Visual Testing Checklist
- □Colors match your brand guidelines
- □Fonts are consistent with your website
- □Dark mode (if used) has sufficient contrast
- □Images load and display correctly
- □Widget doesn't conflict with page CSS
Responsive Testing
Test these breakpoints to ensure responsive behavior:
<!-- Responsive Testing -->
<style>
/* Container for different viewport previews */
.responsive-preview {
display: grid;
gap: 2rem;
margin: 2rem 0;
}
/* Desktop preview */
.preview-desktop {
width: 100%;
border: 2px solid #e2e8f0;
border-radius: 8px;
}
/* Tablet preview */
.preview-tablet {
max-width: 768px;
margin: 0 auto;
border: 2px solid #e2e8f0;
border-radius: 8px;
}
/* Mobile preview */
.preview-mobile {
max-width: 375px;
margin: 0 auto;
border: 2px solid #e2e8f0;
border-radius: 8px;
}
</style>
<!-- Test at different breakpoints -->
<div class="responsive-preview">
<div class="preview-desktop">
<h3>Desktop (1200px+)</h3>
<div id="el-widget-desktop"></div>
</div>
<div class="preview-tablet">
<h3>Tablet (768px)</h3>
<div id="el-widget-tablet"></div>
</div>
<div class="preview-mobile">
<h3>Mobile (375px)</h3>
<div id="el-widget-mobile"></div>
</div>
</div>Functional Testing Checklist
- □Widget loads within 2 seconds
- □All experiences display correctly
- □Filtering and search work
- □Date picker functions properly
- □Checkout flow completes successfully
- □Test payments with Stripe test cards
- □Confirmation emails arrive
Browser Testing
Test in Chrome, Safari, Firefox, and Edge. The widget supports all modern browsers (last 2 versions). For IE11 support (not recommended in 2026), contact our enterprise team.
Best Practices
Follow these recommendations for optimal widget performance and user experience.
Use dashboard customization first
Configure colors, layouts, and settings in your dashboard before resorting to custom code. This ensures updates work smoothly and reduces maintenance.
Load the script asynchronously
The widget script loads async by default. Don't add defer or async attributes—they can cause race conditions.
Keep embed codes up to date
We occasionally release new widget versions (/v1/, /v2/, etc.). Older versions are supported for 12 months after deprecation. Update when notified.
Monitor widget errors
Listen for el-widget-error events and log them to your monitoring system (Sentry, Datadog, etc.). This helps catch issues before guests report them.
Accessibility matters
The widget is WCAG 2.1 AA compliant. Maintain this by ensuring sufficient color contrast (especially with custom colors) and not hiding focus indicators.
Avoid global CSS that affects iframes
Don't apply styles like iframe {width: 100% !important} globally. This can break the widget's responsive behavior. Target your own iframes specifically.
Test payment flows thoroughly
Always test the complete booking flow after customization changes. Use Stripe test cards and verify emails arrive correctly before pushing to production.
Custom CSSEnterprise
Enterprise customers can inject custom CSS to deeply customize the widget's appearance beyond the standard options.
Example Custom CSS
/* Advanced Custom CSS */
/* Override widget container */
#el-widget {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
/* Responsive adjustments */
@media (max-width: 768px) {
#el-widget {
padding: 1rem;
}
}
/* Custom scrollbar for widget iframe */
#el-widget iframe {
border-radius: 12px;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
/* Loading state */
#el-widget:empty::before {
content: 'Loading experiences...';
display: block;
text-align: center;
padding: 3rem;
color: #64748b;
font-family: system-ui, -apple-system, sans-serif;
}Custom CSS Support
Custom CSS is powerful but can break with widget updates. We provide best-effort support for custom CSS but cannot guarantee compatibility across versions. Document your customizations and test thoroughly after widget updates.
Need Custom CSS?
Custom CSS is available exclusively on the Enterprise plan. Contact our sales team to discuss your customization requirements.
Contact SalesRelated Documentation
Embedding the Widget
Basic widget installation and setup guide for all platforms.
Widget Analytics
Track widget performance, conversions, and user behavior.
PMS Integrations
Connect your PMS (Opera, Mews, Cloudbeds) with the widget.
Plans & Features
Compare plan features including white-label options.
Ready to Customize?
Head to your dashboard to start customizing your widget. Use the visual editor for quick changes or dive into the code for advanced integrations.
Need Help?
Our support team is available to help with customization questions. For complex integrations or custom development, we also offer professional services. Contact us to learn more.