Skills
Skill 9 of 67
Build a Wix Headless site fast by wiring SHIPPED, verified @wix/sdk code instead of authoring the integration from recipes.
26 minutes · 5,709 words · 5 sections
Install
npx skills add wix/skills --skill wix-headless-kitnpx skills add wix/skills/plugin marketplace add wix/skillsThe first command installs just this skill, by the name in its SKILL.md; the second installs the whole repository.
Build a Wix Headless site on shipped, verified code instead of authoring the integration. Each vertical ships the integration itself — a typed data layer, hooks, components, pages, and a seed script that are already correct. On a stack that runs it (Wix-managed Astro, any React project) the code is deployed and the agent’s job narrows to brand, layout, copy, and wiring. On a stack that can’t run it (a static site with no bundler, a server-rendered app in another language) the same code is the reference: its REST twin deploys for the browser side, and the rules it encodes are what the agent ports. Either way the decisions live in the code; don’t re-litigate them.
Scope. Tuned for Wix-managed Astro, and each vertical ships one shape of its solution. Use
it as-is when the brief doesn’t contradict it. When the brief asks for something that shape
doesn’t express — or once the site exists and the work turns to managing or extending it — that’s
wix-docs and wix-manage, not a workaround here.
wix-headless-templates skill (skills/wix-headless-templates/<vertical>/), not in this skill’s
folder. node <SKILL_ROOT>/install/templates.mjs prints where that skill is: the sibling folder
<SKILL_ROOT>/../wix-headless-templates/ when it was installed beside this skill (the cold start
installs both; a plugin may not), else a one-time fetch into <SKILL_ROOT>/templates/ (a git
clone of the skill’s repository, a second); every script below
resolves it the same way. Every templates/... path in this document is relative to that
printed root — there is no templates/ folder inside this skill when the sibling exists.
The folder stays with the project (only the composed project/ scaffolds are left out of its
repository), so a later session reads the version the project was built from. Each vertical holds:
app/ — the framework-agnostic core (TypeScript): a data layer that returns plain,
serializable DTOs (images resolved to https URLs, prices pre-formatted), React hooks, and
routing-free headless components. Works in Astro islands, Vite SPAs, and Next.app-astro/ — a thin Astro overlay: SSR pages that fetch via the core and pass DTOs to
islands, with owner-editable item-page SEO pre-wired.seed/ — a build-time REST seed script (plain-data plan in, created content out) plus its
SEED.md contract.INSTRUCTIONS.md — the vertical’s playbook: file map, what you build, hard rules.project/ — the vertical composed into the Wix CLI’s blank Astro scaffold, with its
lockfile: what wix create copies for a new site, so the first vertical installs without
resolving.src/wix/sdk.ts: on Wix-managed Astro
auth is ambient (no client, no id); on any other React setup the same file runs a manual
visitor client off the public client id in src/wix/config.ts. The deploy step configures
this — nothing to wire by hand.wix-docs; never infer one from generated SDK types,
package files, or node_modules. A normal caller-permitted operation belongs in a new
data-layer function. A privileged operation belongs in a validated server endpoint — see
templates/shared/CUSTOM_OPERATIONS.md. The presentation doesn’t ship: the vertical’s
INSTRUCTIONS names the surfaces you design and implement yourself on the shipped hooks,
with a skeleton carrying each surface’s contract (for storefront: the shop and PDP pages
with their islands, and home).wix-docs. Read it there first, then write the call.
The test, before every request: the exact path and body appear in the output of a file
read or a docs search you ran in this session, and you copy them from that output. Anything
else is memory: a file whose output was cut short before the call, a source you remember
reading earlier, a call built by changing part of one you did find. A guessed call that
returns 400 or nothing is not a step toward the
answer; it is the failure this rule exists to prevent, trying the next variant is still
guessing, and an empty or error reply to a call that failed the test tells you about the
call, never about the site. Keep errors visible while a call is unconfirmed: no 2>/dev/null,
no | echo. The shipped code is tested against live sites; a body that looks similar is the
one that returns nothing, and the API rarely says why.capabilities.mediaUpload.policies entry to the plan; Fast ships its client helper, Astro
endpoint, dependencies, and generated policy module once. Read
templates/shared/CUSTOM_OPERATIONS.md before choosing it. The agent wires the helper to
the product UI; it never authors or widens the endpoint. For a site-wide search (a header box
with suggestions, a /search?q= page over the deployed verticals’ products, services, posts
and events), add a capabilities.siteSearch entry; Fast ships its data layer, stores, hooks,
components and search page once. Enabling it means the Wix Site Search app is installed on the
site by the seed step (install: true; the capability’s seed/install.mjs, run after the
content seed) — the index fills within about half a minute of the install. Playbook:
templates/shared/capabilities/site-search/INSTRUCTIONS.md.<SKILL_ROOT>/install/ holds plain Node scripts, no build step, each with a header comment that
says what it does and how it is called. They are the deterministic steps of the run: each copies,
composes, installs or seeds, and prints one JSON object (or one JSON event per line) saying what it
found and did. Read any of them when you want to know what a step does before running it, or when a
step’s output surprises you; the templates’ seed modules are the reference for the Wix calls a
vertical needs, in the order that works.
| Script | Does |
|---|---|
templates.mjs | Finds the shipped code (the wix-headless-templates skill beside this one), or fetches it once as a sparse clone; prints its folder. |
context.mjs | Reads wix.config.json and .env.local, pulls the env on the CLI route when it is missing, and prints the folder’s shape, the deploy site and the content site, the publisher (cli or plugin), whether npm reaches the registry, and whether the upload tool’s S3 host answers from this shell (carrier.s3). Changes nothing. |
setup.mjs | One call from the folder and the brief to a project ready for the brand layer: scaffolds (or, with --site --app, copies the composed template and writes the config and env), deploys the vertical’s code, writes the agent config files, starts the install, and seeds a site it created. |
attach.mjs | setup.mjs for a site that already exists: does what wix create does after creating one (OAuth app, hosting, env, wix.config.json) against the site id given, then scaffolds, deploys and installs; seeds only with --plan; with --hosting self, puts the given origins on the OAuth app’s allow-list instead of Wix hosting. |
deploy.mjs | Composes a vertical’s code layers into the project for the stack (astro, react, lib, static), adds its dependencies, and keeps the lock valid for npm ci (lock.mjs). |
install.mjs | The one dependency install: decides none, npm install or npm ci from the lock and what node_modules already holds; writes .install-exit. |
bootstrap.mjs | CLI route only: checks the Wix CLI and runs the device-code login, one JSON event per line. |
check.mjs | Compares this installed skill and its templates with the repository they came from; read-only, prints the commands that would update. |
agents-md.mjs, env-ignore.mjs | Write a new project’s AGENTS.md, CLAUDE.md and .gemini/settings.json; keep .env.local out of git. |
proc.mjs, background.mjs, pins.json | npm and npx started the same way on every OS; the detached install and seed; the pinned CLI and template versions. |
templates/<vertical>/seed/seed-*.mjs, read-site.mjs | The vertical’s seed from a plan, and a read of what the site already holds. SEED.md beside them is the plan’s contract. |
Needed throughout: Node ≥ 22.12 (the Astro build’s line; the CLI route’s Wix CLI wants ≥ 24.18), git, the two companion skills installed beside this one,
wix-docs and wix-manage, and one of two ways to Wix. node <SKILL_ROOT>/install/context.mjs
prints which one this machine has, as publisher:
plugin — no Wix CLI session on this machine; the Wix MCP’s tools are in your tool list
(ExecuteWixAPI, UploadHeadlessWebsiteFiles: a Wix plugin or connector, connected); and npm
reaches the registry, so the kit runs here. The MCP carries the user’s login. The site is provisioned through ExecuteWixAPI with the recipe
wix-manage/references/sites/create-headless-site.md, the vertical in seedOptions so its app
installs with the site (the provision call returns the
metaSiteId and the site’s OAuth client appId); step 3’s setup takes both as --site and
--app and runs no CLI; the seed is an ExecuteWixAPI script written from the vertical’s
SEED.md (the cold start’s run, step 4); the release is npx astro build, then the build
uploaded with UploadHeadlessWebsiteFiles (step 5), attached in one call where the client shows
attachments as a local path, or in two calls with curl to the URLs the first returns, from a
shell that reaches the internet (the URLs are on Amazon S3; curl -sI -m 25 https://s3.amazonaws.com
answers with S3’s own headers where they work, x-amz-request-id and usually Server: AmazonS3,
and a sandbox limited to a few hosts gets a proxy’s refusal with neither). The tool releases the build to the site’s Wix hosting, stores the project’s source in the
site’s Code Store repository, and returns the live URL. The plugin route asks for no login.
The carrier is settled before the build, from context.mjs‘s carrier.s3 and from whether
the client hands attachments over as files (the tool’s attachments description names the
clients that do): with neither, the Astro build has no way to the site and the run is the cold
start’s “The run, through the plugin”: the site, the apps and the seed through ExecuteWixAPI
and the frontend as a few small static pages dropped with the upload tool, written against the
kit’s REST twins and cores as reference (its step 5); the compose is not run, since every file
it writes would have to be written out as text.cli — where the Wix MCP is not connected, or a Wix CLI session is already on this machine:
a logged-in Wix CLI (npx @wix/cli@latest whoami; npx @wix/cli@latest login is a
device-code flow: surface the URL and code to the user, never read tokens into context).
node <SKILL_ROOT>/install/bootstrap.mjs checks the CLI and runs the login when there is none;
wix create, wix env pull and wix release do what the steps below say.The cold-start page, https://www.wix.com/skills/headless-cold-start/headless-kit.md, gets a
machine with none of this, the skills included, to that point. The four skills this run reads
(wix-headless-kit, wix-headless-templates, wix-docs, wix-manage) are on disk after that
install (.agents/skills/, or a plugin’s folder), or served by the client’s skill tool (text to
read, not files: the scripts and the templates run only from disk), or online at
https://www.wix.com/skills/<skill>/<path>, where <skill>.manifest.json lists every file with its
size and a folder’s _content returns its files at once; <SKILL_ROOT> below is the kit’s folder
on disk. In a folder that
already holds a wix.config.json, node <SKILL_ROOT>/install/context.mjs first: it runs
wix env pull when .env.local is missing (on the CLI route) and prints the folder’s shape
(folder.shape, the cases of step 3, with the next for each) and the two identities a project
has — the deploy site (the config, where the release goes) and the content site (the env, whose
app the SDK client runs as and whose dashboard manages the business). They are one site, except on a migration preview
(guides/migration.md), where the env names the site being migrated. Every script here reads that
context; the site a call targets is never guessed from the config alone. Then fetch the shipped
code once: node <SKILL_ROOT>/install/templates.mjs. It prints the folder; the templates/…
paths below are relative to that folder, never assumed under <SKILL_ROOT>.
node <SKILL_ROOT>/install/check.mjs says whether the skill or its templates have a newer version
and prints the update commands; it changes nothing.
Throughout any run, keep the site working at every step so the user can try it as it grows. Steps only the site owner can take never hold a flow back: drafted content is live, and anything that takes money reaches Wix’s checkout before payments are connected. The owner’s steps go in the closing with their links, as next steps the user can take or ask for.
Throughout any run: if the user asks to send feedback to Wix, complains or gets frustrated, or the
run hits friction of any kind: anything that cost more turns than it should have, whether or not
it ended in an error (a confusing error, a doc gap, a seed that had to be re-run, a shipped file
that did not cover the brief, a playbook line you had to read the source to understand, a call you
had to work out by trial, a workaround you had to invent, a slow or flaky step, a platform gate),
offer to relay it to Wix per <SKILL_ROOT>/guides/feedback.md. Default to offering rather than waiting to be asked; send
only after an explicit yes, never automatically. Step 5 ends with the same self-check.
Resolve the stack. Default is Wix-managed Astro — take it unless the user names another framework or the directory already holds one. Then, by what the shipped code can run there:
--stack react. The agent’s own files may be JS; the shipped files are TypeScript and
build untouched inside a JS project — never strip them by hand; if the brief wants no
TypeScript anywhere, say the shipped code cannot meet that and ask before going on.
A named framework is scaffolded with its own command
first (npm create vite@latest, …), then step 3 runs in that folder.src/wix/ has no React in it), the React hooks and components
don’t apply: --stack lib. The agent binds the stores and writes its framework’s components
against the same contracts.<SKILL_ROOT>/guides/reference-mode.md). Nothing from app/ deploys; the REST layer
deploys for the browser side, and the server side ports it for its reads.What Wix hosting takes, and what each stack needs to be released there. wix release
uploads the folder named in wix.config.json (site.outputDirectory) and serves it as
files — no SPA fallback, no directory index, no rewrites: / and real files resolve, a clean
client-side route answers 404 when loaded directly or shared. Server code runs only as a
Cloudflare Workers build, declared as outputDirectory: { client, server }.
@wix/astro, ambient auth), the hosting adapter (@wix/astro-wix-hosting-adapter, the
Workers build), @astrojs/react with React 18 for the shipped components, and in
astro.config.mjs integrations: [wix(), react()], adapter: wixHostingAdapter(),
output: "server", security: { checkOrigin: false }, image.domains with
static.wixstatic.com. An Astro project made without the CLI has none of that; add it
before deploying, and the site serves every route. The integration’s current major
(@wix/astro 3, as in this skill’s templates) requires Astro 7: a project on an earlier
major moves to 7 first, or is connected as a React host./.outputDirectory: { client, server }; otherwise it is self-hosted, with its domain added to
the OAuth app’s allowed domains before checkout can return to it.outputDirectory points at the folder the pages live in; a route is a
page plus a query-string slug (reference mode).The seed plan. The brief decides what is seeded; a site this run makes always opens with content:
| the brief | the plan |
|---|---|
| supplies the content in any form: a CSV, JSON or spreadsheet, a list in the prompt, a PDF price list, a folder of photos and a text file, a link to their current catalog, anything that names the content | that IS the plan: map it into plan.json per templates/shared/SUPPLIED-CONTENT.md and the vertical’s SEED.md (“Supplied content”), every entry, names and prices verbatim, their images and no others |
| describes the content without listing it (“a store for hand-poured candles, four of them”, “a dozen FAQ questions in three groups”) | draft a plan from the description per the vertical’s SEED.md (read only that for this; save INSTRUCTIONS.md for step 4) |
| says nothing about content (“build me a store”) | on a site made for this run (create, adopt, config-only) draft a plan per the vertical’s SEED.md so the site opens with content — demo content the agent decides on, without being asked — and say in the closing message that it is placeholder content and where the owner edits it. On a site that existed before the run: seed nothing; its content is its own |
An existing site has no plan of its own: when the brief names a site by its id, or the folder’s config does, the site holds the content already; the frontend reads what is there (step 3’s attach path), and only content the brief supplies or describes is added to it.
Set up the project, in its folder — one deterministic call, the same for an empty folder
and for a project already on disk; the folder decides what it does, from a few file facts:
wix.config.json, its site.outputDirectory, the migration variables in .env.local,
package.json, index.html (at the root or in public/), src/pages/. node <SKILL_ROOT>/install/context.mjs prints the shape it reads
and the next for it. The brief is the instruction: what it asks to switch on is installed
on the site the folder names, without asking again. Ask only when acting would create a second
site for a folder that already has one, or when a cleanup seems needed.
node <SKILL_ROOT>/install/setup.mjs --vertical <vertical>[,<vertical>…] [--plan plan.json] [--business-name "<Brand>"] [--stack <stack>]Name every vertical the brief needs in this one call (a store with member accounts is
storefront,members): the first one’s template scaffolds the project; the others deploy in the
same call, so the one install covers them all. A vertical added after the install has started
costs a second install.
| the folder holds | shape | what setup does | seeded by setup |
|---|---|---|---|
| nothing, or loose files (a CSV, a brief) | empty → create | wix create with the vertical’s composed template, here; --business-name names the site. On the plugin route, --site <metaSiteId> --app <appId>: the ids the provision call returned for a new site, or, for a site that exists with no project (a dropped site), its id and the companion app’s id from get-or-create (guides/existing-site.md); the composed template is copied in and wix.config.json and .env.local written for that site, no CLI | yes, from --plan, on the CLI route. On the plugin route setup takes no --plan and seeds nothing: the plan is seeded through ExecuteWixAPI (the cold start’s run, step 4) |
a frontend, no config (a package.json, or index.html at the root: someone’s Astro, Vite, Next, plain HTML) | project → adopt | init in place gives it a new, empty site, then deploys; --stack from step 1 is required; make the project what that stack needs on Wix hosting (step 1) before or right after | yes, from --plan |
a config whose .env.local declares an active editor migration (EDITOR_MIGRATION_STATUS=ACTIVE), with or without the blank Astro starter the download carries | migration → migrate | the shipped code into the starter (or the composed template around a bare config), deployed with the migrated site’s app as the client, the install starts; ready_for_brand_layer says mode: "migrate", the parent as siteId, the child as deploySiteId (guides/migration.md) | no, ever |
| a config, no frontend | config-only → refuses | the site exists and has no frontend yet: on the CLI route attach.mjs (below) takes the site from the config, reuses its hosting, scaffolds and deploys; on the plugin route setup.mjs --site --app with the config’s ids, in an empty folder, then the build released by UploadHeadlessWebsiteFiles (guides/existing-site.md). That config is what init leaves behind, and init always creates a site: this site was made for this run and is empty | yes: draft the plan as for create, then attach.mjs --plan |
a config and a frontend (a package.json, or index.html inside the folder site.outputDirectory names) | wix-project → refuses | iterate: never scaffold, init or reseed. deploy.mjs <vertical…> --stack <stack> adds a solution (the client id comes from .env.local, the config as the fallback), then one install, node <SKILL_ROOT>/install/install.mjs (nothing when node_modules already satisfies the lock); a change is file edits; then release | no |
a config, a package.json, public/index.html and no src/pages/ (a site published through the drop flow, on its Wix Dev Machine) | static-in-astro → refuses | the pages stay plain files in public/: deploy.mjs <vertical…> --stack static --out public puts the REST layer in public/js/wix/, the pages are wired in place (reference mode), and no Astro pages are added; release with build then release, the URL stays | no |
a config and the CLI’s blank Astro starter with no work of its own (wix-astro-blank, only the blank template’s packages: a Dev Machine’s never-released site, a bare wix create) | blank-starter → refuses | attach.mjs --business-name <brand> --vertical <v…> [--plan plan.json] on the config’s site: the vertical’s composed template takes the starter’s place (its lockfile with it), the install and the seed start detached; build the brand layer while they run | yes, from --plan: the site was made for this run and is empty, unless read-site.mjs shows content |
a config, index.html at the root, no package.json (a site published through the drop flow and downloaded) | published-static | the config’s site, no init: site/ becomes the upload, the REST layer deploys into site/js/wix/; the next says to move the pages, styles and assets in; release keeps the URL | no |
A folder no row names is wix-project: the fill-only path — never scaffold, init, reseed or delete; deploy, edit, release. A wrong guess costs a slower run, never the user’s work.
Who decides the seed: where the site came from, never the brief’s wording. A site made
for this run is empty by construction, so it is always seeded — with the brief’s content when
it supplies or describes any, otherwise with demo content the agent drafts per the vertical’s
SEED.md, without being asked, so the site opens with something to see. Made for this run
means: setup created it (create, adopt), or the folder held only a wix.config.json and no
frontend (config-only — the config is what init leaves behind, and init always creates a
site; attach reports siteOrigin: "init"). A site that existed before the run — named by its
id in the brief or by --site, a project linked to it, a migration’s parent (attach reports
siteOrigin: "given") — holds content the run did not make: seed only what the brief
supplies or asks to add (attach.mjs --plan plan.json, or the vertical’s seed module from
the project root: node <templates>/<vertical>/seed/seed-<vertical>.mjs plan.json, <templates>
being the folder install/templates.mjs printed),
and never invent content for it. “A new storefront for my toy store” describes the business,
not content to add: nothing is seeded. Read an existing site first either way
(seed/read-site.mjs). Seeds are additive and idempotent by name; nothing on a site is ever
deleted or overwritten, and the result’s preexisting[] names what was already there.
<SKILL_ROOT>/guides/existing-site.md
and follow it (read the site, then attach.mjs, which does what setup does against the
site given and seeds only with --plan, which that guide says to pass only for content the
brief supplies or asks to add; self-hosting and a project already on disk are in there too).--vertical is required and picks which shipped code deploys AND which seed runs. The
ready_for_brand_layer event says mode (create, adopt, migrate, published-static),
shape, the stack, publisher (cli or plugin), and the next for that stack, including how
it releases.
setup scaffolds with --skip-git: it composes its own steps and leaves version control to
you / the enclosing repo, so it does not create the scaffold’s usual git repo + initial
commit (which would otherwise become a nested-repo gitlink if the project lands inside a repo).
The project is created in the current directory — the folder the entry had you work from,
which already holds the installed skills — so the project is self-contained and a later session
opened in it finds everything. It refuses if the folder already holds a file the scaffold would
write. --subfolder creates it in a new folder named after the business instead, for a current
folder that must stay as it is; the skills then sit one level above the project.
It emits one JSON event per line and returns in ~35s: scaffolds the project from the
vertical’s composed template (wix create copies it: the code and its lockfile arrive with
the scaffold), deploys whatever the folder still lacks (patching package.json with every
dependency the code imports), then starts two detached background jobs — the dependency install (install/install.mjs: nothing when node_modules already satisfies the lock, npm install over a tree that is there, else npm ci || npm install, each with --ignore-scripts --no-audit --no-fund)
and the seed — whose logs and completion markers are in the events. The final
ready_for_brand_layer event carries the project dir, siteId, ready-made dashboard links,
and both markers. Relay notable events. On an error event, recover just that step via the
manual path below, then continue.
Recovering one step, or adding a solution later: the pieces run on their own from the
project root — node <SKILL_ROOT>/install/deploy.mjs <vertical…> --stack <stack> (the client
id is read from wix.config.json), ONE node <SKILL_ROOT>/install/install.mjs
(never a second npm install concurrently: two npms in one
node_modules race and redo each other’s work; setup already started one — wait on its
marker), the vertical’s seed module per its seed/SEED.md.
A code change on an existing project is done when it is released (step 5) and the live
URL shows it — not when a dev server or a local build shows it. A management change (a
recipe against the site) needs no release; the frontend reads it live.
A site released through the upload tool keeps its source in its Code Store repository: a later
change, in any session, downloads it (guides/existing-site.md), edits, builds and uploads with
the downloaded revision as expectedHeadRevisionId. One site keeps one writer path: such a site
is not changed through wix release or a plain drop.
Design and build the presentation while the install finishes — in the project dir from
the ready_for_brand_layer event, per the vertical’s INSTRUCTIONS.md: set the @theme
tokens, brand the chrome, and implement the vertical’s creative surfaces yourself on the
shipped hooks (for storefront: your product card + grid, shop surface, PDP surface, and the
home page) — designed to fit the brief, not copied from the reference components. Read the
INSTRUCTIONS and the shared floors — templates/shared/DESIGN.md +
templates/shared/CONTENT.md — now (not earlier — their contracts matter only from this
step on); the hook/DTO
contracts are inlined there, so don’t open the shipped files themselves.
A frontend that already exists gets the minimum. When the run wires pages that were
there before it (a dropped mock, an adopted site, a published static site), do the least that
makes them work: connect each control the pages show to the shipped code, and add only what a
control can’t work without. Anything more the vertical offers is added only when the brief
asks for it; name it in the closing message.
If the brief needs a core operation that shipped code does not cover, read
templates/shared/CUSTOM_OPERATIONS.md before writing it. Use one documented path and
implement it; do not reverse-engineer SDK internals.
When both background jobs have completed — the install’s marker
(.install-exit, containing 0) and the seed’s (.seed-exit) both exist — verify the
seed succeeded (.seed-exit contains 0; seed-result.json has the created counts for
your summary — if non-zero, read seed.log and re-run the seed module manually). Those two
seed files exist only when setup started the seed (attach runs none: only the install
marker is waited on). When you ran seed-storefront.mjs
yourself (adopt, iterate and published-static runs, reference mode), there is no marker to wait for: the process’s
exit code is the result and its stdout is the JSON — wait on the process (a foreground run,
or wait on its pid), not on a file. Then
build & release once (managed), as the next of the ready_for_brand_layer event says
for the stack and the publisher: Astro on the CLI route → npx @wix/cli@latest build then
npx @wix/cli@latest release; Astro on the plugin route → npx astro build from the project
root, then UploadHeadlessWebsiteFiles with the site’s siteId, in one of two forms (the next
carries the zip commands, with Python’s zipfile where there is no zip binary):
node_modules (.wix/build-metadata.json
and dist/ in it), passed as attachments. The build is released and the source in the same
zip is stored.curl -sI -m 25 https://s3.amazonaws.com answers with S3’s own headers where they work,
x-amz-request-id and usually Server: AmazonS3; a sandbox limited to a few hosts gets a
proxy’s refusal with neither, and cannot release a build this way): the build zip (zip -qr build.zip dist .wix) and the source zip, the project
without node_modules, dist, .wix, .astro, .env*, .agents
(zip -qr source.zip . -x 'node_modules/*' 'dist/*' '.wix/*' '.astro/*' '.agents/*' '.env*' 'build.zip').
First { siteId, prepare: true, size }, size being wc -c < build.zip: the reply gives a
curl -X PUT ... --data-binary @build.zip "<putUrl>", one for the source zip when the site’s
repository takes it, the repository’s headRevisionId, and the exact second call. Run the
curls as given, then { siteId, uploadKey, sourceUploadId, expectedHeadRevisionId }.The service deploys, commits the source to the site’s Code Store repository, then releases; a
refused commit releases nothing. expectedHeadRevisionId is the revision the project started
from: the one it was downloaded at, or for a project started in this run the headRevisionId
the prepare returned. Left out, the release works only on a repository with nothing in it yet;
otherwise it answers EXPECTED_HEAD_REQUIRED and releases nothing. A 409
CODE_STORE_HEAD_CHANGED means the repository moved since: download it again
(guides/existing-site.md), carry the change over, build and upload. A 404 on the second call
means the upload expired: prepare again. The result carries the live URL; a release replaces
static pages dropped on the site before, at the same URL.
Otherwise:
React or another bundler → the project’s own build, then npx @wix/cli@latest release of
the build folder named in wix.config.json (deep URLs must answer 200 directly, step 1);
static → release alone. If the install failed, run it once more and then build. Don’t
build+release mid-flow; backend content is fetched at
runtime, so a re-release never “refreshes” seeded data. The run is complete only when the
site is released — close with the live URL and the dashboard link
https://manage.wix.com/dashboard/<siteId> (the siteId of the ready_for_brand_layer
event: on a migration preview that is the migrated site’s dashboard, the release URL is the
preview’s, the original site is unchanged, and you complete the migration once they
approve (guides/migration.md) — say all three). Tell the user how to put their own
domain on the site, per the wix-manage recipe references/domains/domain-search-purchase-and-connect.md
(installed beside this skill, else https://www.wix.com/skills/wix-manage/references/domains/domain-search-purchase-and-connect.md):
bought through Wix, or one they already own. When the site takes money through
hosted checkout (a cart, a paid booking or rental, tickets, plans, donations) and nothing says
payments are already set up, say what a visitor meets at checkout until they are — “We
can’t accept online payments. Contact us for help with your order.” — and hand the two links
that fix it: Accept payments https://manage.wix.com/dashboard/<siteId>/wix-cashier/payments
(connect a payment method; “manual payments” is enough for free and pay-in-person flows) and
Upgrade the plan https://www.wix.com/upgrade/website?metaSiteId=<siteId> (online payments
need a premium plan). Both are the owner’s steps, not a defect in the site. When the run started
from the owner’s own pages, name what those pages promised that the released site does not do.
Copy the live URL verbatim from the
release output (the CLI’s, or the upload tool’s result) — never retype it from memory (a
mistyped subdomain hands the user a 404). Before you sign off, run the feedback self-check over the whole session
(guides/feedback.md): anything that cost more turns than it should have, including what you
recovered from silently, is signal; if anything qualifies, offer to relay it as you deliver the
links, and send only after an explicit yes.
The shipped data layer exists a second time as a REST layer over fetch, for the stacks that
cannot run app/: a static site with no bundler, or a server-rendered app in another language
(Flask, Laravel, Rails). The REST layer deploys for the browser side; the server side ports its
reads. When step 1 resolves to one of these stacks, read <SKILL_ROOT>/guides/reference-mode.md
before step 3: it holds the mechanics (the site/ layout and setup’s part in it, what runs in the
browser versus the server, the OAuth allow-list for a self-hosted origin, pre-rendered output) and
how to close such a run. A public site is still better served by managed Astro; say so when you
close.
Where the kit does not run (no route to npm, no Node), or when the install, the CLI or the login is
blocked where you are, the run is the cold start’s “The run, through the plugin”
(wix-headless-cold-start/headless-kit.md, https://www.wix.com/headless/skill.md): the same run,
step by step, as the Wix API calls the scripts make and the files beside this skill that carry the
contracts. On the plugin route the same steps are the reference for the calls that go through
ExecuteWixAPI (the provision call, the seed); the build and the release are this skill’s step 5.
The shortlist. Match the brief against the first column; when it names a Wix product or a
feature not here, when two rows could fit, or when the request sounds like something this skill
does not ship (meetings, gift cards, loyalty, groups), read
<SKILL_ROOT>/guides/capabilities.md: every Wix product, what it covers, which vertical here
ships it and what is not shipped.
| The user wants… | Vertical | Playbook |
|---|---|---|
| Online store: products, categories, variants, cart, checkout | storefront | templates/storefront/INSTRUCTIONS.md |
| Appointments/classes: services, time slots, staff, booking, checkout | bookings | templates/bookings/INSTRUCTIONS.md |
| Rentals: rooms, vehicles, gear rented by the hour or the day, customer-picked length, checkout | rentals | templates/rentals/INSTRUCTIONS.md |
| Blog: post feed, categories/tags, rich-content post pages | blog | templates/blog/INSTRUCTIONS.md |
| Structured content collections (directory, recipes, listings) with pages designed per schema | cms | templates/cms/INSTRUCTIONS.md |
| Any visitor-fillable form: contact/enquiry, signup, application, survey — rendered from the live schema | forms | templates/forms/INSTRUCTIONS.md |
| Events: listing, event pages, free RSVP, ticket sales via hosted checkout | events | templates/events/INSTRUCTIONS.md |
| Member accounts: custom in-app login/sign-up, gated pages, account page | members | templates/members/INSTRUCTIONS.md |
| Portfolio/showcase: collections of projects, project pages with media galleries | portfolio | templates/portfolio/INSTRUCTIONS.md |
| Membership/subscription plans: pricing page, plan detail, hosted purchase | pricing-plans | templates/pricing-plans/INSTRUCTIONS.md |
| Restaurant: menu with photos, online ordering, table reservations | restaurants | templates/restaurants/INSTRUCTIONS.md |
| FAQ: questions grouped by category, search, expandable answers, a link per question | faq | templates/faq/INSTRUCTIONS.md |
| Donations: campaign pages, goal progress, one-time and recurring giving via hosted checkout | donations | templates/donations/INSTRUCTIONS.md |
Verticals compose: a brief that spans several (a restaurant with a blog, a store with member
accounts) names them all in the setup call (--vertical restaurants,blog), so one install covers
them; each vertical’s seed runs with its own plan. On a project already built,
node <SKILL_ROOT>/install/deploy.mjs <vertical…> from the project root adds one, then one
npm install, then its seed. A request that matches no shipped vertical has no shipped
code: say so in one line, then build it from the Wix API reference through wix-docs (search,
then the method page), with the same rule as every other call, on the same project and stack,
starting from the closest shipped vertical when one exists (guides/capabilities.md says which).
Build a Wix Headless site fast by wiring SHIPPED, verified @wix/sdk code instead of authoring the integration from recipes. Each Wix business vertical ships a typed, framework-agnostic React core (data layer returning plain DTOs, hooks, headless components) plus an Astro overlay (SSR pages with owner-editable SEO pre-wired) and a build-time REST seed script — the agent scaffolds via the Wix CLI, deploys the shipped code, seeds the backend, designs the presentation layer itself on the shipped hooks (product card/grid, PDP, home, theme), and releases to Wix hosting. Works on Wix-managed Astro (ambient auth, the default) and on any React-based project (Vite, non-Astro) over the public OAuth client id. Verticals: stores/storefront (products, categories, variants, cart, hosted checkout), bookings (services, appointment/class time slots, staff, booking form, checkout-or-place), rentals (rooms, vehicles, gear by the hour or the day: resources, customer-picked length, priced quote, checkout), blog (posts, categories/tags, rich content), cms (structured content collections), forms (schema-driven visitor forms: render, validate, submit), events (listing, RSVP, ticket sales), members (login, gated pages, account), portfolio (project collections, media galleries), pricing-plans (plan grid, hosted purchase), restaurants (menus, online ordering, table reservations), faq (categorized questions and answers, search, a link per question), donations (campaign pages, goal progress, one-time and recurring donations via hosted checkout). Triggers: build me a store/blog/booking/rental/event/restaurant/portfolio/FAQ/donation site fast, take appointments fast, rent out rooms/cars/equipment headless, sell tickets or membership plans headless, collect donations headless, wix headless kit, connect a Wix business app with ready-made SDK code.
The verbatim description from this skill’s front matter — the string an agent matches on to decide whether to load it.
main, last pushed 8 November 2026.SKILL.md, not by matching a directory convention. 5 distinct layouts observed: skills/*/SKILL.md, skills/wix-headless-replatform/resources/*/SKILL.md, skills/wix-replatform/resources/*/SKILL.md, */SKILL.md, wix-replatform/resources/*/SKILL.md.h1 and no skipped levels:.claude-plugin/marketplace.json by Wix, declaring 1 plugin. It is read for editorial metadata only — never as the skill index, which is always the repository tree./wix/skills.md, and each skill at its own .md URL.20 files · 187 KB
Everything this skill ships beside its prose. All of it is set here, as subchapters of skill 9.
Everything else published alongside the skill.
guides/5 files · 39 KB