Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.penbox.io/llms.txt

Use this file to discover all available pages before exploring further.

Penbox allows you to embed forms directly in your website using iframes, so your users never leave your application.

How It Works

Instead of redirecting users to a Penbox URL, you load the form inside an <iframe> on your own page. Penbox communicates back to your page using postMessage events.
1

Configure allowed origins

In your workspace Branding settings, add the origins (domains) that are allowed to embed Penbox forms. For example: https://app.yourcompany.com.
2

Enable embedding per form

On each form template, toggle Embedding on in the settings panel. Only forms with this toggle enabled can be embedded.
3

Add the iframe to your page

Use the form URL with the embed_v=1 query parameter:
<iframe
  src="https://fill.penbox.io/f/<flow-customization-id>?embed_v=1&autostart"
  allow="clipboard-write; camera; microphone"
  style="width: 100%; height: 600px; border: none;"
></iframe>
4

Listen for events

Listen for postMessage events from the iframe to know when the form is ready and when it’s completed.

Configuration

Embedding requires a double opt-in:
  1. Workspace level: declare which origins are allowed to embed forms (in Settings > Branding)
  2. Form level: enable embedding on each individual form template
This prevents accidental exposure — a workspace with 50 forms won’t have them all embeddable just because one origin is configured.

Allowed Origins

Origins must be exact matches — no wildcards, no paths, no trailing slashes. HTTPS is required in production. http://localhost (with optional port) is allowed for development.
ValidInvalid
https://app.example.comhttps://app.example.com/ (trailing slash)
https://portal.example.comhttps://*.example.com (wildcard)
http://localhost:3000https://app.example.com/path (path)
You can configure up to 20 origins per workspace.
If the embedding toggle is on for a form but no origins are configured at workspace level, embedding will be blocked.

Query Parameters

ParameterDescription
embed_v=1Required. Activates embed mode: hides the top navigation bar and enables postMessage events.
autostartOptional. Skips the welcome page and starts the form automatically. Recommended for embedded forms.
A typical embedded URL looks like:
https://fill.penbox.io/f/<flow-customization-id>?embed_v=1&autostart

Events

Penbox sends events to the parent window using postMessage. All events share the same envelope:
{
  "source": "penbox",
  "type": "<event-type>",
  "v": 1
}

ready

Sent when the form layout has mounted and is ready to be displayed.
{
  "source": "penbox",
  "type": "ready",
  "v": 1
}

completed

Sent exactly once when the form is submitted. Includes the request_id for reference.
{
  "source": "penbox",
  "type": "completed",
  "v": 1,
  "request_id": "<uuid>"
}
The completed event fires regardless of whether an auto-redirect is configured on the form. It is sent before any redirect delay.

Integration Example

<iframe
  id="penbox-form"
  src="https://fill.penbox.io/f/abc123?embed_v=1&autostart"
  allow="clipboard-write; camera; microphone"
  style="width: 100%; height: 700px; border: none;"
></iframe>

<script>
  window.addEventListener("message", (event) => {
    // Filter for Penbox events
    if (event.data?.source !== "penbox") return;
    // Recommended: verify origin
    if (event.origin !== "https://fill.penbox.io") return;

    switch (event.data.type) {
      case "ready":
        console.log("Form is ready");
        break;
      case "completed":
        console.log("Form completed:", event.data.request_id);
        // Navigate to a thank-you page, close a modal, etc.
        break;
    }
  });
</script>

Security

Penbox uses the Content-Security-Policy: frame-ancestors header to control which origins can embed forms. When embedding is properly configured, the X-Frame-Options: DENY header is replaced with a CSP header listing only your allowed origins. If a page tries to embed a form from an unauthorized origin, the browser blocks it — the iframe will show an error or remain blank.
Always filter incoming postMessage events by checking event.data?.source === 'penbox' and event.origin === 'https://fill.penbox.io' to avoid processing unrelated messages.

Known Limitations

  • Exact origins only — wildcards and regex patterns are not supported. Each origin must be declared explicitly.
  • 20 origins max — contact support if you need more.
  • Token visible to parent — the parent page can read the iframe URL. This is standard iframe behavior and does not expose additional data.
  • Third-party cookie restrictions — Safari ITP and Chrome strict mode may block third-party cookies. Penbox uses sessionStorage-based authentication, so this is generally not an issue.
  • Custom form domains — embedding currently only works with fill.penbox.io URLs. Custom domain support is planned.

Next Steps

Form Security

Protect forms with access controls

Form Templates

Build and configure form templates