---
url: https://plugin.stripo.email/editor-configuration/initialization-settings.md
---

# Initialization Settings

The new Stripo editor accepts a series of configuration parameters upon initialization, allowing you to customize the editor to meet your specific needs.

A minimal configuration looks like this:

```js
const stripoConfig = {
  metadata: {
    emailId: '...'
  },
  html: '...',
  css: '...',
  onTokenRefreshRequest: function(callback) {
    /*
      This function is called whenever the authentication token needs to be refreshed.
      You should send a request to your backend to obtain a new token.

      Example:
      Send a request to your backend (e.g., https://your_domain/stripo/token) to retrieve the new token.
    */
    const token = ... // Replace with the logic to obtain the token
    callback(token);  // Pass the retrieved token to the callback function
  }
}
```

You can configure various parameters to customize its behavior and functionality. Below is a list of possible parameters

## Supported Parameters

### metadata

### onTokenRefreshRequest

### html

### css

### entityType

Defines what the editor opens for editing: `email` (default) or `module`. When set to `module`, the editor launches in **Module Editing Mode**, which lets you create or edit a reusable module instead of an email. Available on the **Enterprise** plan only — on any other plan the editor does not initialize and shows a toaster notification. See [Module Editing Mode](/editor-configuration/module-editing-mode).

### moduleId

