Skip to main content

Overview

After receiving a session token from the handshake endpoint, you’ll embed Sticker into your application using an HTML iframe. This guide covers implementation, customization, and best practices.

Basic iframe Implementation

The simplest integration uses a standard HTML iframe:
<iframe
  src="https://app.sticker.com/embed?session_key=YOUR_SESSION_TOKEN"
  width="100%"
  height="800px"
  frameborder="0"
  allow="payment"
  sandbox="allow-same-origin allow-scripts allow-forms allow-popups"
  style="border: none;"
/>

iframe Attributes

Required Attributes

src
string
required
The Sticker embed URL with session_key parameter
https://app.sticker.com/embed?session_key={token}
sandbox
string
required
Security sandbox flags. Must include:
  • allow-same-origin - Required for local storage
  • allow-scripts - Required for app functionality
  • allow-forms - Required for checkout
  • allow-popups - Required for payment processing
width
string
Set to 100% for responsive design
height
string
Minimum 800px recommended. See responsive height section below.
allow
string
Feature policy. Include payment for checkout:
allow="payment"
frameborder
string
Set to 0 to remove border
title
string
Accessibility label for screen readers:
title="Medical Supplies"

URL Parameters

Customize the embedded experience with URL parameters:
session_key
string
required
The authentication token from the handshake endpoint
theme
string
Color theme: light (default) or dark
?session_key={token}&theme=dark
category
string
Initial product category to display
?session_key={token}&category=gloves
hide_nav
boolean
Hide the top navigation bar (useful if embedding in a modal)
?session_key={token}&hide_nav=true
redirect_on_complete
string
URL to redirect to after order completion
?session_key={token}&redirect_on_complete=https://yourapp.com/success

Responsive Design

Fixed Height

Simple approach with a fixed minimum height:
.supplies-container {
  width: 100%;
  height: 100vh;
  min-height: 800px;
}

.supplies-iframe {
  width: 100%;
  height: 100%;
  border: none;
}

Dynamic Height with postMessage

For a truly responsive experience, listen to height change messages from the iframe:
// Listen for height updates from the iframe
window.addEventListener('message', (event) => {
  // Verify the message is from Sticker
  if (event.origin !== 'https://app.sticker.com') {
    return;
  }
  
  // Handle different message types
  if (event.data.type === 'sticker:height') {
    const iframe = document.getElementById('sticker-iframe');
    iframe.style.height = event.data.height + 'px';
  }
});
Sticker sends height update messages whenever content changes. This ensures the iframe is always the perfect size without scrollbars.

Framework Integration Examples

import { useState, useEffect, useRef } from 'react';

function StickerEmbed({ sessionKey }) {
  const iframeRef = useRef(null);
  const [height, setHeight] = useState(800);

  useEffect(() => {
    // Listen for height changes from iframe
    const handleMessage = (event) => {
      if (event.origin !== 'https://app.sticker.com') return;
      
      if (event.data.type === 'sticker:height') {
        setHeight(event.data.height);
      }
      
      if (event.data.type === 'sticker:order_complete') {
        console.log('Order completed:', event.data.order_id);
        // Handle order completion
      }
    };

    window.addEventListener('message', handleMessage);
    return () => window.removeEventListener('message', handleMessage);
  }, []);

  return (
    <iframe
      ref={iframeRef}
      src={`https://app.sticker.com/embed?session_key=${sessionKey}`}
      width="100%"
      height={`${height}px`}
      frameBorder="0"
      allow="payment"
      sandbox="allow-same-origin allow-scripts allow-forms allow-popups"
      title="Medical Supplies"
      style={{ border: 'none', transition: 'height 0.3s ease' }}
    />
  );
}

postMessage API

Sticker communicates with your application using the postMessage API. Here are the events you can listen for:

Events from Sticker (iframe → parent)

Sent whenever the iframe content height changes
{
  type: 'sticker:height',
  height: 1200  // Height in pixels
}
Sent when the iframe has loaded and is ready
{
  type: 'sticker:ready',
  version: '1.0.0'
}
Sent when items are added/removed from cart
{
  type: 'sticker:cart_updated',
  item_count: 3,
  total: 45.99
}
Sent when an order is successfully placed
{
  type: 'sticker:order_complete',
  order_id: '550e8400-e29b-41d4-a716-446655440000',
  total: 45.99
}
Sent when user navigates to different pages
{
  type: 'sticker:navigation',
  page: 'cart' | 'checkout' | 'products' | 'orders'
}
Sent when an error occurs
{
  type: 'sticker:error',
  error: 'Payment failed',
  code: 'PAYMENT_ERROR'
}

Commands to Sticker (parent → iframe)

You can send commands to the iframe to control its behavior:
const iframe = document.getElementById('sticker-iframe');

// Navigate to a specific page
iframe.contentWindow.postMessage({
  type: 'sticker:navigate',
  page: 'cart'
}, 'https://app.sticker.com');

// Refresh the content
iframe.contentWindow.postMessage({
  type: 'sticker:refresh'
}, 'https://app.sticker.com');
Always specify the target origin when sending messages to prevent security issues.

