Embedding Workflows

A step-by-step guide to embed public Streamline workflows on your site (no authentication required).

Overview

This guide walks you through embedding a public Streamline workflow on your own website using an iframe. Embedded workflows run without requiring your visitors to log in; they are ideal for public facing forms.

You will:

  1. Build the embed URL for your workflow
  2. Add an iframe to your page
  3. Listen for postMessage events from the embed
  4. Handle resize events so the iframe height fits the content
  5. React to session completion or failure (optional)

Prerequisites

  • A public workflow in Streamline (workflow must be configured to allow unauthenticated/embed access)
  • Your workflow ID (from the Streamline app)
  • Your site served over HTTPS in production (required for iframe and postMessage)

Workflow requirements for embedding:

The first step of the workflow must:

  1. Be either a Form or an Incoming Webhook.
  2. Not have an assignee.

Step 1: Build the embed URL

The embed URL has this form:

{BASE_URL}/start-session/{WORKFLOW_ID}?source=embed
  • BASE_URL: Your Streamline Production base URL (see below).
  • WORKFLOW_ID: The workflow's unique ID from Streamline.
  • source=embed: So that Streamline can treat the session as an embed.

Example:

https://us.streamline.intellistack.app/start-session/abc123-my-workflow-id?source=embed

Production base URL: https://us.streamline.intellistack.app (or your region's host if your organization uses a different domain).

Step 2: Add the iframe

Add an iframe and set its src to the URL from Step 1.

<iframe
  id="streamline-embedded-workflow"
  title="Streamline Workflow"
  src="https://us.streamline.intellistack.app/start-session/YOUR_WORKFLOW_ID?source=embed"
  width="600"
  height="800"
  style="border: none;"
></iframe>
  • Use a descriptive title for accessibility.
  • width="600" and height="800" are just examples; change them or use CSS (e.g. width: 100%) to fit your layout.
  • Height can be updated dynamically in Step 4 when you handle streamline:resize events.

Step 3: Listen for postMessage events

The workflow inside the iframe sends events to the parent window via postMessage. Always validate the message origin before handling data.

Allowed origin: Only accept messages from your Streamline Production origin, e.g. https://us.streamline.intellistack.app (or your region's host).

Event format: Messages are objects with type and payload. Streamline event types use the prefix streamline:.

Minimal listener with origin check:

const ALLOWED_ORIGINS = ['https://us.streamline.intellistack.app'];

function isOriginAllowed(origin) {
  return ALLOWED_ORIGINS.some((allowed) => origin.startsWith(allowed));
}

window.addEventListener('message', (event) => {
  if (!isOriginAllowed(event.origin)) {
    return; // Ignore messages from other origins
  }

  const { type, payload } = event.data || {};
  if (!type || !type.startsWith('streamline:')) {
    return;
  }

  switch (type) {
    case 'streamline:ready':
      // Embed has loaded and is ready
      // payload: { timestamp, sessionId }
      break;
    case 'streamline:resize':
      // payload: { width, height } — both are emitted (see Step 4)
      break;
    case 'streamline:session:completed':
      // User completed the workflow
      break;
    case 'streamline:session:failed':
      // Session failed or expired
      break;
    default:
      break;
  }
});

For security purposes, never process or trust event.data without checking event.origin against your allowlist.

Step 4: Handle resize events

The embed sends streamline:resize when its content size changes so your page can avoid scrollbars inside the iframe. Resize events are debounced (≈150 ms), so you may see a brief delay between content changes and the event.

Payload: { width, height } (numbers, in pixels). Both dimensions are included on every resize event.

Example: Update the iframe height when you receive a resize event:

const iframe = document.getElementById('streamline-embedded-workflow');

// Inside your message handler, for type === 'streamline:resize':
if (type === 'streamline:resize' && payload && payload.height > 0) {
  iframe.style.height = `${payload.height}px`;
}

You can also use payload.width if you need to constrain or match width.

Step 5: Handle session completion and failure (optional)

Use these events to show a thank-you message, redirect, or track analytics on your own website.

  • streamline:session:completed — User finished the workflow. Payload: { sessionId }.
  • streamline:session:failed — Session failed or expired. Payload: { sessionId, error } (error may be undefined).

Example:

case 'streamline:session:completed':
  console.log('Workflow completed', payload?.sessionId);
  // e.g. show thank-you message, redirect, or send to analytics
  break;
case 'streamline:session:failed':
  console.warn('Workflow failed or expired', payload?.sessionId, payload?.error);
  break;

Event reference

EventDescriptionPayload
streamline:readyEmbed has loaded and is ready for interaction.{ timestamp, sessionId }
streamline:resizeContent size changed.{ width, height }
streamline:session:completedUser completed the workflow.{ sessionId }
streamline:session:failedSession failed or expired.{ sessionId, error? }

All events are sent with type (string) and payload (object). Only process messages whose type starts with streamline: and whose event.origin is in your allowlist.

Security

  • Origin validation: Always check event.origin against a fixed list of Streamline origins. Do not use wildcards or accept any origin.
  • HTTPS: In production, serve your page and use Streamline over HTTPS.
  • Workflow visibility: Only workflows configured as public (embeddable without authentication) can be used with this URL.

Troubleshooting

  • Embed shows "This page isn't available right now": The workflow is not configured correctly for embedding. Verify that the first step is a Form or Incoming Webhook, the first step has no assignee, and the workflow is public.

Tips

  • Use source=embed in the URL so Streamline can apply embed-specific behavior (e.g. styling, in-memory routing).
  • Give the iframe a sufficient initial min-height to avoid layout shift; resize events will refine it.
  • For debugging, log incoming messages and payloads; ensure you only act on allowed origins and streamline:* types.