npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lacneu/wix-openclaw

v0.6.1

Published

Wix REST API plugin for OpenClaw — manage blog, CMS data, forms, bookings, contacts, events, FAQ on a single Wix site with site_id whitelist and approval gating on destructive ops

Readme

wix-openclaw-plugin

Wix REST API plugin for OpenClaw Manage blog, CMS data, forms, bookings, contacts, events, FAQ on a single Wix site — with site_id whitelist and approval gating on every destructive operation.

License: MIT OpenClaw npm version Plugin version


Overview

wix-openclaw is an OpenClaw plugin that lets your agent operate a Wix site through the official Wix REST API. It registers 50 tools by default across a dozen Wix products (Blog, CMS Data, Forms, Bookings, Contacts, Events, Reviews, FAQ, Multilingual, Sites, Site Media), plus a wix_design_brief helper that turns loose textual briefs into structured markdown artefacts. Three families are opt-in and add to that: SEO (enableSeoTools, 19 tools), accessibility (enableAccessibilityTools, 6 tools) and analytics (enableAnalyticsTools, 4 tools) — 79 with all three.

Every tool funnels through a single authenticated HTTP client that:

  1. Injects the correct headers (Authorization, wix-account-id, wix-site-id)
  2. Refuses any call to a site UUID not in allowedSiteIds — before the network round trip
  3. Retries on 429/5xx with exponential backoff
  4. Maps non-retryable errors to clean tool failures (WixApiError)

Destructive operations (publish, delete, cancel, moderate) trigger a before_tool_call approval prompt that the operator must accept in the Control UI / Telegram before the call goes through.


Why a whitelist?

Wix accounts can host many sites. The wix-site-id header is the only thing between an agent and "we just published a draft on the wrong site".

allowedSiteIds is enforced in the client itself, before any HTTP request is built. If the LLM hallucinates a site UUID, the call fails locally — no traffic is generated and no Wix logs are polluted. This is the same reason google_workspace enforces a domain allowlist: prompt injection should never reach the wrong tenant.


Installation

Requirements

  • OpenClaw >= v2026.4.0
  • A Wix REST API key with the minimum required permissions (see Wix API Key permissions below)
  • The Wix account UUID and at least one site UUID

Install via OpenClaw CLI

openclaw plugins install @lacneu/wix-openclaw
openclaw plugins inspect @lacneu/wix-openclaw

Configuration

Add the entry to your openclaw.json:

{
  "plugins": {
    "allow": ["wix-openclaw", "openclaw-knowledge", "telegram"],
    "entries": {
      "wix-openclaw": {
        "enabled": true,
        "config": {
          "apiKey": "${WIX_API_KEY}",
          "accountId": "${WIX_ACCOUNT_ID}",
          "allowedSiteIds": ["${WIX_SITE_ID_ATARAXIS}"],
          "defaultSiteId": "${WIX_SITE_ID_ATARAXIS}",
          "logLevel": "info"
        }
      }
    }
  }
}

Add the secrets to your .env:

WIX_API_KEY=<your-wix-api-key>
WIX_ACCOUNT_ID=<your-wix-account-uuid>
WIX_SITE_ID_ATARAXIS=<your-target-site-uuid>

Restart the gateway:

openclaw gateway restart

Configuration reference

| Field | Type | Default | Description | |---|---|---|---| | enabled | boolean | true | Master switch — disables all wix_* tools when false | | apiKey | string | — | Wix REST API key. Sent raw in Authorization (no Bearer prefix). Supports ${ENV_VAR} | | accountId | string | — | Wix account UUID. Sent as wix-account-id. Supports ${ENV_VAR} | | allowedSiteIds | string[] | [] | Whitelist of Wix site UUIDs. Calls to other sites are rejected before the network round trip | | defaultSiteId | string | first of allowedSiteIds | Site UUID injected when a tool does not explicitly specify one | | approvalRequired | string[] | (every destructive tool) | Tool names that trigger a before_tool_call approval prompt | | logLevel | enum | info | debug / info / warn / error. debug logs request bodies (mind PII) |


Authentication header convention

Wix REST APIs use a slightly non-standard auth pattern: the API key goes raw in the Authorization header — without the Bearer prefix.

Authorization: <wix-api-key>
wix-account-id: <wix-account-uuid>
wix-site-id: <wix-site-uuid>

This plugin handles that for you; you only need to provide the three values.


Wix API Key permissions

A Wix REST API key has account-wide reach by design — it can target any of the sites under the Wix account it belongs to. Wix does not let you scope a key to a single site at creation time. The plugin compensates with its allowedSiteIds whitelist (cf. Why a whitelist?), but the API key permission set itself remains your most important defense against accidental — or malicious — over-reach. Treat it as a least-privilege configuration exercise.