Loading States

Show a loading indicator while the iframe initializes:
function StickerWithLoading({ sessionKey }) {
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    const handleMessage = (event) => {
      if (event.origin !== 'https://app.sticker.com') return;
      
      if (event.data.type === 'sticker:ready') {
        setIsLoading(false);
      }
    };

    window.addEventListener('message', handleMessage);
    return () => window.removeEventListener('message', handleMessage);
  }, []);

  return (
    <div style={{ position: 'relative' }}>
      {isLoading && (
        <div style={{
          position: 'absolute',
          top: 0,
          left: 0,
          right: 0,
          bottom: 0,
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          backgroundColor: '#f5f5f5'
        }}>
          <div>Loading supplies...</div>
        </div>
      )}
      
      <iframe
        src={`https://app.sticker.com/embed?session_key=${sessionKey}`}
        width="100%"
        height="800px"
        frameBorder="0"
        allow="payment"
        sandbox="allow-same-origin allow-scripts allow-forms allow-popups"
        style={{ border: 'none', opacity: isLoading ? 0 : 1 }}
      />
    </div>
  );
}

Styling & Theming

Container Styling

Style the container div for better visual integration:
.supplies-wrapper {
  width: 100%;
  max-width: 1400px;
  margin: 0 auto;
  padding: 20px;
  background: #f9f9f9;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.supplies-iframe {
  width: 100%;
  height: 800px;
  border: none;
  border-radius: 8px;
  overflow: hidden;
}

Dark Mode

Support dark mode by passing the theme parameter:
const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
const theme = isDarkMode ? 'dark' : 'light';

const iframeSrc = `https://app.sticker.com/embed?session_key=${sessionKey}&theme=${theme}`;

Security Considerations

Always include the sandbox attribute with minimal permissions:
sandbox="allow-same-origin allow-scripts allow-forms allow-popups"
Never use allow-top-navigation or allow-modals unless absolutely necessary.
Always verify the origin of postMessage events:
if (event.origin !== 'https://app.sticker.com') {
  return; // Ignore messages from other origins
}
Add Sticker to your CSP frame-src directive:
Content-Security-Policy: frame-src https://app.sticker.com;
Always embed Sticker over HTTPS. Mixed content (HTTP page with HTTPS iframe) will be blocked by browsers.

Mobile Optimization

Ensure the iframe works well on mobile devices:
/* Mobile-first responsive design */
.supplies-container {
  width: 100%;
  height: 100vh;
  overflow: auto;
  -webkit-overflow-scrolling: touch; /* Smooth scrolling on iOS */
}

.supplies-iframe {
  width: 100%;
  height: 100%;
  min-height: 600px;
  border: none;
}

/* Adjust for smaller screens */
@media (max-width: 768px) {
  .supplies-container {
    padding: 0;
  }
  
  .supplies-iframe {
    min-height: calc(100vh - 60px); /* Account for header */
  }
}
On mobile, consider using fullscreen mode for the best user experience. The supplies module is fully responsive and optimized for mobile devices.

Modal/Overlay Integration

Embed Sticker in a modal for a non-invasive integration:
function SuppliesModal({ isOpen, onClose, sessionKey }) {
  if (!isOpen) return null;

  return (
    <div style={{
      position: 'fixed',
      top: 0,
      left: 0,
      right: 0,
      bottom: 0,
      backgroundColor: 'rgba(0, 0, 0, 0.5)',
      zIndex: 1000,
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'center'
    }}>
      <div style={{
        width: '90%',
        height: '90%',
        backgroundColor: 'white',
        borderRadius: '8px',
        overflow: 'hidden',
        position: 'relative'
      }}>
        <button
          onClick={onClose}
          style={{
            position: 'absolute',
            top: '10px',
            right: '10px',
            zIndex: 1001
          }}
        >
          Close
        </button>
        
        <iframe
          src={`https://app.sticker.com/embed?session_key=${sessionKey}&hide_nav=true`}
          width="100%"
          height="100%"
          frameBorder="0"
          allow="payment"
          sandbox="allow-same-origin allow-scripts allow-forms allow-popups"
        />
      </div>
    </div>
  );
}

Troubleshooting

Possible causes:
  • Invalid or expired session token
  • CORS/CSP blocking the iframe
  • Network connectivity issues
Solutions:
  • Generate a fresh session token
  • Check browser console for errors
  • Verify CSP headers allow frame-src
Cause: Session token is invalid, expired, or already usedSolution: Generate a new session token via the handshake endpoint
Cause: Missing allow="payment" attribute or insufficient sandbox permissionsSolution: Add allow="payment" and ensure sandbox includes allow-popups
Cause: Not listening to postMessage height eventsSolution: Implement the postMessage listener for sticker:height events

Best Practices

Always Verify Origin

Check event.origin before processing postMessage events

Use Loading States

Show loading indicators for better UX

Handle Errors Gracefully

Display user-friendly error messages

Test on Mobile

Ensure the experience works well on all devices

Monitor Performance

Track iframe load times and errors

Refresh Tokens

Generate new tokens if the user returns after >5 minutes

Next Steps