HEX
Server: Apache/2.4.46 (Win64) OpenSSL/1.1.1j PHP/8.4.25
System: Windows NT DESKTOP-4TAV2RJ 10.0 build 19045 (Windows 10) AMD64
User: fred (0)
PHP: 8.4.25
Disabled: NONE
Upload Files
File: C:/Users/fred/.codex/.tmp/plugins/plugins/wix/skills/wix-app/references/EMBEDDED_SCRIPT.md
# Wix Embedded Script Builder

Embedded scripts are HTML code fragments injected into the DOM of Wix sites — for integration with third-party services, analytics tracking, advertising, and custom JavaScript functionality.

## Scaffold

Use `wix generate --params` with all 5 required fields:

```bash
wix generate --params '{"extensionType":"EMBEDDED_SCRIPT","name":"<name>","folder":"<folder>","scriptType":"<scriptType>","placement":"<placement>"}'
```

| Field | Constraint |
| --- | --- |
| `name` | Display name, any string. |
| `folder` | Lowercase alphanumeric, hyphens, slashes (for sub-paths). |
| `scriptType` | One of: `ESSENTIAL`, `FUNCTIONAL`, `ANALYTICS`, `ADVERTISING`. |
| `placement` | One of: `HEAD`, `BODY_START`, `BODY_END`. |

The CLI generates the folder, `<folder>.html` (the actual script HTML), the builder file, the UUID, and the `src/extensions.ts` registration. (It may also drop a sample `<other>.ts` module to demonstrate `<script type="module" src="./xxx.ts">` imports — feel free to delete or repurpose it.)

