# Embeddable Live Preview

If you're familiar with Stencil's Form integration, you'll notice that the preview tab shows live preview of your template based on the form inputs. This is exactly what Embeddable Live Preview is - it adds live preview of the template to your custom solution.

<figure><img src="https://1726200576-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MYeUDPAhozAcUAcc2Lr%2Fuploads%2FxCZwW2Xck8ZsKp7oOijA%2Ftemplate-preview.gif?alt=media&#x26;token=719a9071-b3f3-4f0c-91af-2e8bf54b8d26" alt=""><figcaption><p>Live template preview in Form integration</p></figcaption></figure>

## Better UX

For advanced users seeking to deeply integrate Stencil into their app with maximum flexibility, using our Form integration might be limiting. Combining the Embeddable Live Preview feature with our image generation API is the most effective solution in this case.

### Common use case

Most common use case revolves around having to preprocess the input or limiting the input to the custom form before passing the inputs to Stencil's image generation API.

* You need a custom form that allows user to search from your database to prefill some values.
* You need conditional inputs that may depend on other related inputs.
* You want to limit what users' input based on your own criteria.

If you answer yes to any of these, you'll probably need to build a custom solution that fits you. However, one missing part is having a preview to your template based on users input. Embedding live preview solves this elegantly.&#x20;

* You have full control on the UI and business logics for your inputs.
* Save costs since users have access to the live preview without having to generate image to see the changes.&#x20;
* Improved UX, users get instant feedback and reduce frustration.

{% hint style="success" %}
[forms-integration](https://docs.usestencil.com/integrations/forms-integration "mention") is the better option for users looking for drag-and-drop experience in generating image while having the option to integrate image generation service into their app.

If you don't have the above requirements, generally using our form integration with our built-in form builder is sufficient.
{% endhint %}

## Using Embeddable Live Preview

There are two parts to this.

1. Building your own solution for gathering inputs from users - this can be a form that populates data from your database or with additional business logic applied to the inputs.
2. Inserting embeddable live preview and connecting it to your solution.

We won't cover building your solution as this can vary between businesses but the general idea is to gather inputs and use the inputs to feed to image generation API.

We only cover the latter where we can use the same inputs to the API to also build a preview for the template.

#### 1. Embed template live preview

You can copy embed link from your template menu. Then, use `iframe` to display this preview.

```html
<iframe 
  id="template-preview" 
  src="https://app.usestencil.com/live-preview/8be62eca-72de-4f81-9edc-a4dbeee6986f?token=abcdefghijkl" 
  style="width:600px; height:600px; border:1px solid black;">
</iframe>
```

The iframe content will resize automatically to fit the container.

#### 2. Send modification

To update the preview, you can send a message to the `iframe` with your modification.

```javascript
const preview = document.getElementById('template-preview');

button.addEventListener('click', () => {
  const modifications = [{
          "name": "image_1",
          "src": "https://images.unsplash.com/photo-1499678329028-101435549a4e?q=80&w=2400&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
      },
      {
          "name": "text_2",
          "text": "Hello world"
      },
      {
          "name": "discount_tag",
          "visible": "{{show_discount}}"
      }
  ]
  const message = {
      namespace: 'stencil',
      action: 'preview_changes',
      data: modifications,
      variables: {
          show_discount: true
      }
  };

  // Send message to iframe
  preview.contentWindow.postMessage(message, 'https://app.usestencil.com');
});
```

Currently, `namespace` and `action` must be set to `stencil` and `preview_changes` respectively like in the above example.

The example above updates the template preview each time the button is clicked, but ideally you should do this whenever your custom form inputs changes.

## Variables

Variables are also supported by adding the `variables` property. See the above example for usage.

For more details, see [template-variables](https://docs.usestencil.com/using-stencil/template-variables "mention")

## Handling Errors

Template data returned directly without wrapper:

```json
{
  "id": "template-id",
  "name": "Template Name",
  "template": { ... },
  // ... other template fields
}
```

### Error Response

Structured error format with `status` field:

```json
{
  "status": "error",
  "error": {
    "type": "build_template_error",
    "message": "Error building template",
    "details": {
      "variables": "Variable 'userName' expected type string but got number"
    }
  }
}
```

### Error Types

| Type                       | Description                | Details Field        |
| -------------------------- | -------------------------- | -------------------- |
| `template_not_found_error` | Template doesn't exist     | `null`               |
| `invalid_request_error`    | Invalid request parameters | Error message string |
| `build_template_error`     | Template rendering failed  | Error details map    |
| `invalid_digest_error`     | Invalid authentication     | `null`               |

### Frontend Implementation

#### Detecting Errors

Check for the presence of `status: "error"` field:

```javascript
socket.addEventListener("receive-preview-image", (event) => {
  const response = event.detail;

  if (response.status === "error") {
    // Handle error
    handlePreviewError(response.error);
  } else {
    // Success - render preview
    renderPreview(response);
  }
});
```

#### Handling Errors from Iframe

The iframe forwards errors to the parent window via `postMessage`:

```javascript
window.addEventListener("message", (event) => {
  if (event.data.namespace === "stencil" && event.data.action === "preview_error") {
    const error = event.data.error;

    // Display error message
    showErrorNotification(error.message);

    // Handle specific error types
    switch (error.type) {
      case "build_template_error":
        if (error.details?.variables) {
          highlightVariableErrors(error.details.variables);
        }
        break;

      case "template_not_found_error":
        redirectToTemplateList();
        break;
    }
  }
});
```

### Sample project

We have developed a simple React application that demonstrates the usage of embeddable live preview. The demo consists of a live preview for products database.

{% hint style="info" %}
Clone the project here <https://github.com/usestencil/stencil-embed-preview-demo>
{% endhint %}