Where to configure them Wix Dashboard → Settings → Headless Settings → API Keys → click your key → Edit API Key → Permissions.

Minimum required (for the V1 toolset shipped here)

Tick only the following permissions on your API key. Everything else should stay unticked.

Basic permissions

  • [x] Get Sites List — required to discover and validate site UUIDs

Site permissions

  • [x] Wix Blog — drafts, posts, categories, tags
  • [x] Manage Site Media — upload images for blog cover & rich content
  • [x] Business Info — name, address, hours, timezone
  • [x] Wix Data — custom CMS collections (read & write)
  • [x] Wix Forms — read submitted forms
  • [x] Manage Form Submissions — read leads / contact requests
  • [x] Wix Contacts & Members — CRM contacts + members
  • [x] Wix Bookings — services, sessions, bookings
  • [x] Wix Events — events, RSVPs, guests
  • [x] Wix Reviews — list & moderate reviews
  • [x] Manage FAQ — FAQ categories and questions
  • [x] Multilingual Translation Schema Read — read site translations
  • [x] List Marketing Tags — read-only marketing/analytics tags

Optional, depending on the business model

Tick these only if the corresponding Wix product is actually in use on the target site:

  • [ ] Manage SEO (SCOPE.PROMOTE.MANAGE-SEO) — only if you set enableSeoTools: true, which registers nineteen tools of which eleven write irreversibly (four on redirects, seven on tags and patterns; a pattern write re-renders every page of its type). In the default configuration the SEO tools are not registered at all, so granting this scope would hand the key the power to delete redirects for tools that cannot run. Wix exposes a single SEO scope, not a read/write pair: ticking it grants redirect creation and deletion along with the read-only audit, so there is no such thing as an audit-only SEO key. In the Wix UI the checkbox sits under All site permissions, between Social Posts and Import orders; its label is currently untranslated and renders literally as site.scope.SCOPE.PROMOTE.MANAGE-SEO.name. Since Wix cannot narrow it, the read/write boundary is enforced by this plugin instead — each of the eleven writing tools refuses until what it would destroy, be it a redirect, a tag or a template, has been named and acknowledged.

  • [ ] Manage Accessibility Scans — the name Wix uses in its own agent documentation, and the only name available: the scope identifier is not published, the method reference pages return 404, and the whole docs dump contains no accessibility scope. On a permissions page inspected on 2026-08-30 (166 scopes) there was no accessibility permission at all — so there may be nothing to tick yet, this API being in Developer Preview. Needed only if you set enableAccessibilityTools: true, which registers six tools. None of them writes to the site: Wix runs the scan, the plugin reads the result. Note that reading page collections or past results does not prove the key may start a scan: Wix states that starting one needs this permission specifically, and answers 403 / PERMISSION_DENIED otherwise — which the tools surface as a permission problem, never as an empty site.

  • [ ] Wix Analytics — "Can view all site analytics and statistics." That is the checkbox to tick; in the permissions UI it carries the identifier SCOPE.MEDIA.VIEW-SITE-ANALYTICS. Note the mismatch: the API reference names the scope SCOPE.DC-ANALYTICS-AND-REPORTS.READ-SITE-ANALYTICS, which does not appear on the permissions page — searching for it there finds nothing. Ticking Wix Analytics is what makes the calls work; verified against a live site on 2026-08-30. Grant it only if you set enableAnalyticsTools: true, which registers four read-only tools. The reference names its own scope on all four methods (ListSemanticModels, GetSemanticModel, QuerySemanticModelData and GetAnalyticsData), so one permission covers the whole family and grants nothing but reading. Note what NO_ACCOUNT_IDENTITY does and does not mean: the reference classifies it as HTTP 401 / UNAUTHENTICATED — "the caller isn't authenticated" — so it points at the credentials, not at this scope, and it is never evidence of a site with no traffic. The separate SCOPE.DC-ANALYTICS-AND-REPORTS.MANAGE-SESSIONS scope covers the Sessions API, which this plugin deliberately does not expose.

  • [ ] Pricing Plans — if you sell subscription packages

  • [ ] Wix Stores + Wix eCommerce — if you sell physical/digital products. Without these, the wix_* tools that touch e-commerce resources (none in V1) cannot run.

Permissions to never tick (defense in depth)

The plugin does not need any of the following, and granting them needlessly amplifies the blast radius if the key ever leaks. Audit your key periodically and keep these unticked:

| Permission | Why it's dangerous | |---|---| | Manage Sites | Allows site deletion | | Manage Domains | Allows transferring your domain away | | Publish Metasite | Allows un-publishing the entire site | | Manage Embedded Scripts | Allows arbitrary JavaScript injection on every page | | OAuth Apps | Allows creating persistent OAuth apps that survive key revocation | | Manage Functions / Manage Your App | Arbitrary server-side code | | Connect Wix Payments Account / Wix Payments / Wix Cashier | Reroutes customer payments | | Manage Email Marketing / Manage Email Subscriptions | Mass-email spam & subscription tampering | | Server Sign On for Members | Lets the holder impersonate any member | | Manage Roles / Manage Site Members | Account take-over | | Wix CLI - Git Integration | Modify deployed code | | Multilingual Translation Schema Write | Tamper with on-site copy across languages | | Manage Notifications | Push spam to members | | Invoke AI Models | Bills your account for arbitrary LLM usage | | Manage Wixel Projects / Manage Site Branches | Layout/structure mutation | | Any All account permissions master toggle | Unties every account-wide capability above |

Mapping: tool group → required permission

Use this table to figure out which permission a given group of tools relies on. If you want a slimmer key (e.g. blog-only first), drop entire columns and remove the matching tools from your agent's allow-list.

| Tool group | Wix permission | Required if you use… | |---|---|---| | wix_sites_list, wix_site_url_get | Get Sites List | Always (used internally — wix_site_url_get reads viewUrl from the Site object, no separate "Read Site URLs" permission needed) | | wix_business_info_get | Business Info | wix_business_info_get | | wix_blog_* | Wix Blog | Any blog tool | | wix_media_* | Manage Site Media | Any media tool, and rich-content blog drafts | | wix_data_* | Wix Data | Any CMS collection tool | | wix_forms_* | Wix Forms + Manage Form Submissions | Lead reading | | wix_contacts_* | Wix Contacts & Members | CRM tooling | | wix_bookings_* | Wix Bookings | Booking tooling | | wix_events_* | Wix Events | Event tooling | | wix_reviews_* | Wix Reviews | Reviews moderation | | wix_faq_* | Manage FAQ | FAQ tooling | | wix_multilingual_* | Multilingual Translation Schema Read | Translation reads | | wix_seo_* (all nineteen) | Manage SEO (SCOPE.PROMOTE.MANAGE-SEO) | SEO audit and redirect changes — Wix has no read-only SEO scope, so this one permission covers both | | wix_a11y_* (all six) | Manage Accessibility Scans — not offered on the permissions page as of 2026-08-30, and no identifier is published | Starting a scan. Until Wix exposes the grant, this family cannot be enabled | | wix_analytics_* (all four) | Wix Analytics in the UI (SCOPE.MEDIA.VIEW-SITE-ANALYTICS); the reference calls it SCOPE.DC-ANALYTICS-AND-REPORTS.READ-SITE-ANALYTICS, which is not what the permissions page shows | Reading analytics. NO_ACCOUNT_IDENTITY is a 401 about the credentials, not about this scope — and never an empty site | | wix_design_brief | (none — no API call) | Always |

Wix app installation requirements

Some Wix REST endpoints only exist when the corresponding Wix app is installed on the target site. The plugin ships them all generically — they will simply return a clean error when the app is missing, and start working as soon as the app is installed (no plugin upgrade needed).

| Tool group | Wix app required | Error returned when missing | |---|---|---| | wix_blog_* | Wix Blog | 404 | | wix_data_* | Wix CMS (Velo / Wix Code — enable in Editor) | 400 WDE0110: Wix CMS app is not installed for site | | wix_forms_* | Wix Forms | 404 | | wix_bookings_* | Wix Bookings | 404 | | wix_events_* | Wix Events | 428 WIX_EVENTS_APP_NOT_INSTALLED | | wix_reviews_* | Wix Reviews | 428 APP_NOT_INSTALLED | | wix_faq_* | Wix FAQ | 400 App is not installed | | wix_multilingual_* | Wix Multilingual | 403 | | wix_contacts_*, wix_media_*, wix_sites_list, wix_site_url_get, wix_business_info_get | (always available) | — |

To install a Wix app on your site: Wix Dashboard → App Market → search for the app → Add to Site. It is free in most cases and takes effect immediately for API calls.

Rotating the key

Wix keys can be revoked at any time from the same API Keys page. If a key leaks, or if you need to ship a temporary smoke-test key with narrower scope:

  1. Generate a new key with the desired scope.
  2. Update WIX_API_KEY in your environment.
  3. Restart the OpenClaw gateway.
  4. Revoke the old key.

The plugin reads the key on each request through the resolved config — no in-memory caching beyond the gateway lifecycle, so a restart fully flushes the previous credential.


Wix query envelope

Every POST /query tool (wix_contacts_query, wix_bookings_*_list, wix_forms_list_submissions, wix_events_*, wix_reviews_list, wix_multilingual_list_languages, wix_sites_list, wix_data_query_items) accepts the standard Wix Query Language envelope as plain optional parameters:

{
  // Optional — MongoDB-style filter, e.g.
  //   { "status": { "$in": ["ACTIVE", "PENDING"] } }
  //   { "$and": [{ "createdDate": { "$gt": "2026-01-01T00:00:00Z" } },
  //              { "info.emails.email": { "$contains": "acme" } }] }
  "filter": { /* ... */ },

  // Optional — sort entries applied in order
  "sort": [{ "fieldName": "createdDate", "order": "DESC" }],

  // Optional — offset paging (most endpoints)
  "paging": { "limit": 50, "offset": 0 },

  // Optional — cursor paging (Site Media, some Bookings, ...)
  "cursorPaging": { "limit": 50, "cursor": "<opaque>" },

  // Optional — projection
  "fields": ["id", "info.name"]
}

Supported operators (per the Wix Query Language docs): $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $exists, $startsWith, $contains, $hasSome, $hasAll, $matches, $and, $or, $not.

Live verification scope The plugin's smoke test currently exercises $eq, $in, $exists, field equality, sort entries, offset paging, and free-text search against the Ataraxis site. Other operators ($ne, $gt, $gte, $lt, $lte, $nin, $startsWith, $contains, $hasSome, $hasAll, $matches, $or, $not) and cursorPaging / fields projection are exposed structurally and routed to the body by the mapper, but per-operator live coverage on every endpoint is not in v0.2.0's scope. Each Wix endpoint individually decides which fields are filterable and which operators are accepted — Wix returns a clean 400 UNSUPPORTED_QUERY_FILTER when it disagrees, surfaced as a tool failure to the model.

Tools that have ergonomic shortcuts (e.g. wix_blog_list_drafts.status, wix_forms_list_submissions.namespace) always merge the shortcut into the filter via $and, so the agent can never silently override the shortcut by passing a competing filter.

Flat GET endpoints (wix_blog_list_drafts, wix_blog_list_published, wix_blog_list_categories, wix_blog_list_tags, wix_data_list_collections, wix_faq_list_*, wix_media_list, wix_multilingual_list_schemas) accept named query string params plus paging.{limit,offset,cursor} — they do NOT support the operator passthrough above. Each tool's parameters are documented in its description.


Tools

The Validated column reflects v0.2.0 verification on the Ataraxis Coaching site: live means hit by the smoke-test against a real Wix site; app-not-installed and velo-not-enabled mean the tool's endpoint exists but its backing Wix product is not active on the smoke-test site (the request still reaches Wix and the path/headers are correct); docs means write/destructive endpoints that we do not exercise live. The SEO reads are skipped by the smoke test unless WIX_SMOKE_SEO=1 is set, so a key without SCOPE.PROMOTE.MANAGE-SEO is not failed for lacking a scope the default configuration never uses.

Blog

| Tool | What it does | Approval | Validated | |---|---|---|---| | wix_blog_list_drafts | List drafts; supports status (UNPUBLISHED \| PUBLISHED \| SCHEDULED \| IN_REVIEW \| ALL), sort, fieldsets, paging | — | live | | wix_blog_get_draft | Fetch a draft by id; supports fieldsets | — | live | | wix_blog_create_draft | Create a new draft | — | docs | | wix_blog_update_draft | Patch a draft | — | docs | | wix_blog_publish_draft | Publish a draft | required | docs | | wix_blog_list_published | List published posts; supports sort, featured, language, tagIds, categoryIds, fieldsets, paging | — | live | | wix_blog_get_post | Fetch a published post; supports fieldsets | — | live | | wix_blog_unpublish | Move post to trash (reversible) | required | docs | | wix_blog_delete_draft | Permanently delete a draft | required | docs | | wix_blog_list_categories | List blog categories; supports language, paging | — | live | | wix_blog_list_tags | List blog tags; supports language, paging | — | live |

Media

| Tool | What it does | Approval | Validated | |---|---|---|---| | wix_media_upload | Import image into Site Media by URL | — | docs | | wix_media_list | List files; supports parentFolderId, mediaTypes (IMAGE/VIDEO/AUDIO/DOCUMENT/ARCHIVE), cursor paging via paging.cursor | — | live |

The wix_media_upload tool returns the Wix file metadata, including the id. Pass that id back into wix_blog_create_draft as coverMedia.imageId or embed it into a Ricos rich-content node — see the tool description for the contract the LLM should follow.

Site

| Tool | What it does | Approval | Validated | |---|---|---|---| | wix_sites_list | List sites under the account (account-scoped); accepts the standard Wix query envelope | — | live | | wix_site_url_get | Get published URL of a site | — | live | | wix_business_info_get | Read business info (name, address, hours) | — | live |

CMS Data

Requires Velo / Wix Code to be enabled on the target site (Wix Editor → Velo → Enable Code). Without it, calls return HTTP 400 WDE0110: Wix Code not enabled.