**Module Editing Mode only.** The ID of an existing module to open for editing. When provided, any passed `html` and `css` are ignored and the module is loaded from the plugin database. If the module is missing, deleted, or does not belong to the current plugin, the editor does not initialize and shows a toaster notification. See [Editing an existing module](/editor-configuration/module-editing-mode#editing-an-existing-module).

### moduleType

Module Editing Mode only. Required when creating a new module (i.e. when `moduleId` is **not** provided). One of `STRIPE`, `STRUCTURE`, `CONTAINER`. If \``moduleId` is also provided, `moduleType` is ignored. If it is missing or invalid in create mode, the editor does not initialize and shows a toaster notification. See [Creating a new module](/editor-configuration/module-editing-mode#creating-a-new-module).

### key

Module Editing Mode only, optional. The storage key of the module folder the new module is saved to (the same **Storage Key ID** configured for module folders in your Plugin settings). If omitted, the first folder the user can write to is used. See [Module Editing Mode](/editor-configuration/module-editing-mode).

### moduleName

Module Editing Mode only, applies when **creating** a new module (ignored if `moduleId` is provided). Initial name of the new module. Maximum 200 characters; longer values are trimmed. Default: `New module`. See [Initial metadata for a new module](/editor-configuration/module-editing-mode#initial-metadata-for-a-new-module).

### moduleDescription

Module Editing Mode only, applies when **creating** a new module (ignored if `moduleId` is provided). Initial description of the new module. Maximum 500 characters; longer values are trimmed. Default: empty. See [Initial metadata for a new module](/editor-configuration/module-editing-mode#initial-metadata-for-a-new-module).

### moduleCategoryId

Module Editing Mode only, applies when **creating** a new module (ignored if `moduleId` is provided). Numeric ID of the category to assign to the new module. If the category does not exist or is unavailable for this plugin, it is silently ignored (no error, no toaster). Default: `Uncategorized`. See [Initial metadata for a new module](/editor-configuration/module-editing-mode#initial-metadata-for-a-new-module).

### moduleTags

Module Editing Mode only, applies when **creating** a new module (ignored if `moduleId` is provided). Array of tag strings applied to the new module. Default: no tags. See [Initial metadata for a new module](/editor-configuration/module-editing-mode#initial-metadata-for-a-new-module).

### name

### utm

### locale

The locale setting for the editor, determining the language and regional
settings.

**Supported locales:**\
`bg` — Bulgarian\
`cs` — Czech\
`de` — German\
`en` — English\
`es` — Spanish\
`fr` — French\
`it` — Italian\
`ja` — Japanese\
`ko` — Korean\
`nl` — Dutch\
`pl` — Polish\
`pt` — Portuguese\
`pt-br` — Portuguese (Brazilian)\
`ro` — Romanian\
`ru` — Russian\
`sl` — Slovenian\
`tr` — Turkish\
`uk` — Ukrainian\
`zh` — Chinese (Traditional)\
`zh-cn` — Chinese (Simplified)

### forceRecreate

### ignoreClickOutsideSelectors

### panelPosition

### notifications

### textEditorAllowedPasteContent

### imageGalleryViewMode

The `imageGalleryViewMode` parameter sets how images are displayed when users open the image selection dialog (Image Gallery). This affects the visual layout and browsing experience:

* `grid` - Traditional grid layout with uniform-sized image tiles arranged in rows
* `masonry` - Pinterest-style masonry layout where images maintain aspect ratio with varied heights
* `list` - Compact list view showing images as rows with thumbnails on the left

**Sample:**

```js
"imageGalleryViewMode": 'masonry'
```

**Behavior:**\
When the editor initializes:

* If `imageGalleryViewMode` is set to one of the allowed values, the image gallery will open in that view mode.
* If the parameter is omitted or set to an invalid value, the gallery defaults to `grid` mode.
* When the user manually switches view modes in the gallery, the editor triggers the `onImageGalleryViewModeChange` event ([see below](#onimagegalleryviewmodechange)).

### uiSettings

The `uiSettings` parameter passes editor UI preferences that your application stores per user and sends back on every initialization. Unlike the values the editor keeps in the browser, these preferences follow the user between devices and browsers.

**Fields:**

* `moduleGalleryViewMode` - view mode of the modules gallery: `grid`, `smallGrid`, or `list`. When passed, it applies to every modules folder and overrides the view mode saved in the browser.
* `defaultViewMode` - view mode the editor opens in: `DESKTOP` or `MOBILE`. Defaults to `DESKTOP`.

**Sample:**

```js
"uiSettings": {
   "moduleGalleryViewMode": "list",
   "defaultViewMode": "MOBILE"
}
```

**Behavior:**

* Every field is optional. A field that is omitted or has an invalid value falls back to the editor default.
* When the user changes the view mode of the modules gallery in the editor, the `onUiSettingsChange` callback receives the changed field ([see below](/editor-configuration/initialization-settings#onuisettingschange)). Save it and pass it back in `uiSettings` on the next initialization.
* `defaultViewMode` sets the initial state only. The user can switch between Desktop and Mobile in the editor header as usual; every switch, and the initial mode on load, is reported through the `onEditorVisualModeChanged` callback ([see below](/editor-configuration/initialization-settings#oneditorvisualmodechanged)). The `mobileViewButtonSelector` and `desktopViewButtonSelector` parameters keep working independently.

### preserveAltOnImageReplace

When `false` (default), ALT text is cleared when an image is replaced, requiring users to manually enter new ALT text for the replacement image.

**Sample:**

```js
"preserveAltOnImageReplace": true

// User replaces image_1.jpg with image_2.jpg
// ALT text: "Product screenshot" is preserved
```

**Use Cases:**\
When the editor initializes:

* Enable for templates where image descriptions apply across multiple image variations.
* Use for workflows where maintaining consistent ALT text is critical for accessibility.
* Disable for scenarios where different images require different descriptions.

### bankImagesDefaultSearchString

### codeEditor

### codeEditorButtonSelector

### counterRangeEnabled

Controls the drag-to-change behavior of numeric counter controls (paddings, sizes, and other stepper inputs) in the settings panel. When enabled, hovering over a counter input shows a range cursor, and dragging left or right decreases or increases the value — in addition to typing and the +/- steppers.

Type: `Boolean`\
Default: `true`

**Sample**

```js
"counterRangeEnabled": false
```

### mergeTags

### mergeTagsAutocomplete

Enables inline autocomplete for merge tags in the Text block. When the user starts typing the syntax of a configured merge tag directly on the canvas, the editor shows a suggestion list, so the tag can be inserted without opening the merge tags dropdown in the settings panel.

Type: `Boolean`\
Default: `false`

When enabled, typing two or more characters that match the beginning of a configured tag `value` (or a tag `label`, once the typed fragment starts with a tag opening sequence) opens a flat suggestion list. Picking a suggestion replaces the typed fragment with the merge tag; typing the full tag syntax manually keeps working exactly as before — the autocomplete is an optional shortcut, it never intercepts Enter/Tab unless a list item was highlighted with the arrow keys.

Tags with `hidden: true` never appear in the suggestions. If the merge tags UI is overridden by an extension (a custom `UE-MERGETAGS` element), the autocomplete is disabled regardless of this parameter.

**Sample**

```js
"mergeTagsAutocomplete": true
```

See the [Merge Tags Setup](/editor-configuration/initialization-settings#merge-tags-setup) section for the tags configuration.

### socialNetworks

### specialLinks

### hiddenShareItems

An array of share-item keys that should be hidden from the **Share** tab in the link-type selector. Accepts a subset of the supported keys: `facebook`, `x`, `linkedin`, `pinterest`. For a detailed description and usage instructions, refer to the [Share Link Configuration](#share-link-configuration) section.

### hideShareTab

A boolean flag that hides the entire Share tab from the link-type selector in the Link control. When set to `true`, the Share tab and all its contents are removed from the UI. For a detailed description and usage instructions, refer to the [Share Link Configuration](#share-link-configuration) section.

### viewOptions

### templateThemeMode

### editorFonts

### conditionsEnabled

### undoButtonSelector

### redoButtonSelector

### mobileViewButtonSelector

### desktopViewButtonSelector

### versionHistoryButtonSelector

### localePatch

```js
{
  "localePatch": {
    "en": {
      "settingsPanel.accordion.structures": "Available Structures",
      "settingsPanel.block.timer": "Clock"
    }
  }
}
```

Deprecated Format (Deprecated):

```js
{
  "localePatch": {
    "settingsPanel.accordion.structures": {
      "en": "Available Structures"
    },
    "settingsPanel.block.timer": {
      "en": "Clock"
    }
  }
}
```

::: warning ⚠️ Note:
The previous format is now deprecated but remains functional for backward compatibility. It is recommended to use the new format to ensure future compatibility.
:::

For a list of all editor phrases, refer to the editor phrases JSON file.

### defaultMenuItems

```js
"defaultMenuItems": [
  {
    "name": "Item 1",
    "href": "https://google.com"
  },
  {
    "name": "Item 2",
    "href": "https://test.com"
  }
]
```

### syncModulesEnabled

```js
"syncModulesEnabled": true
```

### disableAdaptDesign

```js
"disableAdaptDesign": true
```

### responsiveDesignByDefault

Defines the initial state of the “Responsive Design” control for newly created emails. Useful when the emails are sent through systems where responsive markup is not supported and the extra mobile CSS is undesirable.

Type: `Boolean`\
Default: `true`

When set to `false`, a new email is created with the “Responsive Design” control in General settings turned off — the result is the same as when the user turns the control off manually: mobile styles are disabled and excluded from the email code and export.

The parameter is applied once, at email creation. The control itself stays available: the user can turn Responsive Design back on in a specific email, and on reopening, the state is taken from the email — not from this parameter.

Unlike [`disableAdaptDesign`](/editor-configuration/initialization-settings#disableadaptdesign), which force-disables the responsive view, this parameter only sets the starting state and leaves the choice to the user.

**Sample**

```js
"responsiveDesignByDefault": false
```

### disableRemoteCursors

```js
"disableRemoteCursors": true
```

### moveBlockAvailability

```js
"moveBlockAvailability": true
```

### enableNativeSpellChecker

### enableTextEmojis

### enableXSSSecurity

```js
"enableXSSSecurity": true
```

### allowedScriptSourceDomains

```js
"allowedScriptSourceDomains": "https://domain1.com http://domain2.net"
```

### buttonTextDecorationsEnabled

Adds the Underline and Strikethrough options to the Text Style row of the Button block settings, next to the existing Bold and Italic. The options behave the same way as in the Text block.

Type: `Boolean`\
Default: `false`

When the parameter is omitted or set to false, the Button block Text Style row shows only Bold and Italic, as before.

**Sample**

```js
"buttonTextDecorationsEnabled": true
```

### supportOutlookButtonsByDefault

```js
"supportOutlookButtonsByDefault": true
```

### sameFontSizeForOutlook

This feature controls automatic font size optimization for button elements in Outlook.

**Usage:**\
Set the `sameFontSizeForOutlook` parameter to `true` to enable the built-in font size optimization logic for Outlook. The editor automatically calculates appropriate font sizes based on button dimensions and spacing. If you prefer to disable this optimization and use standard font sizing instead, set the parameter to `false`.

**Sample:**

```js
"sameFontSizeForOutlook": true
```

**How It Works:**\
The editor includes a built-in optimization algorithm that adjusts button font sizes while considering:

* Button height and overall dimensions
* Font size settings
* Padding and internal spacing

This logic ensures that button text renders correctly in Outlook without overflow or unwanted wrapping. If this automatic optimization doesn't match your design preferences or causes unexpected font sizing, you can disable it by setting the parameter to false to use standard, unmodified font sizes.

**Details:**\
When enabled, the optimization improves visual consistency between Outlook and modern email clients. When disabled, buttons use the exact font sizes specified without any Outlook-specific adjustments. Test both settings with your specific button designs across different Outlook versions (Outlook 2016, 2019, Outlook Online, Outlook for Mac) to determine which approach works best for your templates.

### shouldBeSavedToLibrary

```js
{
  ...
  "shouldBeSavedToLibrary": function() {
    return false;
  },
  ...
}
```

```js
{
  ...
  shouldBeSavedToLibrary: function(moduleHtml) {
    // Your logic to determine if the module can be saved
    return true; // or false
  },
  ...
}
```

### validateModuleSave

```js
"validateModuleSave": function(data) {
  // Your validation logic here
  return { allowed: true };
}
```

### validateModuleDelete

```js
"validateModuleDelete": function(data) {
 // Your validation logic here 
return { ok: true }; 
}
```

### shouldHideImagePath

```js
shouldHideImagePath: function (url) {
  // hide images already hosted on Stripo CDN
  return url.includes('stripocdn.email') || url.includes('assets.mycompany.com');
}
```

```js
"shouldHideImagePath": (url) => url.startsWith("https://assets.mycompany.com/")
```

### disableImageUnadapt

```js
"disableImageUnadapt": true
```

### youtubeApiKey

```js
"youtubeApiKey": "YOUR_YOUTUBE_API_KEY_HERE"
```

::: warning ⚠️ **Deprecated since Plugin 2.82.0.**:
This parameter is no longer used. Video metadata and preview generation are now handled entirely on the Stripo backend, so the editor no longer sends requests to the YouTube API directly. You can keep passing `youtubeApiKey` for backward compatibility — the editor simply ignores it — but new integrations don't need to pass it.
:::

### keepModuleStylesEnabled

```js
"keepModuleStylesEnabled": true
```

In this configuration, the Keep Module Styles control becomes available in the module saving panel, allowing users to inline appearance styles into the module HTML when saving the module.

### keepModuleStylesByDefault

This parameter sets the initial state of the Keep Module Styles toggle in the module saving panel. By default, the toggle is off when the panel opens, and users turn it on for each module they want to save with inlined styles. When `keepModuleStylesByDefault` is set to `true`, the toggle is on by default for every new module. Users can still turn it off before saving; the module is saved with the toggle state at the moment of saving. Usage: Include the `keepModuleStylesByDefault` parameter during the initialization of the plugin together with `keepModuleStylesEnabled: true`. The parameter works only when the Keep Module Styles control is enabled; if the control is hidden, the parameter is ignored. When a user updates an existing module, the toggle shows the state that was saved in that module, not the value of this parameter.

Default: `false`

**Sample**:

```js
"keepModuleStylesEnabled": true,
"keepModuleStylesByDefault": true
```

In this configuration, the Keep Module Styles toggle is available in the module saving panel and is turned on by default for every new module.

### modulesDisabled

```js
"modulesDisabled": true
```

If this parameter is not specified, users will have the default ability to manage modules. Note that this parameter will be ignored if you deactivate Modules within the plugin configuration page. Disabling module management can be useful for maintaining control over the modules and ensuring a consistent user experience.

### showModuleUid

The `showModuleUid` parameter controls whether the module's unique identifier (uid) is displayed in the editor interface.

By default, this field is hidden because it is primarily intended for advanced scenarios such as internal workflows, integrations, or companion applications that require access to the module identifier.

When enabled, the module uid becomes visible in the module management interface, allowing users to view and reference it when saving, editing, or browsing modules in the library.

**Usage:**\
Include the `showModuleUid` parameter during plugin initialization. Set the value to `true` if you want to display the module UID in the module save form, edit form, and module list tooltip.

**Sample:**

```js
"showModuleUid": true
```

If this parameter is not specified or set to `false`, the module UID field will remain hidden.

When `showModuleUid` is enabled:

* the **Id (uid)** field is displayed in the **module save form**;
* the **Id (uid)** field is displayed in the **module edit form**;
* the **Id (uid)** is shown in the **tooltip/module information** inside the Modules Library.

### selectBlockAfterDropFromSettingsPanel

```js
"selectBlockAfterDropFromSettingsPanel": true
```

### selectElementAfterDrop

This feature allows any element dropped into the editor — whether it is a **block**, **extension**, **stripe**, **structure**, or **module** — to be automatically selected right after being placed in the editor. &#x20;
Usage:
Set the selectElementAfterDrop parameter to true during the initialization of the Stripo editor to enable this functionality.
Sample:

```js
"selectElementAfterDrop": true
```

With this parameter enabled, as soon as the user drags and drops any element into the email layout, that element becomes instantly selected in the editor for immediate customization.

This improves workflow consistency by eliminating the need to manually click the dropped element before editing it — useful for all element types, including blocks, structures, stripes, modules, and extensions.

### modulesExcludedCategories

```js
"modulesExcludedCategories": [1, 2]
```

### messageSettingsEnabled

```js
"messageSettingsEnabled": true
```

### calendarDateTimeFormat

Defines the date and time display format for the Timer block in the editor.\
By default, Stripo uses the `MM DD YYYY` format (month–day–year).\
With this parameter, you can override the default and choose how the date should be displayed in the Timer.

**Supported Date Formats**\
The Timer block fully supports the following formats:

| Format             | Example                 | Description                   |
| ------------------ | ----------------------- | ----------------------------- |
| `DD.MM.YYYY`       | `25.12.2024`            | Day.Month.Year                |
| `DD/MM/YYYY`       | `25/12/2024`            | Day/Month/Year                |
| `MM/DD/YYYY`       | `12/25/2024`            | US format                     |
| `YYYY-MM-DD`       | `2024-12-25`            | ISO format                    |
| `D MMMM YYYY`      | `25 December 2024`      | Day + full month name + year  |
| `DD MMM YYYY`      | `25 Dec 2024`           | Day + short month name + year |
| `dddd, DD.MM.YYYY` | `Wednesday, 25.12.2024` | Weekday + date                |
| `DD.MM.YY`         | `25.12.24`              | Short year                    |

*💡 Month and weekday names are displayed according to the editor’s selected locale.*

**Usage:**

```js
"calendarDateTimeFormat": "DD.MM.YYYY"
```

**Example:**

```js
{
  ...
  "calendarDateTimeFormat": "MM/DD/YYYY",
  ...
}
```

This configuration will render a date such as **12/31/2025** in the Timer block.

**Notes**

* Only the formats listed above are supported.
* The formatting patterns follow a predefined internal rule set and do not use moment.js or similar libraries.
* If an unsupported format is passed, the editor will fall back to the default `DD MM YYYY`.

### displayTitle

```js
"displayTitle": false
```

### displayHiddenPreheader

```js
"displayHiddenPreheader": false
```

### displayUTM

```js
"displayUTM": false
```

### displayGmailAnnotations

```js
"displayGmailAnnotations": false
```

### previewIframeAttributes

```js
previewIframeAttributes: {
  foo: "bar",
  withoutValue: ""
}
```

### customViewStyles

```js
// turn custom styles ON
window.StripoEditorApi.actionsApi.activateCustomViewStyles(true);

// turn custom styles OFF
window.StripoEditorApi.actionsApi.activateCustomViewStyles(false);
```

Usage:

Add the parameter to your initEditor call and pass CSS as plain text.

```js
"customViewStyles": ".esd-block-button { border: 2px solid red; }";
```

Sample:

```js
"customViewStyles": "\n  .esd-block-button {\n    border-radius: 8px;\n    padding: 12px 24px;\n    background: linear-gradient(45deg,#ff8a00,#e52e71);\n    color:#fff;\n  }\n  .esd-text h1 {\n    font-family: 'Roboto Condensed', sans-serif;\n    letter-spacing: 1px;\n  }\n"
```

### brandColorPalette

```js
"brandColorPalette": [
  {
    "name": "Primary Brand Color",
    "value": "#FF5733"
  },
  {
    "value": "#33C1FF"
  },
  {
    "name": "Accent",
    "value": "rgba(50, 205, 50, 0.8)"
  }
]
```

The heading of this section in the color picker can be customized with the `brandColorPaletteLabel` parameter. Each time a user applies a brand color, the editor emits a `color_palette_used` event through the `onEvent` callback, so your application can track brand palette usage.

### brandColorPaletteLabel

Custom heading for the brand colors section of the color picker.

Type: `String`\
Default: `"Brand Palette"`

**Sample:**

```js
"brandColorPaletteLabel": "Acme Corp Colors"
```

### colorPalette

Pre-populates the My Palette section of the color picker — the personal set of colors the user collects while
working in the editor.

If the parameter is not provided, the palette is restored from the user's browser storage. Users add the currently
selected color to this section with the “+” button; the palette holds up to 13 colors (newest first) and is
persisted in the browser between sessions.

Type: `Array` of CSS color values

**Sample:**

```js
"colorPalette": ["#FF5733", "#33C1FF", "rgba(50, 205, 50, 0.8)"]
```

### customColorPalette

Replaces the built-in Default Palette colors with your own fixed set. When this parameter is provided, the free-form
color picker (spectrum canvas) and the My Palette section are hidden, so users can only choose from the colors you
define — plus the transparent swatch and the brand palette, if configured. Use it when the color choice in the
editor must be limited to an approved set.

Note: the colors are displayed inside the Default Palette section, so this parameter takes effect only while
`defaultPaletteEnabled` is not set to `false`.

Type: `Array` of CSS color values

**Sample:**

```js
"customColorPalette": ["#000000", "#FFFFFF", "#FF5733", "#33C1FF"]
```

### defaultPaletteEnabled

Shows or hides the **Default Palette** section of the color picker — the built-in set of standard colors together
with the transparent swatch (or your own set, if `customColorPalette` is configured).

Type: `Boolean`\
Default: `true`

**Sample:**

```js
"defaultPaletteEnabled": false
```

### customColorsEnabled

Shows or hides the free-form color selection tools of the color picker: the spectrum canvas and the **My Palette** section with user-saved colors.

When set to `false`, users cannot pick arbitrary colors — only the colors available in the default, custom, or brand palettes.

If `defaultPaletteEnabled` and `customColorsEnabled` are both `false` and no `brandColorPalette` is configured, the color picker popup is disabled entirely; users can still type a color value manually into the input field.

Type: `Boolean`\
Default: `true`

**Sample:**

```js
"customColorsEnabled": false
```

### baseBlocks

```js
"baseBlocks": {
  "ampAccordionEnabled": false,
  "ampCarouselEnabled": true,
  "ampFormControlsEnabled": false,
  "bannerEnabled": false,
  "buttonEnabled": true,
  "htmlEnabled": true,
  "imageEnabled": true,
  "menuEnabled": true,
  "socialNetEnabled": true,
  "spacerEnabled": true,
  "textEnabled": true,
  "timerEnabled": true,
  "videoEnabled": true
}
```

### ampFormServices

Defines a list of predefined backend endpoints available for AMP Form blocks in the editor. Each entry includes a `label` (user-friendly name) and a `value` (submission URL). These endpoints appear in the AMP Form block settings as selectable options for form submission. For a detailed description and configuration examples, refer to the [AMP Form Services section](/editor-configuration/initialization-settings#amp-form-services).

### showExternalAmpFormServices

Controls whether users can manually add their own external AMP Form endpoints. When set to `false`, the “Add external service” option is hidden, and users can only select endpoints from the predefined `ampFormServices` list. For a detailed description, refer to the [AMP Form Services section](/editor-configuration/initialization-settings#amp-form-services).

### copyPasteEnabled

Enables copying and pasting of email elements (stripes, structures, containers, and blocks) between tabs and windows of the editor through the system clipboard.

Type: `Boolean`\
Default: `false`

When set to `false`:

* Cmd/Ctrl+C on a selected element does not place the element into the clipboard, and Cmd/Ctrl+V does not paste one;
* the “You have copied an element…” notification with the Paste action is not shown — including when the element was copied in another tab;
* the “Copy to Clipboard” hint on the element handle is hidden.

Everything else stays unaffected: selecting and natively copying text inside text blocks works as usual, and the Duplicate action on the element handle remains available.

**Sample**: `"copyPasteEnabled": false`

### gradients

Granular control over the gradient options in the editor's color settings. Lets you hide the “Apply gradient” switcher and gradient controls — everywhere at once or per element type — when your sending environment does not support CSS gradients.

**Type**: Object (all fields are Boolean and default to `true`)

```js
"gradients": {
 "enabled": true,                  // master switch for all gradient controls
 "buttonEnabled": true,            // General Styles > Button (incl. hover), inline button color/hover, button block background
 "textEnabled": true,              // text block background
 "containerEnabled": true,         // container background
 "structureEnabled": true,         // structure background
 "stripeEnabled": true,            // inline stripe backgrounds and General Styles > Stripes
 "messageBackgroundEnabled": true, // General Settings > message background
 "spacerEnabled": true,            // spacer block background
 "socialEnabled": true             // social block background
}
```

Disabling an element type hides the gradient controls in all locations of that type at once (for example, `buttonEnabled: false` removes the gradient option from General Styles > Button, from inline button settings including hover styles, and from the button block background), together with their dark-mode counterparts. The regular solid color picker keeps working.

`enabled: false` takes priority over the individual flags and hides gradient controls everywhere.

Gradients that already exist in the template content are not removed from the HTML and keep rendering as they are — only the controls are hidden.

**Sample:**

```js
"gradients": {
 "buttonEnabled": false
}
```

### imageResizeOnCanvasEnabled

Controls the availability of the on-canvas resize handle for image blocks. With this feature, users can drag the handle that appears in an image's bottom-right corner directly on the canvas to resize it, with a live width/height tooltip and a maximum clamped to the available column width — without opening the settings panel. The handle is available only in Desktop preview mode.

Type: `Boolean`\
Default: `true`

When set to `false`, the resize handle is not shown on the canvas. Images can still be resized through the **Size** control in the settings panel — this flag only turns off the canvas drag gesture, not image resizing itself.

**Sample**: `"imageResizeOnCanvasEnabled": false`

### containerResizeOnCanvasEnabled

Controls resizing of containers by dragging the borders between them directly on the canvas.

Type: `Boolean`\
Default: `true`

When set to `false`, the resize handles between the containers of a structure do not appear on hover and dragging the borders is unavailable. Managing container widths from the settings panel stays available and is not affected by this option.

**Sample**: `"containerResizeOnCanvasEnabled": false`

### structurePerRowEnabled

Controls the availability of the Containers per Row control — a sub-control of “Responsive structure” in the mobile mode of the structure settings that keeps two to four containers side by side on mobile devices instead of stacking them one under another. Useful for product grids, catalogs, and news digests that should look the same on mobile as on desktop.

Type: `Boolean`\
Default: `true`

While the parameter is enabled, users see the Containers per Row counter once “Responsive structure” is turned on. The default value 1 keeps the standard behavior (each container takes the full row); values from 2 to 4 keep the corresponding number of containers in one row — the maximum cannot exceed the number of containers in the structure at the moment of setting. The setting applies to the whole structure, including containers added later; containers keep their configured widths; a single container left in the last row takes the full row width; turning “Responsive structure” off restores the regular markup while preserving the counter value.

When set to `false`, the Containers per Row control is not shown, and structures keep the standard mobile behavior — one container per row. Use it when your integration relies on a fixed mobile layout of structures (for example, in custom extension blocks).

Sample:

```js
"structurePerRowEnabled": false
```

### dataFeed

Controls the availability of the **Data Feed** option in the Data tab of Smart Elements — the ability to fill a smart element from a structured data source instead of a website page.

Type: `Object`\
Default: `hidden` — the Data Feed option appears only when explicitly enabled

```js
"dataFeed": {
 "enabled": true,
 "allowExternalSourceUrl": false
},
"dataSources": [
 { "id": "products", "name": "Products", "type": "JSON", "sourceUrl": "https://api.acme.test/products.json" }
]
```

* If the `dataFeed` section is not passed at all, or `enabled` is `false`, users see only the “Website Page” option — no “Data Feed”.
* enabled: `true` with a non-empty  `dataSources`  shows the Data Feed option with your sources listed in the Data Source dropdown; when `allowExternalSourceUrl: true`, the “External Source URL” option is added to the list.
* `allowExternalSourceUrl: false` hides the “External Source URL” option, so users can pick only from the sources you passed.
* A configuration with no available source is treated as disabled: `enabled: true` with an empty `dataSources` and  `allowExternalSourceUrl: false` hides the Data Feed option entirely.

Sample (external URLs only):

```js
"dataFeed": {
 "enabled": true,
 "allowExternalSourceUrl": true
}
```

### calendarEventLinkEnabled

Controls the availability of the **Calendar Event Link** type in the Link control. With this link type, users describe an event (title, time, time zone, location, description, recurrence) right in the editor and get a generated add-to-calendar link they can attach to any clickable element. The link can be switched between seven calendar types — Stripo landing page, Google, Outlook, Yahoo, AOL, Apple, and a downloadable .ics file — and generated events are reusable across the elements of the same email via the Events tab of the link type dropdown.

Type: `Boolean`\
Default: `true`

When set to `false`, the Calendar Event Link option is not offered in the link type dropdown. Links already generated with this feature are plain href elements in the email HTML, so existing emails keep working regardless of this option.

**Sample**: `"calendarEventLinkEnabled": false`

### dragImageFromGalleryEnabled

Controls the availability of the drag-to-document gesture in the settings-panel image gallery. With this feature, users can drag an image thumbnail out of the gallery and drop it directly onto the canvas — onto an existing image block to fill/replace it, or next to a block to insert a new image block at that position. It applies only to galleries whose target is the document itself (the main image picker); auxiliary galleries (rollover image, timer expiration image, menu/social icons, dark-mode variant, etc.) never offer drag-to-document, regardless of this flag.

Type: `Boolean`\
Default: `true`

When set to `false`, gallery thumbnails are no longer draggable onto the canvas. Users can still pick an image by clicking a thumbnail in the gallery — this flag only turns off the drag-and-drop path, not image selection itself.

### playInEmailEnabled

Controls the availability of the **Play in email** mode of the Video block. In this mode, the editor embeds a playable video into the email: an AMP-powered player for supported clients, with an automatically generated GIF and poster fallback for all other email clients.

Type: `Boolean`\
Default: `false`

The mode is disabled by default. To make it available to your users, pass `playInEmailEnabled: true` during the editor initialization — the **Play in email** tab then appears in the Video block settings.

**Plan availability:** the parameter takes effect on the Business and Enterprise Plugin plans. On lower plans,  `playInEmailEnabled: true` is ignored and the mode stays disabled.

Disabling the mode affects only creating and changing videos: video blocks that already exist in the template keep rendering and are exported with their assets as usual, while the upload and regeneration controls are disabled with an explanatory hint.

**Sample**: `"playInEmailEnabled": true`

### elementLockEnabled

Enables the [Lock Element](/editor-configuration/lock-element) feature in your integration — the ability to lock stripes, structures, and containers against content or style changes.

Type: `Boolean`\
Default: `false`

The feature is disabled by default. When set to `true`, the Lock Element control becomes available to users who have the `elementsLock.write` permission — the parameter enables the feature but does not replace the permission check.

When the parameter is omitted or set to `false`, only the lock management control is hidden: elements that are already locked in the template remain protected according to their lock settings.

### historySaveAsNew

The `historySaveAsNew` function enables the Restore as new action in the Version History menu, which creates a new email from a selected version without modifying the current one. The editor passes the selected version's `patchID` to your application; creating the new email and copying the version is performed by your backend through the [Email Model Clone API](/reference/cloning-an-email-model#description/introduction).

**Function Signature**

```js
historySaveAsNew: function({ patchID }, callback) {
  // patchID:  string -- UUID of the version selected by the user
  // callback: (error: string | null) => void -- call with null on success or an error message on failure
}
```

The action appears in the Version History menu only when this callback is provided, the user has the `versionHistory.write` permission, and the editor is online. The editor itself does not create a new email, modify the current model, or switch the user to another email.

For the full flow — backend copy request, retrieving the new email's HTML/CSS, and opening the new email — see [Restore a Version as a New Email](/plugin-invocations/javascript-api#restore-a-version-as-a-new-email).

### onUpdateDisplayConditionsForViewOptions

```js
onUpdateDisplayConditionsForViewOptions: function(displayConditions) {
  // displayConditions is an array of:
  // { id: 'audience-new', name: 'New Customers', visibility: true }
  // Optionally update your View Options UI or save state externally
}
```

### onViewOptionsReset

```js
onViewOptionsReset: function(entity, entityId) {
  // Optionally reset your interface to the default state
}
```

### onSettingsPanelBlockSorting

```js
onSettingsPanelBlockSorting: function(names) {
  return names.sort();
}
```

### onPreheaderChanged

```js
onPreheaderChanged: function(preheader) {
  // Custom logic to execute when the email preheader changes
}
```

### onRtlSet

```js
onRtlSet: function(value) {
  console.log('rtl set', value);
}
```

### onTemplateLoaded

```js
onTemplateLoaded: function() {
  // Custom logic to execute after the email is fully rendered
}
```

### onTitleChanged

```js
onTitleChanged: function(title) {
  // Custom logic to execute when the email title changes
}
```

### onCodeEditorVisibilityChanged

```js
onCodeEditorVisibilityChanged: function(isOpen) {
  // ...
}
```

### onConnectCustomFont

When provided, the **`onConnectCustomFont`** callback activates a **"Connect another font"** option in the font family dropdown. When the user clicks this option, the editor invokes the callback so your application can open a custom UI to collect font details and register the new font.

**Parameters:**

* `onSave` — a callback provided by the editor.
  Call it with font data once the user confirms. Accepts an object with the following fields:
  * `name` - display name shown in the selector,
  * `value` - CSS `font-family` declaration,
  * `link` (optional) - URL to the font stylesheet,
  * `importMethod` (optional) - `'link'` | `'import'` | `'fontFace'` | `'local'`.

**Usage:**\
Define the **`onConnectCustomFont`** function during the initialization of the Stripo editor. When the user clicks "Connect another font", the editor invokes this function. Open your own modal or font selection UI, collect the font details, and call `onSave` to register the font.

**Sample:**

```js
onConnectCustomFont: function(onSave) {
  // Open your font selection UI, then call onSave with font data
  onSave({
    name: 'Roboto',
    value: "Roboto, sans-serif",
    link: 'https://fonts.googleapis.com/css2?family=Roboto',
    importMethod: 'link'
  });
}
```

This callback ensures that your application can provide users with a seamless font connection experience directly from the font selector. If this parameter is not provided, the "Connect another font" option does not appear in the dropdown (unless activated via the `external-custom-font` extension in plugin mode). See [User-Added Fonts in Editor](/editor-configuration/initialization-settings#user-added-fonts-in-editor).

### onSettingsPanelPositionChanged

```js
onSettingsPanelPositionChanged: function(position) {
  // Custom logic to execute when the settings panel position changes
}
```

### onVersionHistoryVisibilityChanged

```js
onVersionHistoryVisibilityChanged: function(isOpen) {
  // Custom logic to execute when version history visibility changes
}
```

### onVersionHistoryReadAccessChanged

```js
onVersionHistoryReadAccessChanged: function(enabled) {
  // Custom logic to execute when version history read access changes
}
```

### onSaveStarted

```js
onSaveStarted: function() {
  // Custom logic to execute when the save procedure starts
}
```

### onSaveCompleted

```js
onSaveCompleted: function() {
  // Custom logic to execute when the save procedure is completed
}
```

### onEditorVisualModeChanged

```js
onEditorVisualModeChanged: function(visualMode) {
  // Custom logic to execute when the visual mode changes
}
```

### onUsersInfoRequest

```js
onUsersInfoRequest: function (userIds, successCallback, errorCallback) {
  fetch(`/api/users/info`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ ids: userIds })
  }).then(res => res.json())
    .then(data => successCallback(data.users))
    .catch(err => errorCallback(err));
}
```

### onUsersInfoSearchRequest

```js
onUsersInfoSearchRequest: function (params, successCallback, errorCallback) {
  fetch(`/api/users/search?query=${encodeURIComponent(params.filter || '')}`)
  .then(res => res.json())
  .then(data => successCallback(data))
  .catch(err => errorCallback(err));
}
```

### onCommentModeChange

The `onCommentModeChange` function is called every time the editor's comment mode is turned on or off. Use it to keep your application's UI in sync with the editor — for example, to highlight your own "Comments" button in the host application header while the comment mode is active.

**Function Signature:**

```js
onCommentModeChange: function(isActive) {
  // isActive: boolean -- true when comment mode is turned on, false when it is turned off
}
```

**Usage:**\
Define the optional `onCommentModeChange` function during the initialization of the Stripo editor (the [Commenting](/editor-configuration/commenting) feature must be enabled). The callback fires on every state change, regardless of how it was triggered — a click on the comments control or the keyboard shortcut (holding Ctrl on Windows / Cmd on Mac while in comment mode).

**Sample:**

```js
onCommentModeChange: (isActive) => {
 myApp.header.setCommentsButtonActive(isActive);
}
```

### onUserListChange

```js
onUserListChange: function(usersList) {
  // Custom logic to execute when the user list changes
}
```

### onEvent

```js
onEvent: function(type, params) {
  // Handle different event types
}
```

### onEditorClicked

The `onEditorClicked` function is called at the beginning of any pointer interaction (`pointerdown`) inside the email preview area. Because the editor renders the email preview in a separate document, clicks inside it are not visible to the outside-click handlers of the host application.

This callback lets your application react to such clicks — for example, to close its own popovers, dropdown menus, or overlays when the user starts interacting with the email.

**Function Signature:**

```js
onEditorClicked: function() {
 // called without any payload
}
```

**Usage:**\
Define the optional `onEditorClicked` function during the initialization of the Stripo editor. The editor invokes it on every `pointerdown` inside the email preview. The first click both triggers the callback and performs the regular editor action (for example, selecting a block), so the user does not have to click twice.

**Sample:**

```js
onEditorClicked: () => {
 // Close all overlay menus of the host application
 myApp.overlayManager.closeAllOverlays();
}
```

### onDataChanged

```js
onDataChanged: function() {
  console.log('Data changed');
  // Additional logic to handle unsaved changes
}
```

### onElementCopy

```js
onElementCopy: function(modifier) {
  // Get the target element being copied
  const targetElement = modifier.getTargetNode();

  // Find all blocks (elements with class starting with 'esd-block')
  const blocks = targetElement.querySelectorAll('[class*="esd-block"]');

  // Set a custom attribute on each block to mark it as a copy
  blocks.forEach(function(block) {
    modifier.modifyHtml(block).setAttribute('data-copy-marker', 'copied');
  });
}
```

### onElementMove

The `onElementMove` function is called whenever a block, container, structure, or stripe is moved within the email template — via drag-and-drop or via keyboard shortcuts.

**Parameters:**

* `modifier` — A TemplateModifier object. The root node of the moved element is pre-set as the target. Use it to read and modify the moved element's HTML. For more information, refer to the [Template Modification System](https://plugin.stripo.email/extensions/template-modification).
* `sourceElement` (optional) — A read-only `ImmutableHtmlElement` representing the parent element from which the node was moved (its container, structure, or stripe before the move). Use it to inspect the origin of the move.\
  Resolving the source module:
  ```js
  const sourceModule = sourceElement?.getClosestModuleElement(); 
  const sourceModuleId = sourceElement?.getClosestModuleId();
  ```
  This parameter is undefined if the original parent could not be resolved (for example, if it was removed as part of the move flow).

**Note:** You do not need to call `apply()` explicitly. It is called automatically after your function returns, and your changes are merged with the move patch as a single undo/redo entry.

**Difference from `onElementCopy`:**

`onElementCopy` is triggered when an element is duplicated (a new node is inserted).\
`onElementMove` is triggered when an existing element changes position within the document tree — no new node is created. Use `onElementMove` when you need to react to repositioning, such as updating link-tracking IDs that depend on a module context.

**Sample:**

```js
onElementMove: function(modifier, sourceElement) { 
   // Determine which module the element was moved FROM   
   const sourceModuleId = sourceElement?.getClosestModuleId(); 
   // Determine which module the element was moved INTO 
   const targetModuleId = modifier.getTargetNode().getClosestModuleElement() ?.getAttribute('data-module-id'); 
   // If the element crossed a module boundary, regenerate its tracking ID 
   if (sourceModuleId !== targetModuleId) { 
      modifier.setAttribute('data-tracking-id', crypto.randomUUID()); 
   } 
}
```

### onModuleAdd

```js
onModuleAdd: function(action, modifier) {
  // Get the module being added or copied
  const targetElement = modifier.getTargetNode();

  // Generate new EVENT ID based on the action type
  const eventId = action === 'COPY'
    ? targetElement.getAttribute('event-id') + '_copied'
    : crypto.randomUUID();

  // Set attribute to root module node
  modifier.setAttribute('event-id', eventId);
}
```

### onModuleDetach

The `onModuleDetach` function is called when a user triggers the **"Unlink and Apply Changes Locally"** action for a synced module in the email template. It is the symmetric counterpart to [`onModuleAdd`](#onmoduleadd) and follows the same contract for the `modifier` parameter.

Without `onModuleDetach`, plugins that react to unlinking via the `module_detached` event and apply changes through a `templateModifier` produce two separate entries in the undo/redo stack — one for the unlink itself and one for the plugin's modifications.

This means the user must press Undo twice to fully revert the operation. `onModuleDetach` solves this by merging both the unlink action and your plugin-side modifications into a **single atomic undo/redo entry**. One Ctrl/Cmd+Z press reverts everything at once.

**Parameters:**

* **`modifier`** — A `TemplateModifier` object that provides methods to modify the unlinked module's HTML. The module's root node is set as the target node. The contract is identical to the `modifier` in `onModuleAdd`. For more information, refer to the [Template Modification System](/extensions/template-modification).

**Usage:**\
Define the `onModuleDetach` function during the initialization of the Stripo editor. Use it to perform any custom HTML transformations needed at the moment of unlinking — such as injecting link-tracking attributes, stripping internal `data-` attributes, or updating references. You do not need to call `apply()` at the end; it is called automatically, and your changes are merged with the unlink patch as one atomic operation.

**Backward compatibility:**\
If `onModuleDetach` is not defined, the existing `module_detached` event continues to fire as before, and any modifications applied via `templateModifier` in that event handler will create a separate undo-stack entry (requiring two Undo presses to fully revert).

**Sample:**

```js
onModuleDetach: function(modifier) { 
   // Get the root node of the module being unlinked 
   const targetElement = modifier.getTargetNode(); 
   // Remove internal tracking attribute before unlinking
   modifier.removeAttribute('data-module-sync-id');
   // Add a custom marker to identify locally-applied modules
   modifier.setAttribute('data-local-module', 'true'); 
}
```

### onBeforeModuleSave

```js
onBeforeModuleSave: function (data) {
  const copilotApi = window.StripoEditorApi.editorCopilotApi;
  const modifier = copilotApi.getTemplateModifier();

  modifier
    .modifyHtml(data.moduleNode)
    .setAttribute('data-saved-at', new Date().toISOString())
    .apply({
      key: 'Set module save timestamp',
      params: {},
      getValue() {
        return { key: this.key, params: this.params };
      }
    });

  return { canSave: true };
}
```

### onImageSelected

The `onImageSelected` function is called whenever an image is inserted into the editor — from any image gallery tab (General, Custom/External) **or via upload from the local machine**. It fires for **every block that contains an** `<img>` **tag (Image, Button, Menu, Video, Banner)**. This initialization parameter allows developers to programmatically add custom `data-*` attributes (or any other attributes/classes/styles) to the inserted `<img>` immediately after selection.

**Function Signature**

```js
onImageSelected: function(params, modifier, selectedImgNode) {
  // params:      	Image metadata object
  // modifier:    	HtmlNodeModifier already targeting the inserted <img>
  // selectedImgNode: Immutable, read-only wrapper of the inserted <img>
}
```

**Parameters:**

* `params` **–** image metadata (only `url` is guaranteed; other fields are optional):
  ```js
  {
    url:      	"https://example.com/image.jpeg", // freshly inserted URL (always present)
    originalName: "photo.jpeg",                 	  // original filename
    width:    	640,                          	  // image dimensions in pixels
    height:   	427,
    sizeBytes:	61656,                        	  // file size in bytes
    aiGenerated: true,                              // present when the image was created with the built-in AI image generator
    altText:  	"",                           	  // existing ALT text from the gallery item
    thumbnailUrl: "https://example.com/thumb.jpeg", // thumbnail URL for preview
    labels: {                                   	  // custom labels / metadata
      category: "Summer Campaign",
      userId:   "user123"
    }
  }
  ```
* `Modifier` – `HtmlNodeModifier` already targeting the inserted `<img>` node. Use it to mutate the node: `setAttribute`, `removeAttribute`, `setClass`, `setStyle`, etc., refer to the [HTML Node Modification Section](/extensions/reference/modification/HtmlNodeModifier#htmlnodemodifier).
* `selectedImgNode` – immutable, read-only wrapper of the `<img>` node (`getAttribute`, `hasClass`, `getStyle`, `getTagName`, `querySelector` …).

  **IMPORTANT:** it reflects the CRDT state **before** the new `src` is committed — `selectedImgNode.getAttribute('src')` returns the *previous* URL. Use `params.url` to read the freshly inserted value.

The `aiGenerated` flag lets your platform distinguish AI-generated visuals from regular images — for example, to apply a visible AI-content disclosure in your own UI, as required for realistic AI-generated images of people by the EU AI Act (Article 50). The flag accompanies the image both when it is uploaded to the image storage and when it is selected from the gallery.

**Use Cases:**\
Define the `onImageSelected` function during the initialization of the Stripo editor. This function will be automatically triggered every time a user selects and inserts an image from any gallery tab into any image-containing block: Image, Button, Menu, Video, Banner, etc.

The callback allows you to execute custom logic to enrich image elements with additional metadata before they are permanently added to the template.

**Sample:**

```js
onImageSelected: (params, modifier, selectedImgNode) => {
  if (params.labels?.category === 'summer-campaign') {
    modifier
      .setAttribute('data-campaign', params.labels.category)
      .setAttribute('data-recipient', window.externalService.getRecipient());
  }
}
```

### onImageGalleryViewModeChange

The `onImageGalleryViewModeChange` function is called when a user changes the view mode of the image gallery during the editing session. This function helps to notify your application about changes in the gallery display mode, allowing you to manage user preferences and adjust the interface accordingly in real-time.

**Parameters:**

* **mode** — string — The new view mode selected by the user. Possible values are `grid`, `masonry`, or `list`.

**Usage:**\
Define the `onImageGalleryViewModeChange` function during the initialization of the Stripo editor. This callback is invoked whenever the user switches between different image gallery view modes, allowing your external front-account system to receive and process these changes.

**Sample:**

```js
onImageGalleryViewModeChange: function(mode) {
  // Notify your application about gallery view mode change
  console.log('Gallery view mode changed to:', mode);
  
  // Send to your backend or state management
  updateUserPreference('galleryViewMode', mode);
}
```

This callback ensures that your application stays synchronized with user interactions in the image gallery, enabling you to persist user preferences, update UI controls, or log analytics data whenever the gallery view mode is changed.

### onUiSettingsChange

The `onUiSettingsChange` function is called when a user changes an editor UI preference during the editing session, for example, switches the view mode of the modules gallery. It receives only the fields that changed, so your application can save them and pass the full set back in the `uiSettings` parameter on the next initialization.

**Parameters:**

* `changes` — object — Only the fields of `uiSettings` that changed. Currently, the editor reports `moduleGalleryViewMode` (`grid`, `smallGrid`, or `list`). Switching between Desktop and Mobile view is not reported here; use `onEditorVisualModeChanged` for that.

**Sample:**\
Define the `onUiSettingsChange` function during the initialization of the Stripo editor.

```js
onUiSettingsChange: function(changes) {
  // changes example: { moduleGalleryViewMode: 'list' }
  saveUserPreferences(changes);
}
```

## Metadata Information

The `metadata` parameter is mandatory because it is used to identify the email. Additionally, you can specify the username and avatar, which will be used in the version history and during simultaneous editing. You can pass any information needed by the editor, and all these data will be sent to your server in the information provided to the permission checker API.

This is also the right place to define the values for any variables needed during initialization. For example, if a customer configures the folder path for [images](image-gallery) or [modules](modules-library) and needs to operate with specific variables, the editor needs to know the values for those variables. This can be accomplished by including them in the `metadata` parameter.

| Parameter    | Description                                                                         | Required |
| ------------ | ----------------------------------------------------------------------------------- | -------- |
| `emailId`    | Email identifier                                                                    | Yes      |
| `username`   | Username. Used for version history and simultaneous editing                         | No       |
| `email`      | User email                                                                          | No       |
| `avatarUrl`  | URL to the user's avatar image. Used for visualization during simultaneous editing. | No       |
| `customVar1` | Custom variable 1                                                                   | No       |
| `customVar2` | Custom variable 2                                                                   | No       |

Example:

```js
{
  ...,
  "metadata": {
    "emailId": "123",
    "username": "John Smith",
    "email": "john.smith@stripo.email",
    "avatarUrl": "https://yourdomail.com/avatars/avatar_1.png",
    "customVar1": "12345",
    "customVar2": "12345"
  },
  ...
}
```

**Use Cases**

1. Version History and Simultaneous Editing:

   * The `username` and `avatarUrl` help in identifying users in the version history and during simultaneous editing.

2. Folder Paths:

   * If the customer configures a folder path for storing images or modules, the `custom` variables can be included in the metadata. This allows the editor to know where to save or retrieve these resources.

3. Custom Variables:

   * Any other custom variables required by the editor can be included in the `metadata` parameter. For instance, if certain configuration settings or values need to be dynamically provided during initialization, they can be passed here.

By defining these values during initialization, the editor is equipped with all necessary information to function correctly and efficiently, tailored to the customer's specific setup and requirements.

:::success
Please be advised, all the data from this parameter will be included into the UIData parameter within the [Email Resources Permissions API](server-webhooks#email-resources-permissions-api).
:::

## Notification Settings

The notifications parameter is used to display different types of messages on the application's UI.

For example,

::: image-wrap
![](/img/plugin/new/image12.webp){width=964 height=144}
:::

Message parameters:

Example:

```js
{
 ...,
 "notifications": {
   "info": function(message, id, params) { /* Show info message */ },
   "error": function(message, id, params) { /* Show error message */ },
   "success": function(message, id, params) { /* Show success message */ },
   "warn": function(message, id, params) { /* Show warn message */ },
   "loader": function(message, id, params) { /* Show loader message */ },
   "hide": function(id) { /* Hide message by id */ },
 },
 ...
}
```

## Pasting Content Restrictions

The `textEditorAllowedPasteContent` parameter allows you to restrict the tags and attributes that can be pasted from the clipboard into a text block. This is particularly useful in scenarios where maintaining a consistent and secure format for the text blocks is critical.

**Use Case:**

Imagine you are developing an email template editor for a marketing platform. To ensure that the pasted content adheres to your formatting standards and to prevent any potential security risks from unwanted HTML tags or attributes, you can use the `textEditorAllowedPasteContent` option. By defining which HTML tags and attributes are allowed, you can ensure that only specific elements and attributes are included when users paste content into the text editor. Any tags and attributes not specified in the allowed list will be ignored, and the text will be inserted as plain text.

For example, you may want to allow basic formatting tags like `<p>`, `<a>`, `<strong>`, and `<em>` but restrict other tags that could disrupt the email's design or introduce security vulnerabilities. Additionally, you can specify which attributes are allowed for certain tags, such as allowing only `href` and `title` attributes for `<a>` tags, and `src` and `alt` attributes for `<img>` tags. Other tags and attributes will be stripped out, ensuring that only clean and secure content is inserted.

| Parameter    | Description                                          |
| ------------ | ---------------------------------------------------- |
| `tags`       | An array of tags that are allowed to be pasted       |
| `attributes` | An array of attributes that are allowed to be pasted |

```js
{
  ...,
  "textEditorAllowedPasteContent": {
    "tags": ['b', 'strong', 'i', 'a'],
    "attributes": ['href', 'target']
  },
  ...
}
```

In this example, only the specified tags and attributes will be permitted when pasting the coppied content into the text block. This ensures that the content remains consistent with the desired format and helps prevent any unintended HTML or security issues.

## Code Editor Settings

This parameter is used to configure the default display state of the code editor.

::: image-wrap
![](/img/plugin/new/image13.webp){width=1999 height=425}
:::

| Parameter              | Description                                           |
| ---------------------- | ----------------------------------------------------- |
| `isOpen`               | True — if the code editor is open by default          |
| `isDefaultCSSOpen`     | True — if the default CSS section is open by default  |
| `isCustomCSSOpen`      | True — if the custom CSS section is open by default   |
| `containerHeight`      | Default height of the code editor in pixels           |
| `defaultCSSPanelWidth` | Width of the default CSS section by default in pixels |
| `customCSSPanelWidth`  | Width of the custom CSS section by default in pixels  |

Example:

```js
{
  ...,
  "codeEditor": {
    "isOpen": false,
    "isDefaultCSSOpen":true,
    "isCustomCSSOpen": false,
    "containerHeight": 80,
    "defaultCSSPanelWidth": 100,
    "customCSSPanelWidth": 100
  },
  ...
}
```

In this example, the code editor is initially closed (`isOpen: false`), the default CSS section is open (`isDefaultCSSOpen: true`), and the custom CSS section is closed (`isCustomCSSOpen: false`). The default height of the code editor container is set to 80 pixels, and both the default and custom CSS panel widths are set to 100 pixels.

## Merge Tags Setup

The `mergeTags` parameter is used to specify merge tags displayed in the settings of a text block. Merge tags are placeholders that dynamically insert personalized content, such as a recipient's name or other specific information, into the text. This is particularly useful in email marketing, where personalization can significantly improve engagement and response rates.

**Use Case:**

Imagine you are developing an email marketing platform that allows users to create and send personalized emails to their subscribers. To enhance the effectiveness of these emails, you want to allow users to insert personalized content easily. The mergeTags parameter lets you define which merge tags are available for users to insert into their email text blocks. For example, you might want to include merge tags for the recipient's first name, last name, and specific campaign details.

By defining these merge tags, users can quickly add personalized elements to their emails without manually inputting each recipient's information. When the email is sent, the merge tags are replaced with the actual data for each recipient, creating a more personalized and engaging message.

::: image-wrap
![](/img/plugin/new/image14.webp){width=400 height=372}
:::

Example:

```js
{
  ...,
  "mergeTags": [
    {
      "category": "Yespo",
      "entries": [
        {
          "label": "First Name",
          "value": "%FIRSTNAME|%",
          "previewValue": "John",
          "hint": "Recipient's first name",
          "hidden": false
        },
        {
          "label": "Last Name",
          "value": "%LASTNAME|%",
          "previewValue": "Doe",
          "hint": "Recipient's last name",
          "hidden": false
        }
      ]
    }
  ],
  ...
}
```

Using these merge tags, users can effortlessly create personalized and targeted email content, improving the overall effectiveness of their email marketing campaigns.

### Custom Appearance of Merge Tags

You can independently choose how exactly your personalization tags should be displayed. This can be configured during initialization with the following parameters:

* `customAppearanceMergetags`: Enables custom appearance for merge tags.
* `customAppearanceMergetagsInLinks`: Enables custom appearance for merge tags within links.
* `customAppearanceMergetagsBorderColor`: Specifies the border color for merge tags.
* `customAppearanceMergetagsBackgroundColor`: Specifies the background color for merge tags.

**Example**:

```js
{
  ...
  "customAppearanceMergetags": true,
  "customAppearanceMergetagsInLinks": true,
  "customAppearanceMergetagsBorderColor": "blue",
  "customAppearanceMergetagsBackgroundColor": "green"
}
```

This configuration customizes the appearance of merge tags, making them visually distinct with a blue border and green background.

### Custom Thumbnails for Images with Merge Tags

When customers use personalization tags (Merge tags) for different images, the editor can't recognize them and as a result, replaces the image with a "broken" icon:

::: image-wrap
![](/img/plugin/new/image62.webp){width=1187 height=383}
:::

Some users find this confusing. If you want to replace the "broken" icon with your own image, use the configuration below:

```js
{
  "defaultImgForMergeTagSrc": "URL"
}
```

where:

* `URL` - is the link to your image.

You should apply this configuration during initialization, and it will work as shown in the screenshot below:
::: image-wrap
![](/img/plugin/new/image62_2.webp){width=2362 height=606}
:::

### Merge Tag Autocomplete

With the `mergeTagsAutocomplete: true` initialization parameter, users see inline suggestions as they type merge tag syntax in the Text block. When the typed fragment (two or more characters) matches the beginning of a configured tag `value` — or a tag `label`, once the fragment starts with a tag opening sequence — the editor opens a flat suggestion list next to the caret. Each item shows the tag's `label` with its `value` as a subtext.\
::: image-wrap
![](/img/plugin/new/image251.webp){width=1999 height=968}
:::
Selecting a suggestion replaces the typed fragment with the merge tag and places the caret after it. The inserted tag immediately follows the current **View Options → Merge Tags** display mode (raw value, label chip, or preview value).

**Notes:**

* The suggestions are matched against the tag `value` and `label` only — `previewValue` never triggers the autocomplete, so preview data cannot pop up suggestions for regular words.
* Tags with `hidden: true` are excluded from the suggestions.
* Typing the full tag syntax manually still works as before: the fragment is converted into a merge tag by the regular rendering flow, and the suggestion list never intercepts Enter or Tab unless an item was explicitly highlighted with the arrow keys.
* The autocomplete works in the Text block canvas only; settings panel inputs and the code editor are not affected.
* When the merge tags UI is overridden by an extension (custom `UE-MERGETAGS` element), the autocomplete is disabled.

The autocomplete is disabled by default — pass `mergeTagsAutocomplete: true` during initialization to enable it.

### Using Merge Tags as Color Values

Merge tags can be used not only in text, but also as dynamic color values — for example, to let your users reference a brand color that is substituted by your system at sending time.

A merge tag is treated as a color merge tag when its previewValue contains a valid color value (only a hex code is expected). No extra configuration is needed:

```js
"mergeTags": [
  {
    "category": "Brand",
    "entries": [
      {
        "label": "Primary brand color",
        "value": "{{brand_color}}",
        "previewValue": "#93c47d"
      }
    ]
  }
]
```

For such tags:

* The user can insert the tag as the value of color settings (background, border, font, or link color);
* The editor stores and exports the tag exactly as configured in `value` ({{brand\_color}}) — the value is not converted to a hex color, so your system can substitute the real color at sending time;
* On the canvas and in the color picker preview, the editor renders the color from `previewValue`.

An entry whose `previewValue` is not a valid color is treated as a regular text merge tag and is not offered as a color value. Arbitrary strings that do not match any configured merge tag are still rejected by the color inputs, as before.

## Social Networks Configuration

The `socialNetworks` parameter is used to specify the list of social networks that will be added to the social networks block. This feature is especially useful for individuals or businesses who want to include links to their social media profiles directly within their email templates, allowing recipients to easily connect with them across various platforms.

**Use Case:**

Imagine you are creating an email template for a marketing campaign. Including links to your social media profiles in the email can increase engagement and drive traffic to your social media pages. By specifying the `socialNetworks` parameter, you can define which social media icons and links should be displayed in the email's social networks block. If this parameter is specified with social networks, these icons will be added by default once the social network block is dropped into the email template. This ensures that your audience can easily find and follow your social media accounts, helping to build your online presence and foster community engagement.

::: image-wrap true
![](/img/plugin/new/image15.webp){width=1084 height=906}
:::

| Parameter | Description                       | Default   |
| --------- | --------------------------------- | --------- |
| `name`    | Name of the social network. Defines the icon and its type; see the list of supported values below. | — (required) |
| `href`    | URL of the social network profile | — |
| `alt`    | Alt text of the icon. Applied per item. | the social network name as in the editor's social network catalog |
| `title`    | Title (tooltip) of the icon. Applied per item. | the social network name as in the editor's social network catalog |

::: image-wrap
![](/img/plugin/new/image16.webp){width=400 height=319}
:::

Example:

```js
{
  ...,
  "socialNetworks": [
    {
      "name": "instagram",
      "href": "https://instagram.com/acme",
      "alt": "IG",
      "title": "Our Instagram"
    },
    {
      "name": "facebook",
      "href": "https://facebook.com/acme"
    }
  ],
  ...
}
```

The `alt` and `title` fields are optional and independent — you can pass either, both, or none, for each network separately. A missing field falls back to the catalog default; an explicitly empty string (`"alt": ""`) produces an empty attribute in the HTML. Values longer than the limits are trimmed: up to 100 characters for `title` and up to 500 for `alt`. The `name` field remains the only source of the icon and its type — overriding `title` does not affect which icon is rendered.

The configured values are applied when the social networks block is added to the email. If the user later edits the texts through the block's "Title and alt text" controls, the user's values are kept and are not overwritten by the configuration on reopening the email.

**Supported Social Network Names or Icons:**

Pass the `name` values exactly as listed below (matching is case-insensitive, but spaces, dots, and dashes are not ignored — e.g. `lastfm` works, `Last.fm` does not).

**Legacy values.** The following names are no longer shown in the editor's icon picker but are still accepted in the `socialNetworks` configuration, so existing integrations keep working: `twitter` (rendered with the X icon — it is automatically mapped to `xcom`), `skype`, `hangouts`, `askfm`, `yammer`, `googleplus`.

Using the `socialNetworks` parameter ensures that the social media links are consistently formatted and easily accessible, enhancing the overall effectiveness of the email marketing campaign by encouraging social media interaction and engagement.

You can independently choose which style should be applied to the social icons when your customer drops them into an email message. All you need to do is initialize the Plugin with the configuration below:

```js
"socialIconsDefaultView": "squareColoredBordered"
```

**Available Values:**

```
logoBlack, logoGray, logoWhite, circleColored, roundedColoredBordered, circleColoredBordered, roundedColored, squareColored, squareColoredBordered, circleBlack, circleBlackBordered, roundedBlack, roundedBlackBordered, squareBlack, squareBlackBordered, circleGray, circleGrayBordered, roundedGray, roundedGrayBordered, squareGray, squareGrayBordered, circleWhite, circleWhiteBordered, roundedWhite, roundedWhiteBordered, squareWhite, squareWhiteBordered, logoColored
```

The final result depends on your chosen value. In this example, the configuration is set to `logoColored`.

By customizing the `socialIconsDefaultView` parameter, you can ensure that the social icons in your email messages match your preferred style and branding.

## Special Links Configuration

The `specialLinks` parameter is used to specify a list of links that will be added to the link selection component. This feature is particularly useful for adding commonly used links, such as unsubscribe, support, or social media profile links, directly into email templates. It ensures consistency, saves time, and makes the email creation process more efficient.

::: image-wrap
![](/img/plugin/new/image63.webp){width=400 height=331}
:::

**Use Case:**

Imagine you are managing an email marketing platform where users frequently need to include specific links in their email templates, such as unsubscribe links or customer support links. Manually entering these URLs each time can be tedious and prone to errors. The `specialLinks` parameter allows you to define these essential links once, and then make them easily accessible for users to insert into their emails.

For example, you might want to include links for unsubscribing from the newsletter, contacting support, or viewing email in browser. By using the `specialLinks` parameter, you can group these links under specific categories, making it easy for users to find and insert them into their emails

Example:

```js
{
  ...,
  "specialLinks": [
    {
      "category": "Yespo",
      "entries": [
        {
          "label": "Unsubscribe",
          "value": "https://my.yespo.io/unsubscribe",
          "hidden": false
        }
      ]
    }
  ],
  ...
}
```

This approach not only ensures that the links are correctly formatted and consistently used but also significantly speeds up the email creation process. It reduces the likelihood of errors and enhances the overall user experience by providing quick access to frequently used links.

Using the `specialLinks` parameter, you can help users maintain a high standard of professionalism and compliance in their email campaigns while also making the editing process more efficient and user-friendly.

## Share Link Configuration

The `hideShareTab` and `hiddenShareItems` parameters give integrators fine-grained control over the **Share tab** that appears inside the link-type selector of the Link control (used in button blocks, image blocks, text links, and the hyperlink modal).

::: image-wrap true
![](/img/plugin/new/image82.webp){width=1071 height=433}
:::

By default, the **Share tab** is visible and contains four items: **Facebook**, **X**, **LinkedIn**, and **Pinterest**. These parameters let you hide the entire tab or suppress individual items — for example, when your platform has its own sharing logic or when certain networks are not relevant to your users.

### Use cases

Consider an ESP that has built its own social-sharing workflow outside the editor. Showing the editor's built-in Share tab would confuse users with redundant options. By setting `hideShareTab: true`, the integrator removes the tab entirely, keeping the link selector clean and focused on the options that matter.

Alternatively, if an integrator wants to keep the Share tab but their platform does not support Pinterest or X, they can pass `hiddenShareItems: ['pinterest', 'x']` to suppress only those items while leaving Facebook and LinkedIn visible.

### Auto-hide tabs row rule:

If the combination of your configuration (for example, \`Personalization\` disabled at the feature level \*\*and\*\* \`hideShareTab: true\`) results in only \*\*one\*\* tab remaining in the link-type selector, the tabs row is hidden entirely. The user sees the contents of the single remaining tab directly, without a tab strip above it.

| Parameter | Description |
| :---- | :---- |
| `hideShareTab` | `boolean`. When `true`, the entire Share tab is removed from the link-type selector. Its content and related translations are absent from the DOM. Defaults to `false`. |
| `hiddenShareItems` | `string[]`. An array of share-item keys to hide within the Share tab. Supported keys: `'facebook'`, `'x'`, `'linkedin'`, `'pinterest'`. Items not listed remain visible. Defaults to `[]` (all items shown).  |

#### Example — hide the entire Share tab:

```js
{
  ...,
  "hideShareTab": true,
  ...
}
```

#### Example — hide specific share items:

```js
{
  ...,
  "hiddenShareItems": ["pinterest", "x"],
  ...
}
```

**Note:** These parameters apply uniformly across all places where the Link control with the protocol selector is used: button block, image block, text link, and the hyperlink modal.

## Custom Appearance of Special Links

Please refer to the section [Custom Appearance of Merge Tags](#custom-appearance-of-merge-tags).

## View Options

The **View Options** feature allows your end users to control how the email template is rendered inside the editor. This helps them focus on the version of the message that is most relevant to them — whether it's HTML or AMP, mobile or desktop, personalized or raw content.

View Options do not affect the final exported code. They change only what is displayed in the editor for the current user.

**Use Cases:**
Here are typical scenarios where `viewOptions` bring value to your end users:

* **QA testing.** A QA engineer wants to verify how the AMP version of the email renders without interference from HTML blocks.
* **Content personalization.** A marketer previews merge tags as final values to validate personalization logic.
* **Condition debugging.** A support specialist investigates visibility logic by toggling hidden blocks or specific display conditions.
* **Simplified writing.** A copywriter works in a distraction-free environment by hiding irrelevant structures or fallback content.

Each user sees only their own specified View Options — they are not shared across collaborators.

### UI Behavior and Editor Feedback

When you implement View Options in your interface (e.g., via a dropdown or toggles, see the sample below), users will interact with them to switch between different preview modes.

::: image-wrap
![](/img/plugin/new/image204.webp){width=350 height=343}
:::

By default, the template is rendered based on the `viewOptions` object passed during editor initialization. These values define the initial display context for the editor session.

If the user modifies any of the View Options through your custom UI, the editor will detect this and render content accordingly. In such cases, a persistent notification appears above the Settings panel. This warning explains that some elements might currently be hidden and includes a **Restore** button to revert back to the default view.

::: image-wrap
![](/img/plugin/new/image205.webp){width=350 height=189}
:::

Example scenario:

* You pass `showHiddenElements: true` and `mimeType: 'both'` during initialization.
* The end user switches to `mimeType: 'html'` and disables hidden elements.
* The editor displays a banner: *"Some elements may be hidden due to active view options"* with a **Restore** CTA.

This helps users understand that hidden content is not deleted but simply filtered out.

### How to use

Add the `viewOptions` parameter to your plugin initialization script to control how the editor displays the template content.

Below is an example of how to pass this parameter:

```js
viewOptions: {
  showHiddenElements: true, // show/hide hidden elements in the template
  mimeType: 'both',         // 'both' | 'html' | 'ampHtml'
  mergeTags: raw,           // 'raw' | 'label' | 'value'
  showPinsInEditor: false,
  displayConditions: [      // show/hide elements with display conditions
    {
      id: 'audience-new',
      name: 'New Customers',
      visibility: true
    }
  ]
}
```

### Parameter Reference

### Controlling View Options via API

If your interface includes custom controls (e.g., toggles, dropdowns) that allow users to change the way the email is displayed, you should use the `setViewOptions` method to update the editor view dynamically. See reference in [JavaScript API](/plugin-invocations/javascript-api#view-options-api). This method applies new values for MIME type, merge tag rendering, or visibility filters in real time, without reinitializing the editor — it updates the display instantly.

When calling this method, the editor updates its display immediately and triggers internal logic (like banners, conditional rendering, etc.). You can pass the full object or partial updates depending on your logic.

Separately, the editor may update the internal list of display conditions, for example, when the user creates and applies a new condition or deletes an existing one in the settings panel for this specific email template opened in the editor. The plugin will invoke your `onUpdateDisplayConditionsForViewOptions` callback in two cases:

* **On initialization** — to provide the full list of nodes that use display conditions, along with their visibility states;

**On condition update** — whenever a new display condition is created, removed, or applied to a node within the editor. In such cases, the editor will invoke your callback `onUpdateDisplayConditionsForViewOptions`, passing the updated list of active condition IDs with their names and visibility states.

### This allows you to:

* stay in sync with the condition logic configured inside the editor,
* persist view settings externally if needed,
* update your own UI state accordingly.

Example of how the editor will call your callback:

```js
onUpdateDisplayConditionsForViewOptions: function(displayConditions) {
  // displayConditions is an array of:
  // { id: 'audience-new', name: 'New Customers', visibility: true }
  // Optionally update your View Options UI or save state externally
}
```

And finally, when the user clicks the "Restore" button in the View Options banner, the `onViewOptionsReset` callback will be triggered by the plugin. In this case, your application should remove any viewOptions stored on your end for this user and reset the interface accordingly.

Example:

```js
onViewOptionsReset: function(entity, entityId) {
  // Optionally reset your interface to the default state
}
```

### Behavior Notes

* View Options affect only the editor view — not the exported result.
* In Commenting Mode, all View Options reset to default. Previous settings are restored upon exit.
* In Code View, all content is always shown regardless of filters.
* If filters hide part of the content, the editor displays a persistent message with a reset button.

## Template Theme Mode

The **Template Theme Mode** option allows you to define how the opened email template is visually rendered inside the editor — in **Light** or **Dark** mode.

This setting affects **only the editor UI rendering** and does **not** modify the email HTML, styles, or exported content. It is designed to improve editing comfort and visual consistency with your application.

:::success
We understand that different email clients (such as Gmail, Outlook, Apple Mail, etc.) apply their own algorithms to determine how an email is rendered in dark mode. Because of this, **it is not possible to fully replicate or guarantee identical rendering across all inboxes**.
The purpose of this feature is **not pixel-perfect emulation**, but rather a **fast visual check** based on a controlled dark-mode simulation inside the editor.

You can rely on the following principles:

* If the template looks **correct in the editor’s Dark mode**, it is very likely to render correctly in real email clients.
* If a **visual issue is noticeable in the editor**, there is a high probability that the same issue will appear in at least some email clients.

This makes Template Theme Mode a practical tool for **early risk detection**, rather than a strict preview of a specific mailbox.
:::

### **Use cases**

Template Theme Mode is useful when you need to evaluate how the **email content itself** behaves when rendered in a dark-mode environment.

Typical scenarios include:

* Checking how background colors, images, and text contrast behave when the template is displayed in dark mode.

* Identifying elements that rely on transparent or inherited backgrounds and may become unreadable.

* Detecting potential issues with icons, buttons, or images that were designed primarily for light backgrounds.

* Performing a quick visual risk check before exporting or sending an email campaign.

* Validating design decisions early, without testing the email in multiple real inboxes.

This feature helps you catch **dark-mode-related risks in the email layout**, while the template is being edited — not after it is sent.

### **How to use**

To define the initial theme for the opened template, pass the `templateThemeMode` parameter during editor initialization.

```js
templateThemeMode: 'DARK'
```

If the parameter is not provided, the editor opens in **Light** mode by default.

### **Parameter reference**

| Parameter | Type | Default | Description |
| ----- | ----- | ----- | ----- |
| `templateThemeMode` | `'LIGHT' \| 'DARK'` | `'LIGHT'` | Defines how the template is rendered inside the editor UI. This setting affects only the editor view and does not modify the email HTML or exported output. |

### **Controlling the theme via API**

You can also **change or read the template theme at runtime** using the [Template Theme Mode API](/plugin-invocations/javascript-api#template-theme-mode-api).

See the **Template Theme Mode API** section for details on:

* switching the theme dynamically;
* retrieving the current theme value.

## Font Management&#x20;

The Font Management option enables users to customize the fonts available in the Stripo editor, providing flexibility in design and brand consistency.

### Use Cases

Font management helps implement a variety of scenarios, such as:

* **Customizable Font Lists**: Users can customize the list of fonts loaded in the editor. For example, an interface in your app can be created to configure the editor with specific fonts.
* **Brand Consistency for Agencies**: Digital marketing agencies can customize the list of fonts in the editor according to a client's brand requirements.
* **Expanded Font Options**: To expand the list of available fonts in the editor, add your web fonts from popular services like Google Fonts.
* **Reduced Font Options**: By limiting the number of fonts, default fonts are removed, making it easier for users to adhere to brand guidelines.

### How to Activate

::: image-wrap
![](/img/plugin/new/image64.webp){width=350 height=453}
:::

To activate option, include the `editorFonts` parameter in the plugin initialization script. This parameter allows specifying custom fonts, displaying default fonts, and organizing favorite fonts.

```js
"editorFonts": {
  "showDefaultStandardFonts": true,
  "showDefaultNotStandardFonts": true,
  "favouriteFonts": {
    "label": "Favourite Fonts",
    "values": [
      {
        "name": "Barriecito",
        "fontFamily": "'Barriecito', cursive",
        "url": "https://fonts.googleapis.com/css?family=Barriecito&display=swap"
      }
    ]
  },
  "customFonts": [
    {
      "name": "Oswald",
      "fontFamily": "'Oswald', 'helvetica neue', helvetica, arial, sans-serif",
      "url": "https://fonts.googleapis.com/css?family=Oswald"
    },
    {
      "name": "Barriecito",
      "fontFamily": "'Barriecito', cursive",
      "url": "https://fonts.googleapis.com/css?family=Barriecito&display=swap"
    }
  ]
}
```

Find the parameter descriptions below:

:::success
Please be advised that Stripo accepts only the CSS font embedding method, and the CSS file must be hosted in HTTPS protocol. You can use services like Google fonts that provide host font stacks and a well-formatted CSS file. If you want to change the default set of fonts, you need to disable them and use custom fonts to indicate a new set, including the URL parameter for web fonts. In this case, you don’t have to pass the URL parameter to the fonts from the “*Standard fonts*” list.
:::

### User-Added Fonts in Editor

You can let users connect custom fonts directly from the font selector — without leaving the editor. When configured, a **"Connect another font"** option appears in the font family dropdown. Clicking it opens a UI where the user provides font details; the font is then added to the **Custom** category for the current session and immediately applied to the selected element.

There are two ways to enable this:

**Option 1 — `onConnectCustomFont` callback (recommended)**

Works in any integration mode. Pass the callback at initialization — the editor calls it with an `onSave` function when the user clicks the option. Open any UI you choose, collect the font data, and call `onSave`:

```js
onConnectCustomFont: function(onSave) {
  openYourFontModal(function(result) {
    onSave({
      name:         result.displayName,   // shown in the font selector
      value:        result.fontFamily,    // CSS font-family, e.g. "'Roboto', sans-serif"
      link:         result.cssUrl,        // optional: URL to the font stylesheet
      importMethod: result.embedMethod    // optional: 'link' | 'import' | 'fontFace' | 'local'
    });
  });
}
```

The `importMethod` controls how the font is injected into the email `<head>`:

| Value | Injected into \`\<head>\` |
| :---- | :---- |
| link | \<link rel="stylesheet" href="..."> |
| import | \<style>@import url('...');\</style> |
| fontFace | \<style>@font-face { … }\</style> |
| local | nothing — font is assumed to be locally available |

**Option 2 — Extensions SDK (fallback)**

If you are building a plugin-mode integration and prefer not to use the callback, use the [external-custom-font](/extensions/core-concepts#external-custom-font) extension instead. It activates the same "Connect another font" entry point via the Extensions SDK. Note: if `onConnectCustomFont` is also provided, the callback takes priority and the extension is not invoked. No changes to existing extension integrations are required.

This functionality is available in Plugin version **2.21.0** or higher and requires the **Business or Enterprise plan**.

## Display Conditions

Display conditions allow you to change the content of emails displayed to recipients, depending on whether the specified condition on your end is met or not.

Users can set conditions manually in the editor (Local) or select them from a list of predefined conditions set earlier (Predefined).

**Use Cases:**

1. **Personalized Content**: Show different content blocks to different segments of your audience. For example, display a special offer only to female customers or show different products based on user preferences.
2. **Conditional Display**: Include or exclude certain content based on specific conditions, such as geographic location, membership status, or user activity.
3. **Dynamic Marketing Campaigns**: Enhance engagement and relevance by tailoring email content to different user segments.

**Important Considerations:**

* **Editor and Application Responsibilities**: While the editor is responsible for placing the conditional statements into the correct places within the HTML of the email, it is the responsibility of the application (where the plugin is embedded) to correctly handle these statements when it’s time to send the email, according to their business needs.

* **No Language Limitations**: The editor does not have any limitations regarding the language of these statements, so they can be written in any scripting language supported by your application.

::: image-wrap
![](/img/plugin/new/image58.webp){width=1999 height=802}
:::

Now let’s go through the initial process of activating and customizing the Display Conditions for the editor users.

### Activating Display Conditions

To activate Display Conditions during Plugin initialization, include the following parameter:

```js
{
  ...
  "conditionsEnabled": true, // activation of the Display Conditions control in the Editor
  ...
}
```

This activates the Conditions tab in the editor:

::: image-wrap
![](/img/plugin/new/image59.webp){width=1200 height=542}
:::

### Allowing Local Display Conditions Creation

To allow users to create local Display Conditions directly in the editor, you need to enable the custom conditions setting during the Plugin initialization. This provides users with the flexibility to define conditions based on their specific needs without relying solely on predefined conditions.

Add the following setting to your Plugin initialization configuration:

```js
{
  ...
  "conditionsEnabled": true,
  "customConditionsEnabled": true, // enables creating Local Display Conditions inside the Editor
  ...
}
```

Once activated, users will see an option to create custom conditions in the editor:

::: image-wrap
![](/img/plugin/new/image60.webp){width=350 height=548}
:::

### Setting Up Predefined Conditions

If you already have a predefined list of display conditions and want to show them in the editor so that users can simply choose from the available options — you can pass these conditions during the plugin initialization, as shown in the example below.

Example configuration for predefined conditions with categories:

```js
{
  ...
  "conditionCategories": [
    {
      "category": "Gender",
      "conditions": [
        {
          "id": 1,
          "name": "Female",
          "description": "Only female customers will see this part of the email.",
          "beforeScript": "{% if contact.gender == \"Female\" %}",
          "afterScript": "{% endif %}"
        },
        {
          "id": 2,
          "name": "Male",
          "description": "Only male customers will see this part of the email.",
          "beforeScript": "{% if contact.gender == \"Male\" %}",
          "afterScript": "{% endif %}"
        }
      ]
    }
  ],
  ...
}
```

### Parameter Description:

| Parameter    | Description                                                                 |
| :----------- | :-------------------------------------------------------------------------- |
| `category`   | Name of the category                                                        |
| `conditions` | An array of condition details                                               |

**Conditions Details:**

| Parameter      | Description                                                               |
| :------------- | :------------------------------------------------------------------------ |
| `id`           | Unique identifier of the condition                                        |
| `name`         | Name of the condition                                                     |
| `description`  | Description of the condition                                              |
| `beforeScript` | Content to be inserted into the email before the block with the condition |
| `afterScript`  | Content to be inserted into the email after the block with the condition  |

Here is how the predefined conditions will appear in the editor for users to choose from:

::: image-wrap
![](/img/plugin/new/image206.webp){width=1193 height=551}
:::

### Predefined External

If you don't want to (or cannot) pass a predefined array of display conditions and prefer to let users create them manually, there's an alternative approach using external conditions. This method allows you to define an extension that opens a custom modal window when the display condition feature is activated in the editor.
Within your modal, you can present the conditions in any format — even provide a full builder interface to generate them on the fly. Once the user completes their input, the resulting condition code is passed back via a callback and automatically inserted into the email.

* **Documentation**:&#x20;
  <https://plugin.stripo.email/extensions/tutorials/examples/integrations/external-display-conditions>

* **Code example (JavaScript)**:&#x20;
  <https://github.com/stripoinc/stripo-plugin-samples/tree/main/extensions/javascript/external-display-conditions>

* **Code example (TypeScript)**:&#x20;
  <https://github.com/stripoinc/stripo-plugin-samples/tree/main/extensions/typescript/external-display-conditions>

## Link Selector Customization

The Link Selector Customization feature allows you to set up the view of available link protocols independently. If certain protocols are not needed, you can hide them from customers.

**Usage**

To customize the link selector, use the following parameters during the initialization of the plugin:

```js
{
  "hideLinks": ['mail', 'tel', 'https://some.special.link.url'],
  "hideLinksCategories": ['Yespo']
}
```

Where:

* `mail`, `tel` are General protocols.
* `https://some.special.link.url` represents [special links](/editor-configuration/initialization-settings#special-links-configuration) that you have defined in the editor.
* `Yespo` is a category of [special links](/editor-configuration/initialization-settings#special-links-configuration) where it is placed.

After enabling these parameters, the specified protocols will be hidden.

By customizing the link selector, you can streamline the user interface and ensure that only the necessary link protocols are available to your customers, improving their experience and reducing potential confusion

## Event Handling

The `onEvent` parameter is used to define event handlers for various actions within the editor. These events help track user interactions and trigger specific functions in response to those interactions. Below is a list of available events and their descriptions, along with the parameters passed for each event.

**Available Events:**

```js
{state: 'DESKTOP' | 'MOBILE'}
```

```js
{
  target: string
}
```

```js
{
  target: string;
  moduleId: string;
  moduleCategory: {
    key: string | number;
    order: number;
    translatedValue: string;
  }
  syncModule: boolean;
  blockType: string;
}
```

```js
{
  target: string;
  moduleId: string;
  blockType: string;
  moduleCategory: string;
  syncModule: boolean;
}
```

```js
{
  target: string,
  moduleId: string,
  blockType: string,
  moduleCategory: string,
  syncModule: boolean
}
```

```js
{
  moduleId: string;
  moduleCategory: {
    key: string | number;
    order: number;
    translatedValue: string;
  }
  syncModule: boolean;
  blockType: string;
}
```

```js
{
  moduleId: string;
  moduleCategory: {
    key: string | number;
    order: number;
    translatedValue: string;
  }
  syncModule: boolean;
  blockType: string;
}
```

```js
module_copied: {
  copied_from: "stripe",
  moduleId: 1351
}
```

```js
modules_already_deleted: {
  moduleIds: [1, 150, 100500]
}
```

```js
module_detached: {
  moduleId: 153
}
```

```js
module_sync_property_updated: {
  moduleId: 1015,
  sync: true
}
```

```js
module_restored: {
  moduleId: 153
}
```

```js
{
  html: string
}
```

```js
{
  html: string
}
```

```js
{
  html: string
}
```

```js
{blockName: string}
```

```js
{blockName: string}
```

```js
{blockName: string}
```

```js
{blockName: string}
```

```js
{blockName: string}
```

```js
{}
```

`display_condition_applied`

Triggered when a display condition is applied to an element.

```js
{
  conditionCategory: 'custom' | 'predefined' | 'external';
  conditionId: string;
  nodeId: string;
}
```

`display_condition_removed`

Triggered when a display condition is removed from an element — from the condition controls panel as well as from an external display conditions dialog. Use `conditionId` to clean up conditions that are no longer used in the template on your side.

```js
{
  conditionCategory: 'custom' | 'predefined' | 'external';
  conditionId: string;
  nodeId: string;
}
```

**Example Usage:**

```js
{
    "onEvent": function handleEvent(type, params) {
        switch (type) {
            case "editor_view_mode_changed":
                // Handle view mode change
                break;
            case "modules_panel_opened":
                // Handle modules panel opening
                break;
            case "module_dropped":
                // Handle module dropped
                break;
            case "module_saved":
                // Handle module saved
                break;
            case "module_updated":
                // Handle module updated
                break;
            case "module_deleted":
                // Handle module deleted
                break;
            case "module_removed":
                // Handle module removed
                break;
            case "module_copied":
                // Handle module copied from another module
                break;
            case "modules_already_deleted":
                // Handle detection of modules that were already deleted from the Modules Library
                break;
            case "module_detached":
                // Handle detaching a synchronized module from the Modules Library
                break;
            case "module_sync_property_updated":
                // Handle change of the module synchronization state
                break;
            case "module_restored":
                // Handle restoring module content from the Modules Library
                break;
            case "structure_dropped":
                // Handle structure dropped
                break;
            case "structure_deleted":
                // Handle structure deleted
                break;
            case "structure_copied":
                // Handle structure copied
                break;
            case "block_added":
                // Handle block added
                break;
            case "block_dropped":
                // Handle block dropped
                break;
            case "block_copied":
                // Handle block copied
                break;
            case "block_deleted":
                // Handle block deleted
                break;
            case "block_moved":
                // Handle block moved
                break;
            case "email_restored":
                // Handle email restored from version history
                break;
            case "display_condition_applied":
                // Handle display condition applied
                break;
            case "display_condition_removed":
                // Handle display condition removed
                break;
            default:
                console.warn("Unhandled event type:", type);
        }
    },
    ...
}
```

By configuring the `onEvent` parameter, you can effectively monitor and respond to user interactions within the editor, providing valuable insights and enhancing the overall user experience.

## UTM Parameters

The `utm` parameter is used to configure the initial settings for UTM tags in your email templates. These tags are essential for tracking the performance of your email campaigns in analytics platforms.

**Use Case:**

Imagine you are setting up an email marketing campaign and you need to track its performance in Google Analytics. By using UTM tags, you can identify which email brought traffic to your website and how effective it was in terms of conversions. The `utm` parameter allows you to predefine these tags, ensuring that all links in your email carry the necessary tracking information.

::: image-wrap true
![](/img/plugin/new/image19.webp){width=400 height=603}
:::

Here's a detailed description of each parameter and its usage.

**Parameter Description:**

**Example Usage:**

```js
{
  ...,
  "utm": {
    "utmSource": "Yespo",
    "utmMedium": "email",
    "utmCampaign": "Spring_Sale",
    "utmContent": "Banner",
    "utmTerm": "Discount",
    "customUtms": [
      {
        "name": "utmCustom1",
        "value": "someValue"
      }
    ]
  },
  ...
}
```

**Detailed Explanation:**

1. **utmSource:** This parameter identifies the source of the traffic. For example, if your emails are sent through the Yespo platform, you might set `utmSource` to "Yespo".
2. **utmMedium:** This parameter specifies the medium of the campaign. In the case of email campaigns, you would typically set this to "email".
3. **utmCampaign:** This parameter names the campaign. For example, if you are running a Spring Sale, you could set `utmCampaign` to "Spring\_Sale".
4. **utmContent:** This parameter differentiates content within the same ad or campaign. For instance, if you have multiple banners, you could label them individually using `utmContent`.
5. **utmTerm:** This parameter is used for paid search campaigns to capture the keyword term. Even if you are not running paid search campaigns, you can use this field to track specific promotions or discounts, like "Discount".
6. **customUtms:** This array allows you to add additional custom UTM tags that may be specific to your needs. Each custom UTM includes a `name` and a `value`.

**How to Utilize:**

1. **Predefine UTM Tags:** Set the initial values for UTM tags in your email templates using the `utm` parameter. This ensures consistency across all your email campaigns.
2. **Add Custom Tags:** Use the `customUtms` array to include any additional tracking parameters that are unique to your campaign requirements.
3. **Track Campaign Performance:** By embedding these UTM tags in your email links, you can track the effectiveness of your campaigns in your analytics platform, such as Google Analytics. This helps you understand which emails drive the most traffic and conversions, allowing you to optimize future campaigns.

By setting up these UTM tags initially, you ensure that all the necessary tracking information is included in your email links, facilitating comprehensive campaign performance analysis.

## AMP Form Services

The `ampFormServices` parameter is used to predefine backend endpoints available for AMP Form blocks in the editor.

This feature simplifies the setup of AMP forms by allowing users to select a ready-to-use endpoint from a dropdown list instead of manually typing a URL.

It helps maintain consistency, prevents configuration errors, and ensures that form data is sent only to authorized endpoints.

**Use Case**

Imagine your users frequently include AMP forms in their emails — for example, to collect feedback, register event participants, or confirm attendance.

Instead of manually inserting different submission URLs, you can provide them with a list of predefined endpoints.

When they drop an AMP Form block into the template, the settings panel displays those endpoints as selectable options.

::: image-wrap
![](/img/plugin/new/image236.webp){width=1999 height=899}
:::

Selecting a service automatically assigns its URL to the form’s `action-xhr` attribute, ensuring correct data routing.

**Parameter Description**

| Parameter | Description |
| ----- | ----- |
| `ampFormServices` | Defines the list of predefined backend endpoints available for selection in AMP Form block settings. Each service includes a label (visible name) and a value (submission URL). |
| `showExternalAmpFormServices` | Controls whether users can add custom external services manually. If set to `false`, only predefined endpoints from `ampFormServices` will be available. Default: `true`. |

**Example Usage**

```js
{
  ...,
  "ampFormServices": [
    {
      "label": "Feedback form",
      "value": "https://example.com/api/amp/feedback"
    },
    {
      "label": "Event registration",
      "value": "https://example.com/api/amp/register"
    }
  ],
  "showExternalAmpFormServices": false
}
```

In this example:

* Two form services (“Feedback form” and “Event registration”) are predefined.
* The user will see these two options in the dropdown list when configuring the AMP Form block.
* The “Add external service” option will be hidden, ensuring that only approved endpoints are used.

::: image-wrap
![](/img/plugin/new/image237.webp){width=1999 height=980}
:::
