From wix-cli
Use when adding tracking code, advertising pixels, third-party integrations, popups, banners, or client-side JavaScript to sites. Triggers include embed, inject, script, third-party integration, DOM injection, Google Analytics, Facebook Pixel, tracking pixel, chat widget, popup, coupon popup, custom JavaScript, site script.
npx claudepluginhub wix-playground/skills-architecture-test --plugin wix-cliThis skill uses the workspace's default tool permissions.
Creates embedded script extensions for Wix CLI applications. Embedded scripts are HTML code fragments that get injected into the DOM of Wix sites, enabling integration with third-party services, analytics tracking, advertising, and custom JavaScript functionality.
Builds and reviews Wix CLI app extensions: dashboard pages, modals, plugins, Editor React components, backend APIs, events, service plugins, data collections. Prepares apps for App Market review.
Manages inline custom JavaScript on Webflow sites: add scripts (up to 10k chars, no <script> tags), list registered/applied, delete all. For analytics, pixels, chat widgets.
Builds BigCommerce storefront widgets with Handlebars templates, JSON schemas, placements, and Page Builder; injects JS/CSS via Script Manager API.
Share bugs, ideas, or general feedback.
Creates embedded script extensions for Wix CLI applications. Embedded scripts are HTML code fragments that get injected into the DOM of Wix sites, enabling integration with third-party services, analytics tracking, advertising, and custom JavaScript functionality.
Follow these steps in order when creating an embedded script:
src/extensions/site/embedded-scripts/<script-name>/embedded.html with config element, styles, and script logicextensions.ts with extensions.embeddedScript() and unique UUIDsrc/extensions/dashboard/pages/<script-name>-settings/embeddedScripts API from @wix/app-managementsrc/extensions.ts to import and use both extensionsSCOPE.DC-APPS.MANAGE-EMBEDDED-SCRIPTS permission in the Wix Dev Center (see Enable Embedded Script Permission)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 | Description | Best For |
|---|---|---|
HEAD | Between <head> and </head> tags | Analytics, early initialization |
BODY_START | Immediately after opening <body> tag | Critical functionality, noscript |
BODY_END | Immediately before closing </body> tag | Non-blocking scripts, performance |
Selection guidelines:
HEAD (initialize early)BODY_END (non-blocking)HEAD or BODY_STARTBODY_END (better performance)Every embedded script requires a companion dashboard page to configure its parameters. Site owners use the dashboard page UI to set values, which are then passed to the embedded script as template variables.
Dashboard Page (React UI)
│
│ embeddedScripts.embedScript({ parameters: {...} })
▼
Wix App Management API
│
│ Stores parameters, injects as template variables
▼
Embedded Script (HTML)
│
│ {{parameterKey}} → actual value
▼
Site DOM
Related skill: Use wix-cli-dashboard-page to create the configuration UI for your embedded script.
| 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 |
Embedded scripts support parameterization using template variable syntax {{variableName}}. These parameters are configured through the dashboard and passed as template variables that should be used in your HTML/JavaScript code.
Usage Instructions:
Template Variable Syntax:
{{parameterKey}} syntax to insert parameter values into your HTMLHTML Attributes (REQUIRED):
<div id="config" data-headline="{{headline}}" data-text="{{text}}"></div>JavaScript Access:
getAttribute() or the dataset propertyconst config = document.getElementById("config");
const headline = config?.getAttribute("data-headline");
// OR using dataset:
const { headline, text } = config.dataset;
Type Safety:
Number() or parseInt()'true' or 'false' stringsnew Date()Required vs Optional:
Relevant Parameter Usage:
Example Patterns:
Pattern 1 - Configuration in Data Attributes:
<div
id="script-config"
data-api-key="{{apiKey}}"
data-enabled="{{enabled}}"
data-color="{{primaryColor}}"
></div>
<script>
const config = document.getElementById("script-config");
const apiKey = config.getAttribute("data-api-key");
const enabled = config.getAttribute("data-enabled") === "true";
const color = config.getAttribute("data-color");
if (enabled && apiKey) {
// Initialize with configuration
}
</script>
Pattern 2 - Using dataset Property:
<div
id="script-config"
data-headline="{{headline}}"
data-message="{{message}}"
data-image-url="{{imageUrl}}"
></div>
<script>
const config = document.getElementById("script-config");
const { headline, message, imageUrl } = config.dataset;
// Use the variables in your script logic
if (headline) {
document.querySelector("#headline").textContent = headline;
}
</script>
Pattern 3 - Conditional Logic:
<div
id="config"
data-mode="{{activationMode}}"
data-start="{{startDate}}"
data-end="{{endDate}}"
></div>
<script>
const config = document.getElementById("config");
const mode = config.getAttribute("data-mode");
if (mode === "timed") {
const startDate = new Date(config.getAttribute("data-start"));
const endDate = new Date(config.getAttribute("data-end"));
const now = new Date();
if (now >= startDate && now <= endDate) {
// Show content
}
} else if (mode === "active") {
// Show content immediately
}
</script>
Validation Requirements:
{{parameterKey}} must match the exact key names from the parameter definitionsEvery 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 |
A complete embedded script implementation requires two parts:
src/extensions/site/embedded-scripts/
└── {script-name}/
├── embedded.html # HTML/JavaScript code to inject
└── extensions.ts # Metadata (scriptType, placement)
src/extensions/dashboard/
├── withProviders.tsx # WDS provider wrapper (required)
└── pages/
└── {script-name}-settings/
├── extensions.ts # Extension registration (REQUIRED)
└── page.tsx # Configuration UI using embeddedScripts API
Note: The dashboard page requires its own extensions.ts file. Without this file, the dashboard page will not appear in the Wix dashboard.
WARNING: The dashboard page uses DIFFERENT field names than embedded scripts:
title, routePath, componentname, source, placement, scriptTypeDo NOT apply embedded script field names to dashboard page registrations.
See wix-cli-dashboard-page skill for dashboard page implementation details and the extension registration pattern.
<!-- Configuration element with template variables -->
<div id="my-config" data-api-key="{{apiKey}}" data-enabled="{{enabled}}"></div>
<!-- Container for dynamic content -->
<div id="my-container"></div>
<style>
/* Scoped styles for the embedded content */
#my-container {
/* styles */
}
</style>
<script type="module">
// Get configuration from data attributes
const config = document.getElementById("my-config");
if (!config) throw new Error("Config element not found");
const { apiKey, enabled } = config.dataset;
// Exit early if disabled (use throw at module scope, not return)
if (enabled !== "true") {
throw new Error("Script disabled");
}
// Implement functionality in a named function (return is allowed here)
async function initialize() {
try {
// Your implementation
} catch (error) {
console.error("Script error:", error);
}
}
// Initialize when DOM is ready
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initialize);
} else {
initialize();
}
</script>
Request: "Add Google Analytics tracking to my site"
Output:
ANALYTICSHEAD{{trackingId}}Request: "Create a coupon popup that shows when cart value exceeds $50"
Output:
FUNCTIONALBODY_END{{couponCode}}, {{minimumCartValue}}, {{enablePopup}}Request: "Integrate Intercom chat widget"
Output:
FUNCTIONALBODY_END{{appId}}, {{userEmail}}, {{userName}}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.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
embedded.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>
wix-cli-dashboard-page skill)Uses embeddedScripts API from @wix/app-management:
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
},
});
Extension registration is MANDATORY and has TWO required steps.
Each embedded script requires an extensions.ts file in its folder:
import { extensions } from "@wix/astro/builders";
export const embeddedscriptMyScript = extensions.embeddedScript({
id: "{{GENERATE_UUID}}",
name: "My Script",
source: "./extensions/site/embedded-scripts/my-script/embedded.html",
placement: "BODY_END",
scriptType: "FUNCTIONAL",
});
CRITICAL: UUID Generation
The id must be a unique, static UUID v4 string. Generate a fresh UUID for each extension - do NOT use randomUUID() or copy UUIDs from examples. Replace {{GENERATE_UUID}} with a freshly generated UUID like "a1b2c3d4-e5f6-7890-abcd-ef1234567890".
| Property | Type | Description |
|---|---|---|
id | string | Unique static UUID v4 (generate fresh) |
name | string | Display name for the script |
source | string | Relative path to the HTML file |
placement | enum | HEAD, BODY_START, or BODY_END |
scriptType | enum | ESSENTIAL, FUNCTIONAL, ANALYTICS, ADVERTISING |
CRITICAL: After creating the script-specific extension file, you MUST read wix-cli-extension-registration and follow the "App Registration" section to update src/extensions.ts.
Without completing Step 2, the embedded script will not be deployed to the site.
After implementation, the app developer must manually enable the embedded script permission:
{app-id} with your actual app ID)SCOPE.DC-APPS.MANAGE-EMBEDDED-SCRIPTS permissionNote: This is a manual step in the Wix Dev Center. Without this permission, embedded scripts will not function on the site.