After implementation, the app developer must enable `SCOPE.DC-APPS.MANAGE-EMBEDDED-SCRIPTS` in the Wix Dev Center — see [Enable Embedded Script Permission](#enable-embedded-script-permission).

## Script Types

Embedded scripts must declare a type for consent management:

| Type          | Description                                      | Use Cases                               |
| ------------- | ------------------------------------------------ | --------------------------------------- |
| `ESSENTIAL`   | Core functionality crucial to site operation     | Authentication, security features       |
| `FUNCTIONAL`  | Remembers user choices to improve experience     | Language preferences, UI customization  |
| `ANALYTICS`   | Provides statistics on how visitors use the site | Google Analytics, Hotjar, Mixpanel      |
| `ADVERTISING` | Provides visitor data for marketing purposes     | Facebook Pixel, Google Ads, retargeting |

**Selection rule:** If a script falls into multiple types, choose the option closest to the bottom of the list (most restrictive). For example, a script with both Analytics and Advertising aspects should be typed as `ADVERTISING`.

## Placement Options

| Placement    | Where in HTML                            | Best for                                                                |
| ------------ | ---------------------------------------- | ----------------------------------------------------------------------- |
| `HEAD`       | Between `<head>` and `</head>` tags      | Analytics, tracking, early initialization                               |
| `BODY_START` | Immediately after opening `<body>` tag   | Critical functionality, `<noscript>` fallback                           |
| `BODY_END`   | Immediately before closing `</body>` tag | Advertising pixels, non-critical features (non-blocking, better perf)   |

## Dynamic Parameters and Dashboard Configuration

**Every embedded script requires a companion dashboard page** to configure its parameters. Scaffold a separate `DASHBOARD_PAGE` extension and use `embeddedScripts` from `@wix/app-management` to load/save parameters (see [DASHBOARD_PAGE.md](DASHBOARD_PAGE.md)). Wix stores the parameters and injects them as `{{templateVars}}` into the HTML at render time.

### Parameter Types

| Type       | Description              | Dashboard Component    |
| ---------- | ------------------------ | ---------------------- |
| `TEXT`     | Single-line text         | Input                  |
| `NUMBER`   | Numeric value            | Input type="number"    |
| `BOOLEAN`  | True/false toggle        | ToggleSwitch, Checkbox |
| `IMAGE`    | Image from media manager | ImagePicker            |
| `DATE`     | Date only                | DatePicker             |
| `DATETIME` | Date with time           | DatePicker + TimeInput |
| `URL`      | URL with validation      | Input                  |
| `SELECT`   | Dropdown options         | Dropdown               |
| `COLOR`    | Color value              | ColorPicker            |

### Template Variable Syntax

`{{parameterKey}}` placeholders are substituted at injection time, **but only inside HTML attribute values** — not inside `<script>` bodies. The required pattern is: render every parameter as a data attribute on a config element, then read it from `dataset` in JS.

```html
<div id="config"
  data-api-key="{{apiKey}}"
  data-enabled="{{enabled}}"
  data-headline="{{headline}}"
></div>
<script>
  const { apiKey, enabled, headline } = document.getElementById("config").dataset;
  // ...
</script>
```

**Type handling (all `dataset` values are strings):**
- `NUMBER` → `Number(value)` or `parseInt(value, 10)`
- `BOOLEAN` → compare against `"true"` / `"false"`
- `DATE` / `DATETIME` → `new Date(value)`

**Other rules:**
- Template variable names must match the parameter keys exactly.
- Required parameters always have values; optional parameters may be empty — provide fallbacks.
- Only use parameters that are relevant to the use case; don't reference parameters you don't implement.

### Common Parameters

Every embedded script should have at minimum an **enable/disable toggle** parameter:

| Parameter    | Type      | Purpose                              |
| ------------ | --------- | ------------------------------------ |
| `enabled`    | `BOOLEAN` | Allow site owner to activate/disable |
| `apiKey`     | `TEXT`    | Third-party service credentials      |
| `trackingId` | `TEXT`    | Analytics/pixel identifiers          |
| `headline`   | `TEXT`    | Customizable display text            |
| `color`      | `COLOR`   | UI customization                     |

## Module-script Rules

The `<script type="module">` block runs at module scope, where Rollup (used by Astro) **disallows `return` statements**.

- Use `throw new Error(...)` for early exits at module scope (e.g., "script disabled" / "config element not found").
- Wrap the main logic in a named `async function` and call it from a `DOMContentLoaded` listener (or directly if `document.readyState !== "loading"`); `return` is valid inside the function.

See the [Complete Example](#complete-example-coupon-popup) below for the full skeleton.

## Examples

### Analytics Tracking

**Request:** "Add Google Analytics tracking to my site"

**Output:**

- Script type: `ANALYTICS`
- Placement: `HEAD`
- Template variables: `{{trackingId}}`
- Implements: gtag.js initialization, page view tracking

### Popup/Modal

**Request:** "Create a coupon popup that shows when cart value exceeds $50"

**Output:**

- Script type: `FUNCTIONAL`
- Placement: `BODY_END`
- Template variables: `{{couponCode}}`, `{{minimumCartValue}}`, `{{enablePopup}}`
- Implements: Cart value detection, popup display logic, localStorage for "don't show again"

### Third-Party Chat Widget

**Request:** "Integrate Intercom chat widget"

**Output:**

- Script type: `FUNCTIONAL`
- Placement: `BODY_END`
- Template variables: `{{appId}}`, `{{userEmail}}`, `{{userName}}`
- Implements: Intercom SDK initialization, user identification

## Best Practices

- **Always create a dashboard page:** Every embedded script needs a configuration UI
- **Include enable/disable toggle:** Let site owners control activation without removing the script
- **Performance:** Minimize impact - scripts should be lightweight and non-blocking
- **Security:** Avoid inline event handlers, validate data, escape user input
- **Error handling:** Fail silently when appropriate - don't break the site
- **Module scope early exits:** Use `throw new Error()` for early exits at module scope, not `return`. Rollup (used by Astro) doesn't allow `return` statements at module scope. Wrap main logic in a named async function where `return` is valid.
- **Type conversions:** Parameters are always strings - convert in JavaScript as needed
- **API calls:** Only create fetch() calls to /api/\* endpoints that exist in the API spec
- **Scoping:** Prefix CSS classes and IDs to avoid conflicts with site styles
- **Cleanup:** Remove event listeners and intervals when appropriate

## Complete Example: Coupon Popup

### 1. Define Parameters

```
Parameters for "cart-coupon-popup":
- couponCode (TEXT, required) - The coupon code to display
- popupHeadline (TEXT, required) - Headline text
- popupDescription (TEXT, required) - Description text
- minimumCartValue (NUMBER) - Minimum cart value to show popup
- enablePopup (BOOLEAN, required) - Enable/disable toggle
```

### 2. Embedded Script (`<folder>.html`)

```html
<div
  id="popup-config"
  data-coupon-code="{{couponCode}}"
  data-popup-headline="{{popupHeadline}}"
  data-minimum-cart-value="{{minimumCartValue}}"
  data-enable-popup="{{enablePopup}}"
></div>
<div id="popup-container"></div>

<script type="module">
  // Get configuration from data attributes
  const config = document.getElementById("popup-config");
  if (!config) throw new Error("Config element not found");

  const { couponCode, popupHeadline, minimumCartValue, enablePopup } =
    config.dataset;

  // Exit early if disabled (use throw at module scope, not return)
  if (enablePopup !== "true") {
    throw new Error("Popup disabled");
  }

  // Main logic in a function (return is allowed here)
  async function initializePopup() {
    const minValue = Number(minimumCartValue) || 0;
    // ... popup implementation
  }

  // Initialize when DOM is ready
  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initializePopup);
  } else {
    initializePopup();
  }
</script>
```

### 3. Dashboard Page (See the DASHBOARD_PAGE.md reference)

Uses `embeddedScripts` API from `@wix/app-management`:

```typescript
import { embeddedScripts } from "@wix/app-management";

// Load parameters
const script = await embeddedScripts.getEmbeddedScript();
const params = script.parameters; // { couponCode: "...", ... }

// Save parameters (all values must be strings)
await embeddedScripts.embedScript({
  parameters: {
    couponCode: "SAVE20",
    minimumCartValue: "50", // Number as string
    enablePopup: "true", // Boolean as string
  },
});
```

## Enable Embedded Script Permission

After implementation, the app developer must manually enable the embedded script permission:

1. Go to [https://manage.wix.com/apps/{app-id}/dev-center-permissions](https://manage.wix.com/apps/{app-id}/dev-center-permissions) (replace `{app-id}` with your actual app ID)
2. Add the `SCOPE.DC-APPS.MANAGE-EMBEDDED-SCRIPTS` permission
3. Save the changes

**Note:** This is a manual step in the Wix Dev Center. Without this permission, embedded scripts will not function on the site.