| Tool | What it does | Approval | Validated | |---|---|---|---| | wix_data_list_collections | List CMS collections + schemas | — | velo-not-enabled | | wix_data_query_items | Full Wix query envelope on a collection | — | velo-not-enabled | | wix_data_get_item | Fetch one item by id | — | velo-not-enabled | | wix_data_insert_item | Insert a new item | — | docs | | wix_data_update_item | Update an item | — | docs | | wix_data_remove_item | Delete an item | required | docs |

Forms

| Tool | What it does | Approval | Validated | |---|---|---|---| | wix_forms_list_submissions | Full Wix query envelope; namespace defaults to wix.form_app.form and is always $and-merged with passthrough filter | — | live | | wix_forms_get_submission | Fetch a single submission | — | docs |

Contacts

| Tool | What it does | Approval | Validated | |---|---|---|---| | wix_contacts_query | Full Wix query envelope + free-text search | — | live | | wix_contacts_get | Get one contact | — | docs | | wix_contacts_create | Create a contact | — | docs | | wix_contacts_update | Update a contact | — | docs | | wix_contacts_label_add | Add labels to a contact | — | docs | | wix_contacts_delete | Delete a contact | required | docs |

Bookings

| Tool | What it does | Approval | Validated | |---|---|---|---| | wix_bookings_services_list | List bookable services; standard query envelope | — | live | | wix_bookings_query_bookings | Query bookings with operators (e.g. status: { $in: [...] }); standard query envelope | — | live | | wix_bookings_get_booking | Fetch one booking | — | docs | | wix_bookings_create | Create a booking | — | docs | | wix_bookings_reschedule | Move to a different slot | required | docs | | wix_bookings_cancel | Cancel a booking | required | docs |

Events

Requires the Wix Events app (returns 428 WIX_EVENTS_APP_NOT_INSTALLED otherwise).

| Tool | What it does | Approval | Validated | |---|---|---|---| | wix_events_list | List events; standard query envelope | — | app-not-installed | | wix_events_get | Fetch one event | — | app-not-installed | | wix_events_list_guests | List guests / RSVPs; eventId is $and-merged with passthrough filter | — | app-not-installed |

Reviews

Requires the Wix Reviews app (returns 428 APP_NOT_INSTALLED otherwise).

| Tool | What it does | Approval | Validated | |---|---|---|---| | wix_reviews_list | List reviews; standard query envelope | — | app-not-installed | | wix_reviews_get | Fetch one review | — | docs | | wix_reviews_moderate | Approve / reject a pending review | required | docs |

FAQ

Requires the Wix FAQ app (returns 400 App is not installed otherwise).

| Tool | What it does | Approval | Validated | |---|---|---|---| | wix_faq_list_categories | List FAQ categories | — | app-not-installed | | wix_faq_list_questions | List questions (filterable by category) | — | app-not-installed | | wix_faq_create_question | Create a question | — | docs | | wix_faq_update_question | Update a question | — | docs | | wix_faq_delete_question | Delete a question | required | docs |

Multilingual (read-only in V1)

Returns 403 on the Ataraxis smoke-test site, with an EMPTY body. The earlier guess — a missing Multilingual Translation Schema Read permission — has since been ruled out: that permission is granted on the key and the 403 persists. What remains undetermined is whether the Wix Multilingual app is simply not installed, or whether these two endpoints also require the separate SCOPE.MULTILINGUAL.MANAGE_TRANSLATIONS scope. The empty body does not say, and neither answer has been tested.

| Tool | What it does | Approval | Validated | |---|---|---|---| | wix_multilingual_list_languages | List configured languages; standard query envelope | — | 403-permission | | wix_multilingual_list_schemas | List translation schemas | — | 403-permission |

SEO

Developer Preview, and OFF by default. Every Wix endpoint behind these nineteen tools is listed in Wix's Developer Preview — Item SEO Tags, Site SEO Tags, SEO Patterns and all six Redirects methods. Wix may change them at any time, and states plainly that you shouldn't use them on live sites: they are for testing and feedback. An API stays in preview for at most six months.

Nothing here registers unless you set enableSeoTools: true in the plugin config. Eleven of the tools write irreversibly to the live site the moment they succeed — and a pattern write re-renders every page of its type — so opting in is the operator saying they accept both risks. Preview status verified against the Wix reference on 2026-08-28.

Auditing a site's SEO, correcting its tags, and managing its URL redirects and tag patterns.

