Skip to main content

Widget Documentation

Everything you need to embed and customize the <image-layer> widget for image, video, voice, and text workflows in your application.

Quick Start

Add the widget to any HTML page after your backend creates an end-user session token:

HTML
<script type="module" src="https://cdn.imagelayer.app/widget/latest/image-layer.js"></script>

<image-layer id="imagelayer" api-url="https://api.imagelayer.app"></image-layer>
<script>
  const widget = document.getElementById('imagelayer');
  widget.apiKey = 'il_pub_your_publishable_key_here';
  widget.sessionToken = 'SESSION_TOKEN_FROM_YOUR_SERVER';
</script>

The widget renders as a self-contained UI. Users choose a supported workflow, generate on-brand output, and stay inside your product the whole time. Keep live API keys on trusted servers where possible; use the session token to scope each end user.

Installation

CDN rolling path

Use latest for demos, previews, and quick starts. The bytes can change as new widget releases roll out.

HTML
<script type="module" src="https://cdn.imagelayer.app/widget/latest/image-layer.js"></script>

Pinned CDN path (recommended for production)

Pin a versioned or sha-* path and include Subresource Integrity when you need reproducible rollbacks or stricter supply-chain controls.

HTML
<script
  type="module"
  src="https://cdn.imagelayer.app/widget/<version>/image-layer.js"
  integrity="sha384-<hash>"
  crossorigin="anonymous"
></script>

Self-hosted

Copy the built widget files to your static assets and reference the local path:

HTML
<script type="module" src="/assets/image-layer.js"></script>

Attributes

All configuration is done via HTML attributes on the <image-layer> element.

Attribute Type Default Description
apiKeyproperty string""Publishable widget key assigned as a JavaScript property. Do not place secret keys in HTML attributes.
api-urlstring""Required. Base URL of the ImageLayer API.
sessionTokenproperty string""JWT from POST /v1/auth/session. Assign it as a JavaScript property for live generation flows.
authTokenproperty string""Organization auth token used by dashboard and playground flows. Use together with sessionToken.
theme"light" | "dark" | "auto""auto"Color scheme. "auto" follows the system light/dark preference; "dark" forces dark palette.
show-model-selectorbooleantrueShow the model dropdown for the image, video, audio, or text options available in the current widget configuration.
demo-modebooleanfalseEnable the limited hosted demo experience for previews and local testing.
demo-configstring (JSON)undefinedJSON configuration for demo mode presets, visible modes, locked-mode tooltips, and interactive preview behavior.
brand-guidelinesbooleanfalseEnables the brand guidelines toggle in the widget UI.
brand-guidelines-datastring (JSON)undefinedJSON object with brand guidelines configuration (colors, tone, style rules).
animation-style"spring" | "smooth" | "none""spring"Controls the animation style for UI transitions.

demo-config also supports preview-specific keys such as visible_output_modes, disabled_output_modes_reason, preview_behavior, preview_gate_message, preview_cta_href, preview_cta_label, and history_preview_items.

Events

The widget emits custom events that bubble up through the DOM. Listen with addEventListener.

Event Fires when event.detail
il:generateUser submits a prompt or selects a history item.{ prompt: string, output_mode: string, content_type?: string, seed?: number }
il:submitUser finalizes the branded image in the image flow.{ url: string, blob: Blob, generation_id?: string, seed?: number, prompt_metadata?: object }
il:video-generatedVideo generation completes.{ url: string, duration?: number }
il:audio-generatedAudio generation completes.{ url: string, voice?: string, duration?: number, format?: string }
il:voiceover-generatedA video voiceover finishes.{ id: string, video_url: string, audio_url?: string, voice?: string, duration?: number }
il:verification-requiredThe hosted demo needs an external verification step.{ prompt: string, output_mode: string }
il:errorAn error occurs during generation.{ error: string, error_code?: string }
il:text-generatedAI text generation completes.{ text: string }
il:quota-exceededThe user exceeds their credit quota.{ current: number, limit: number, plan: string, canPurchaseCredits: boolean }
JavaScript
const widget = document.querySelector('image-layer');

widget.addEventListener('il:generate', (e) => {
  console.log('Generating:', e.detail.prompt);
});

widget.addEventListener('il:submit', (e) => {
  console.log('Final image URL:', e.detail.url);
  // e.detail.blob contains the raw Blob for upload
});

widget.addEventListener('il:video-generated', (e) => {
  console.log('Video ready:', e.detail.url);
});

widget.addEventListener('il:audio-generated', (e) => {
  console.log('Audio ready:', e.detail.url);
});

