Embeddy API Reference

Technical reference for integrating Embeddy widgets into your applications. Covers the iframe embed API, JavaScript SDK, widget configuration, events and callbacks, the postMessage communication protocol, authentication for protected widgets, and rate limiting.

Developer~12 min read

1. Iframe Embed API

The iframe embed is the simplest way to add an Embeddy widget to any web page. It requires no JavaScript and works on every platform that supports HTML iframes.

Base URL

https://embeddy.ai/demo/{widget_id}

URL Parameters

ParameterTypeDefaultDescription
themestringlightWidget theme. Options: light, dark
hideHeaderbooleanfalseHides the default Embeddy header bar in the widget
localestringenLocale code for internationalization (e.g., es, fr, ja)

Example with URL Parameters

<iframe
  src="https://embeddy.ai/demo/abc123?theme=dark&hideHeader=true"
  width="100%"
  height="600"
  frameborder="0"
  style="border: none; border-radius: 8px;"
  allow="clipboard-write; payment"
  loading="lazy"
  title="My Widget"
></iframe>

Iframe Attributes Reference

AttributeRecommended ValueDescription
width"100%"Fill the parent container width
height"600"Height in pixels (adjust for your widget's content)
frameborder"0"Remove the default iframe border
allow"clipboard-write; payment"Permissions for clipboard access and payment APIs
loading"lazy"Defer loading until the iframe is near the viewport
title"Your title"Accessible label for screen readers (required for a11y)

2. JavaScript SDK

The JavaScript SDK provides programmatic control over widget rendering, configuration, and communication. Load the SDK from Embeddy's CDN, then call Embeddy.render() to mount a widget.

Installation

<script src="https://embeddy.ai/sdk/embed.js"></script>

Embeddy.render(options)

Renders a widget inside the specified container element. Returns an EmbeddyWidget instance for further interaction.

const widget = Embeddy.render({
  container: '#my-widget',       // CSS selector or DOM element
  widgetId: 'YOUR_WIDGET_ID',   // Required: your widget ID
  width: '100%',                 // Width (px, %, or 'auto')
  height: 600,                   // Height in pixels
  theme: 'light',                // 'light' or 'dark'
  autoResize: true,              // Auto-adjust height to content
  hideHeader: false,             // Hide Embeddy header bar
  locale: 'en',                  // Locale code
  customCSS: '',                 // Inject custom CSS into widget
  onLoad: function() { },        // Called when widget finishes loading
  onError: function(err) { },    // Called on load/runtime error
  onResize: function(dims) { }   // Called when widget dimensions change
});

Widget Instance Methods

MethodDescription
widget.destroy()Removes the widget from the DOM and cleans up event listeners
widget.reload()Reloads the widget content without removing the container
widget.setTheme(theme)Dynamically switch between 'light' and 'dark' themes
widget.resize(w, h)Programmatically resize the widget to specific dimensions
widget.postMessage(data)Send a message to the widget via the postMessage API

3. Widget Configuration Options

The following options can be passed to Embeddy.render() or appended as URL parameters to the iframe src.

OptionTypeDefaultDescription
widgetIdstring--Required. The unique identifier for your widget.
containerstring | Element--Required (SDK only). CSS selector or DOM element to mount the widget into.
widthstring | number"100%"Widget width. Accepts pixels (e.g., 400) or percentage (e.g., "100%").
heightnumber600Widget height in pixels. Ignored when autoResize is true.
themestring"light"Color theme. Options: "light", "dark".
autoResizebooleanfalseWhen true, the iframe height adjusts dynamically to match content height.
hideHeaderbooleanfalseHides the default Embeddy branding header in the widget.
customCSSstring""CSS string injected into the widget for custom styling overrides.

Custom CSS Example

Embeddy.render({
  container: '#widget',
  widgetId: 'abc123',
  customCSS: `
    body { font-family: 'Inter', sans-serif; }
    .header { background-color: #1a1a2e; }
    .btn-primary { background-color: #e94560; border-radius: 12px; }
  `
});

4. Events and Callbacks

The SDK provides lifecycle callbacks that let you respond to widget events. These are passed as options to Embeddy.render().

onLoad()

Fired when the widget has fully loaded and is interactive. Use this to hide loading spinners or trigger analytics events.

Embeddy.render({
  container: '#widget',
  widgetId: 'abc123',
  onLoad: function() {
    document.getElementById('spinner').style.display = 'none';
    analytics.track('widget_loaded', { widgetId: 'abc123' });
  }
});

onError(error)

Fired when the widget fails to load or encounters a runtime error. The error parameter contains a message string and optional code.

onError: function(error) {
  console.error('Widget error:', error.message);
  // error.code can be: 'LOAD_FAILED', 'TIMEOUT',
  //   'WIDGET_NOT_FOUND', 'AUTH_REQUIRED'
  document.getElementById('widget').innerHTML =
    '<p>Widget could not be loaded. Please try again.</p>';
}

onResize(dimensions)

Fired whenever the widget's internal content size changes (useful with autoResize: true). The dimensions object contains width and height in pixels.

onResize: function(dims) {
  console.log('New dimensions:', dims.width, 'x', dims.height);
  // Useful for adjusting surrounding layout
}

5. postMessage API

For advanced integrations, the parent page and the Embeddy widget can communicate bidirectionally using the browser's window.postMessage API. This enables scenarios like passing user context to the widget, receiving form submissions, or synchronizing state between the host page and the widget.

Sending Messages to the Widget

// Using the SDK instance
widget.postMessage({
  type: 'SET_USER',
  payload: {
    name: 'Jane Doe',
    email: 'jane@example.com',
    plan: 'pro'
  }
});

// Using raw postMessage (iframe approach)
const iframe = document.querySelector('iframe');
iframe.contentWindow.postMessage({
  type: 'SET_USER',
  payload: { name: 'Jane Doe' }
}, 'https://embeddy.ai');

Receiving Messages from the Widget

window.addEventListener('message', function(event) {
  // Always verify the origin
  if (event.origin !== 'https://embeddy.ai') return;

  const { type, payload } = event.data;

  switch (type) {
    case 'FORM_SUBMITTED':
      console.log('Form data:', payload);
      break;
    case 'NAVIGATION':
      console.log('Widget navigated to:', payload.path);
      break;
    case 'RESIZE':
      console.log('Content size changed:', payload);
      break;
  }
});

Security: Always verify event.origin before processing any messages. Only accept messages from https://embeddy.ai.

6. Authentication for Protected Widgets

If your widget uses Embeddy's built-in user authentication, embedded users will be prompted to log in through Embeddy's auth flow. For widgets embedded on sites with their own user system, you can pass authentication context to the widget using the postMessage API or URL parameters.

Passing Auth Tokens via URL

<iframe
  src="https://embeddy.ai/demo/YOUR_WIDGET_ID?token=USER_JWT_TOKEN"
  width="100%"
  height="600"
  frameborder="0"
  style="border: none;"
></iframe>

Passing Auth via SDK

Embeddy.render({
  container: '#widget',
  widgetId: 'abc123',
  auth: {
    token: 'USER_JWT_TOKEN',
    provider: 'custom'  // 'embeddy', 'custom', or 'anonymous'
  }
});

Note: JWT tokens should be generated server-side and have an appropriate expiration time. Never expose secret keys in client-side code. Contact support for help setting up custom authentication flows.

7. Rate Limits and Usage

Embeddy widgets are served from a global CDN with generous rate limits. Here are the limits per plan:

PlanPage Views / MonthAPI Calls / MinBandwidth
Free1,00030100 MB
Start ($18/mo)10,000601 GB
Build ($36/mo)50,0001205 GB
Pro ($90/mo)500,00030025 GB

If your widget exceeds the rate limits, requests will receive a 429 Too Many Requests response. The response includes a Retry-After header indicating when the client should retry. For high-traffic widgets, consider upgrading to the Pro plan.

8. Full Examples

Basic Embed with Loading State

<!DOCTYPE html>
<html>
<head>
  <title>My Page with Embeddy Widget</title>
</head>
<body>
  <h1>Welcome to My Site</h1>

  <!-- Loading indicator -->
  <div id="widget-loader" style="text-align: center; padding: 40px;">
    <p>Loading widget...</p>
  </div>

  <!-- Widget container -->
  <div id="my-widget"></div>

  <script src="https://embeddy.ai/sdk/embed.js"></script>
  <script>
    Embeddy.render({
      container: '#my-widget',
      widgetId: 'YOUR_WIDGET_ID',
      width: '100%',
      height: 600,
      theme: 'light',
      autoResize: true,
      onLoad: function() {
        document.getElementById('widget-loader')
          .style.display = 'none';
      },
      onError: function(err) {
        document.getElementById('widget-loader')
          .innerHTML = '<p>Failed to load widget: '
          + err.message + '</p>';
      }
    });
  </script>
</body>
</html>

Dark Theme with Custom Styling

Embeddy.render({
  container: '#dark-widget',
  widgetId: 'YOUR_WIDGET_ID',
  theme: 'dark',
  autoResize: true,
  hideHeader: true,
  customCSS: `
    body {
      background: #0d1117;
      color: #c9d1d9;
      font-family: 'JetBrains Mono', monospace;
    }
    .card {
      border: 1px solid #30363d;
      border-radius: 12px;
    }
  `
});

Two-Way Communication

// Parent page: pass user info and listen for events
const widget = Embeddy.render({
  container: '#interactive-widget',
  widgetId: 'YOUR_WIDGET_ID',
  onLoad: function() {
    // Send user context after widget loads
    widget.postMessage({
      type: 'SET_USER',
      payload: {
        id: 'user_123',
        name: 'Alice',
        role: 'admin'
      }
    });
  }
});

// Listen for widget events
window.addEventListener('message', function(event) {
  if (event.origin !== 'https://embeddy.ai') return;

  if (event.data.type === 'FORM_SUBMITTED') {
    console.log('Received form data:', event.data.payload);
    // Process form data on parent page
    saveToDatabase(event.data.payload);
  }

  if (event.data.type === 'ACTION_COMPLETED') {
    showNotification('Action completed successfully!');
  }
});