| Tool | What it does | Approval | Validated | |---|---|---|---| | wix_seo_list_item_tags | List the items of one type with their SEO tags. STATIC_PAGE enumerates the site's pages. Reports hasOverride, the item's own tags, and resolvedTags marked with each tag's source. Cursor paging. | — | live | | wix_seo_get_item_tags | One item's tags, own and resolved | — | schema | | wix_seo_get_site_tags | Site-wide tags, plus dashboard verification embeds (read-only) | — | live | | wix_seo_list_redirects | Every redirect on the site. No filter, sort or paging — the endpoint takes none | — | live | | wix_seo_get_redirect | One redirect by GUID | — | schema | | wix_seo_create_redirect | Create a 301 redirect | required | schema | | wix_seo_delete_redirect | Delete one redirect (re-reads it and refuses until its token is acknowledged) | required | schema | | wix_seo_bulk_create_redirects | Create 1–100 redirects | required | schema | | wix_seo_bulk_delete_redirects | Delete 1–500 redirects | required | schema | | wix_seo_set_item_tags | Set one item's tags — REPLACES its own set in full; refuses until the tags it would drop are acknowledged | required | schema | | wix_seo_bulk_set_item_tags | Set tags for many items of one type (100 max, 20 for BLOG_POST); per-entry results | required | schema | | wix_seo_reset_item_tags | Give an item back the tags it inherits, discarding its own (all or nothing) | required | schema | | wix_seo_set_site_tags | Set the site-wide tags — meta only; Wix rejects title/script/link here | required | schema | | wix_seo_list_patterns | The site's tag templates, per page type | — | schema | | wix_seo_get_pattern | One page type's pattern; read source to know whose it is — an owned pattern may hold zero templates, so empty ≠ absent | — | schema | | wix_seo_list_pattern_variables | The variables a page type's pattern may reference | — | schema | | wix_seo_set_pattern | Change an existing pattern — re-renders EVERY page of the type | required | schema | | wix_seo_create_pattern | Give a page type its first pattern (same path as the set, POST not PATCH) | required | schema | | wix_seo_reset_pattern | Return a page type to the Wix default pattern | required | schema |

Three things to know before using these.

A read of a static page is the SAVED revision, not the live one. For STATIC_PAGE, tags, focusKeywords and resolvedTags always reflect the saved revision, and publishStatus is always PUBLISH_STATUS_UNSPECIFIED — the API has no path to read the published revision back. An audit report should say it is about the saved page. resolvedTags also omits anything site code or apps add while the page renders, so it is not a copy of the rendered <head>.

Creating a redirect can delete another one. Redirects do not chain: if an existing redirect starts at the path a new one points to, that existing redirect is deleted and the create proceeds — no flag involved, no way back. The tool's own top-level forceReplace parameter additionally deletes a redirect holding the same from path. Wix documents that flag nested as options.forceReplace; do not send it there — the tool rebuilds the redirect from the fields it supports, so a nested flag is dropped and the create fails with FROM_URL_EXISTS as if it had never been set. This is why wix_seo_create_redirect is approval-gated by default alongside the deletes. A redirect also takes precedence over a real page at the same path, which makes that page unreachable.

The create refuses before it destroys. wix_seo_create_redirect and wix_seo_bulk_create_redirects list the site's redirects themselves and refuse, naming each redirect they would delete — with its paths, language and whether it is a group rule — until the caller repeats the token from that refusal back in acknowledgeDeletions. The token is derived from the redirect's current state, so it cannot be guessed without listing and goes stale if the redirect changes. The check is in the execution path, not in the tool description, so a direct call gets it too, and it refuses outright rather than assuming an empty list when the redirects cannot be read. Destructive writes are serialised per site; a change made in the Wix dashboard between the read and the write remains possible.

There is no update method and no query method. To change a redirect: get it, delete it, then create it carrying every field over — an omitted field is filled with its default, not its previous value. To find one, list them all and filter client-side.

Accessibility

Developer Preview, and OFF by default — separately from SEO. The Wix Accessibility Scans endpoints are in Developer Preview and may change without notice. Nothing here writes to the site, so there is no approval to give and nothing to undo; the switch exists because starting a scan needs its own Wix permission, which the SEO scope does not grant. Set enableAccessibilityTools: true to opt in. Contract read from the public Introduction, Sample Flows and agent Skill pages, and from the published SDK package @wix/auto_sdk_accessibility_accessibility-scans, whose own host mapping gives the REST prefix /accessibility/v1/accessibility-scans verbatim. The per-method reference pages are listed in the Wix menu but return 404, so no field name here was taken from a rendered page — verified 2026-08-29.

Wix runs the scan; these tools start it and read what it found.