widget.addEventListener('il:error', (e) => {
  console.error('Widget error:', e.detail.error);
});

Theming

The widget uses CSS custom properties for full visual customization. Override them on the <image-layer> element to match your brand.

CSS
image-layer {
  /* Brand colors */
  --il-primary: #6366F1;
  --il-primary-hover: #4F46E5;
  --il-accent: #10B981;
  --il-accent-hover: #059669;

  /* Backgrounds */
  --il-bg: #FFFFFF;
  --il-bg-secondary: #F8FAFC;
  --il-bg-tertiary: #F1F5F9;

  /* Text */
  --il-text: #0F172A;
  --il-text-secondary: #475569;
  --il-text-muted: #94A3B8;

  /* Borders */
  --il-border: #E2E8F0;
  --il-border-hover: #CBD5E1;

  /* Error / Success */
  --il-error: #EF4444;
  --il-success: var(--il-accent);

  /* Border radius */
  --il-radius: 10px;
  --il-radius-sm: 6px;
  --il-radius-lg: 14px;
  --il-radius-full: 9999px;

  /* Typography */
  --il-font: 'Inter', system-ui, sans-serif;

  /* Shadows */
  --il-shadow-xs: 0 1px 2px rgba(0,0,0,0.04);
  --il-shadow: 0 1px 3px rgba(0,0,0,0.08), 0 1px 2px -1px rgba(0,0,0,0.08);
  --il-shadow-md: 0 4px 6px -1px rgba(0,0,0,0.08), 0 2px 4px -2px rgba(0,0,0,0.06);
  --il-shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.08), 0 4px 6px -4px rgba(0,0,0,0.04);
}

Dark Theme

Set theme="dark" on the element. Override dark-specific variables:

CSS
image-layer[theme="dark"] {
  --il-bg: #0F172A;
  --il-text: #F1F5F9;
  --il-border: #334155;
  --il-primary: #818CF8;
}

Server-Side Setup

For live embeds, the widget requires a session token to authenticate end users. Your server obtains this token by calling the ImageLayer API. Dashboard and playground flows also pass an auth-token.

1. Get your API key

Go to Dashboard → API Keys and create a secret key for your backend. Use a publishable key in the browser and add every site origin that will embed the widget.

2. Create a session (server-side)

Call POST /v1/auth/session from your backend:

cURL
// Run on your backend, not in the browser.
const body = JSON.stringify({
  external_user_id: 'user-123',
  display_name: 'Jane Doe',
});

await fetch('https://api.imagelayer.app/v1/auth/session', {
  method: 'POST',
  headers: {
    'X-API-Key': process.env.IMAGELAYER_SECRET_KEY,
    'Content-Type': 'application/json',
  },
  body,
});

Response:

JSON
{
  "session_token": "eyJhbG...",
  "expires_at": "2026-03-29T22:00:00.000Z",
  "user": {
    "id": "uuid",
    "external_id": "user-123",
    "display_name": "Jane Doe"
  }
}

3. Pass the token to the widget

Assign session_token and the publishable key to the widget as JavaScript properties after fetching them from your API.

Full Integration Example

A complete HTML page with session creation and widget embedding.

HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>My App — AI Media Generator</title>
  <script type="module" src="https://cdn.imagelayer.app/widget/latest/image-layer.js"></script>
  <style>
    image-layer {
      max-width: 480px;
      margin: 40px auto;
      --il-primary: #2563EB;
      --il-radius-lg: 16px;
    }
  </style>
</head>
<body>
  <image-layer
    id="widget"
    api-url="https://api.imagelayer.app"
    theme="light"
  ></image-layer>

  <script>
    // Fetch session token from YOUR backend
    async function initWidget() {
      const res = await fetch('/api/imagelayer-session');
      const { session_token, publishable_key } = await res.json();
      const widget = document.getElementById('widget');
      widget.apiKey = publishable_key;
      widget.sessionToken = session_token;
    }

    const widget = document.getElementById('widget');
    widget.addEventListener('il:submit', (e) => {
      // Upload the final branded image to your storage
      const formData = new FormData();
      formData.append('image', e.detail.blob, 'branded-image.png');
      fetch('/api/upload', { method: 'POST', body: formData });
    });

    initWidget();
  </script>
</body>
</html>

Demo Mode

For previews and local development, use demo mode to render the hosted limited demo experience:

HTML
<image-layer
  api-url="https://api.imagelayer.app"
  demo-mode
  show-model-selector
  theme="dark"
></image-layer>
Note: Demo mode is intentionally limited and should only be used for previews. Production integrations should always use your ImageLayer API key plus end-user session tokens.