| Tool | What it does | Approval | Validated | |---|---|---|---| | wix_a11y_list_page_collections | The page collections this site supports right now — pass a collectionId back unchanged | — | schema | | wix_a11y_run_scan | Start a scan of one target: the site, one page, or one collection. Returns a scan id immediately | — | schema | | wix_a11y_get_scan | Poll target: lifecycle, progress, aggregate totals. No pages, no findings | — | schema | | wix_a11y_get_latest_scan | The most recent stored scan for a target, without starting a new one | — | schema | | wix_a11y_list_page_summaries | Every discovered page, including clear ones and ones that failed to scan | — | schema | | wix_a11y_list_findings | The actionable findings, filterable by page, rule, severity or category | — | schema |

What makes a page clear, and why it takes three conditions.

Wix states it plainly: a page is clear only when it has no findings, its page status is completed, and its coverage confirms the relevant checks ran. A page that failed to scan also reports zero findings — because nothing was read, not because nothing is wrong. So every page summary carries clear, valued true, false or "unknown", rather than a bare count — with clearFor naming the checks a true is true for — a scan reports resultIsWhole, and PARTIALLY_COMPLETED never collapses into success. The failure mode this family has is not data loss, it is an agent reporting a clean site from an incomplete scan.

Scans are asynchronous, and these tools do not wait. wix_a11y_run_scan returns a scan id; poll wix_a11y_get_scan after suggestedPollIntervalSeconds (every 5 seconds when absent) until the status is terminal. A tool that blocked for the length of a site scan would be the wrong shape for an agent turn.

attempt is what tells a retry apart from a new scan. Wix takes a caller-generated idempotency key so a lost response cannot create duplicate work, and requires a new key for a genuinely new scan. The plugin derives that key from the site, the target and the attempt label you pass: reuse the label to retry, change it to scan again. A random key per call would satisfy the schema and make the whole guarantee inert.

Limits worth knowing. Runs are capped at 5 per minute per site; a multi-page scan covers at most 300 pages and answers SCAN_SIZE_LIMIT_EXCEEDED beyond that — after which the site must never be described as fully scanned. Stored results are kept about six months, and resultsExpirationDate says exactly when. A published site is scanned from its published version, an unpublished one from its latest saved version — the opposite way round from the SEO tag reads above.


Analytics

OFF by default, behind its own switch. Nothing here writes to the site. The switch is separate because the family needs a permission of its own — SCOPE.DC-ANALYTICS-AND-REPORTS.READ-SITE-ANALYTICS, which the SEO and accessibility scopes do not grant — so an install that opted into either of those has decided nothing here. Set enableAnalyticsTools: true to opt in. Contract read from the public Introductions and from the published SDK packages @wix/auto_sdk_analytics-semantic-model_analytics-semantic-model and @wix/auto_sdk_analytics-data_analytics-data, whose host mappings give the REST prefixes /analytics/semantic-model/v3/semantic-models and /analytics-ng/v2/site-analytics/data verbatim — verified 2026-08-29.

| Tool | What it does | Approval | Validated | |---|---|---|---| | wix_analytics_list_semantic_models | The analytics subject areas this site exposes | — | live | | wix_analytics_get_semantic_model | One model's schema: measures, dimensions, parameters, and each field's dependencies | — | live | | wix_analytics_query_semantic_model | Query a model over an interval; reports every requested field that did not come back | — | live | | wix_analytics_get_data | The six legacy site-wide counters over a date range | — | live |

The answer can be shorter than the question. Wix states it on the fields parameter itself: a field whose dependencies are not also in the query is silently omitted from the results. No error, no empty column — the key is simply absent from the rows, so a report can be missing an entire measure and look finished. wix_analytics_query_semantic_model therefore compares what was asked for against what arrived, names every field that did not come back, and — by re-reading the model's schema only when something is missing — says which dependency to add.

What the models expose is a property of the site, not of this plugin. Measures, dimensions and parameters are discovered through wix_analytics_get_semantic_model — this README states no fixed list, because there is none to state.

What that looked like on one real site (2026-08-30) is worth recording as a sense of scale rather than as a contract: 83 models, and a per-page breakdown does exist there — traffic carries traffic.page_url, traffic.landing_page_flag, traffic.prev_page_url and per-page bounce and time measures, while google-search-page carries Search Console clicks, impressions and average position per page URL. Whether the same holds on another site depends on that site and its installed apps: read the schema.

The legacy counters are site-level, and short-lived. Six measurement types (TOTAL_SESSIONS, TOTAL_UNIQUE_VISITORS, TOTAL_ORDERS, TOTAL_SALES, TOTAL_FORMS_SUBMITTED, CLICKS_TO_CONTACT), no per-page breakdown, and Wix keeps 62 days: a startDate more than 61 days back is refused with a "Do not have data for this start date" message — a retention limit, not an empty site. endDate is exclusive, so the tool reports the days it actually covered rather than leaving an off-by-one to be discovered later.

Site-scoped, confirmed against a live site. These calls send wix-site-id, which is what the site whitelist is enforced on, and not wix-account-id. Because the error is named NO_ACCOUNT_IDENTITY it was an open question whether the account header was needed instead — switching would have removed the whitelist from this family. A live call with a correctly scoped key answered 200 site-scoped on 2026-08-30, so the question is closed and the whitelist stays.

A query returns at most 1000 rows, and Wix's own default page size is 50. The tool always sends an explicit limit, so "did this fill the page" is an exact question rather than one asked against an assumed default — and it defaults to 100, not to Wix's ceiling: the whole response is serialised into the model's context, where 1000 rows across up to 60 fields would swamp it. Raise limit deliberately when you need more. A full page is reported as possibly truncated — exactly limit rows may be the whole answer, and nothing in the response settles it — so the caveat says to page before summing rather than asserting the result was cut short.

Two conventions the contract does not state, both surfaced rather than guessed: whether the semantic interval end bound is inclusive (Wix's own reference example ends a period at …T23:59:59.000Z rather than at the next midnight), and what timezone applies when none is passed. The query echoes the interval it sent and says plainly when the timezone was left unset.


Design

| Tool | What it does | Approval | Validated | |---|---|---|---| | wix_design_brief | Turn a loose textual brief into a structured markdown artefact (palette, typography, sections, image-gen prompts). Does NOT call the Wix API. | — | n/a |


Approval flow

When the LLM calls a destructive tool, the plugin's before_tool_call hook fires and returns a requireApproval directive:

{
  "requireApproval": {
    "title": "Wix: confirm wix_blog_publish_draft",
    "description": "Tool `wix_blog_publish_draft` is about to run with the following parameters:\n\n```json\n{ \"draftPostId\": \"abc-123\" }\n```\n...",
    "severity": "critical",
    "timeoutMs": 600000,
    "timeoutBehavior": "deny"
  }
}

OpenClaw surfaces this to whichever channel/UI the operator is using (Telegram inline buttons, Control UI badge, etc.). If no decision is made within 10 minutes, the call is denied automatically.

You can override the gated set via approvalRequired in the plugin config — use an empty array to disable gating entirely (not recommended in production).


Recommended companion skill

OpenClaw plugins ship code (tools, hooks); they do not ship skills. Skills live in agent workspaces and carry the business context that makes the LLM use the tools correctly (audience, tone, recipes, guardrails).

To get an agent up and running with this plugin, copy examples/recommended-skill.md into the target workspace at ~/.openclaw/workspace-<agent>/skills/wix/SKILL.md, then replace the <PLACEHOLDER> values with your own (organisation name, domain, contributors, tone). Duplicate the file for each agent that should benefit from the skill.

The template covers:

  • Conversational triggers (encoded in the description frontmatter as per OpenClaw skill convention)
  • 5 usage recipes (publish article, list real drafts, read leads, manage bookings, design request)
  • Behavioural guardrails (approval recap before publish, app-not-installed handling, PII rules)
  • Tool mapping (short reference; the README is the source of truth)

Development

Project layout

wix-openclaw-plugin/
├── src/
│   ├── index.ts             # Entry point + tool collection
│   ├── config.ts            # resolveEnv + default resolution
│   ├── wix-client.ts        # Authenticated HTTP client + whitelist
│   ├── types.ts             # Shared interfaces
│   ├── hooks/
│   │   └── approval.ts      # before_tool_call approval gating
│   └── tools/
│       ├── _factory.ts      # defineWixTool helper
│       ├── blog.ts
│       ├── media.ts
│       ├── site.ts
│       ├── data.ts
│       ├── forms.ts
│       ├── contacts.ts
│       ├── bookings.ts
│       ├── events.ts
│       ├── reviews.ts
│       ├── faq.ts
│       ├── multilingual.ts
│       └── design.ts
├── test/
│   ├── wix-client.test.ts
│   ├── manifest.test.ts
│   ├── hooks/approval.test.ts
│   └── tools/blog.test.ts
├── tsconfig.json
├── tsconfig.test.json
├── tsconfig.test-build.json
├── openclaw.plugin.json
└── package.json

Build and test

npm install
npm run typecheck     # strict TS check (src + test)
npm test              # compile tests + run node:test
npm run build         # compile src/ → dist/
npm run clean         # remove dist + dist-test

Release process

  1. Update CHANGELOG.md with a new ## [x.y.z] - YYYY-MM-DD section
  2. Commit
  3. Tag and push:
    git tag v0.1.0
    git push origin v0.1.0
  4. GitHub Actions will:
    • Run typecheck, tests, build on Node.js 24
    • Stamp the version into package.json and openclaw.plugin.json
    • Publish to npm via Trusted Publishing (OIDC) — no NPM_TOKEN secret needed
    • Create a GitHub Release with the changelog excerpt

License

MIT — see LICENSE