Subchapter 9.1
references/AI_FEATURES.mdMarkdown10 KBView on GitHub
Add generative-AI features to a headless app using the Wix AI APIs: LLM text/chat completions and text embeddings. Wix fronts the model providers (OpenAI, Anthropic) and handles auth + billing, so you never hold a provider key. — same gateway, same rules; this file is text + embeddings and the rules that apply to AI calls.
IMAGE_GENERATION.mdOpt-in, by intent — only build AI features when the intent calls for them (a support chatbot, AI
product descriptions, semantic search, summarization…). Like imagery, it’s off by default; there’s
no fixed slot list. Status: Developer Preview — the API shape can change; confirm models with
/models (below) rather than trusting a hardcoded list.
Every AI call must be made from server code. Never from the browser.
@wix/ai SDK throws in browser environments (“AI calls from browser code are not supported.
Move your AI logic to backend code.”).So the AI call always sits behind a server boundary — a Wix serverless/web-method backend (managed), or the app’s own server (self-managed/stripe). The browser calls your endpoint; your endpoint calls Wix. That boundary is also where you enforce credits/abuse controls (see Credits & cost control) — it’s the security and billing perimeter, not optional plumbing.
For the app you build (Astro-on-Wix, Node — any JS/TS server), use the SDK. It’s built on the Vercel AI SDK (opens in a new tab) — typed, and auth is handled for you. Backend only.
npm install @wix/ai "ai@>=6.0.26" "zod@>=4.1.8"// Wix-managed backend (Astro-on-Wix serverless / web method): auth is handled automatically.
import { generateText } from "ai";
import { openai } from "@wix/ai"; // also: anthropic, runware
const { text } = await generateText({ model: openai("gpt-5.2"), prompt: "…" });// Self-managed / stripe: pass an authenticated WixClient instead.
import { createOpenAI } from "@wix/ai";
import { createClient, AppStrategy } from "@wix/sdk"; // or ApiKeyStrategy
const openai = createOpenAI({ client: createClient({ auth: AppStrategy({ appId, appSecret, instanceId }) }) });@wix/ai exports openai, anthropic, runware (ambient, Wix-managed) and createOpenAI,
createAnthropic, createRunware (client-injected, self-managed). Methods come from ai:
generateText / streamText, embed / embedMany, generateImage. Exact model selectors
(verified — don’t guess the method names):
openai("gpt-5.2") or openai.responses(id) / openai.chat(id); anthropic("claude-…").openai.embeddingModel("text-embedding-3-small") — not textEmbeddingModel (that
method doesn’t exist and throws). Returns a number[] (1536 dims for 3-small).runware.image("<air-id>"). generateImage returns { image } with image.base64 +
image.mediaType — build a data URL (data:${mediaType};base64,${base64}) or import to Wix Media.
In ai v7 the fn may be exported as experimental_generateImage; fall back to it if generateImage
is undefined.Runware via the SDK — model gotcha (verified):
google:4@2(Nano Banana) fails via the SDK (“Unknown Runware API error” — the Vercel provider injects params it rejects), even though it works on the raw REST proxy. Usebfl:5@1(FLUX.2 Pro) orrunware:100@1. Runware is also intermittently flaky — wrap image calls in a retry + model fallback (bfl:5@1→runware:100@1) so a transient blip doesn’t surface to the user.
Wiring to the browser: expose a server route (or action) that returns plain JSON and have the
browser fetch it — the AI runs in that route; the browser never touches the gateway.
import { generateText, streamText } from "ai";
import { openai, anthropic } from "@wix/ai";
const a = await generateText({ model: openai.responses("gpt-5.2"), prompt: "Invent a holiday." });
const b = await generateText({ model: anthropic("claude-sonnet-5"), prompt: "Tell me a story." });
// streamText(...) for token-by-token streaming to the client.import { embed, embedMany } from "ai";
import { openai } from "@wix/ai";
const model = openai.embeddingModel("text-embedding-3-small");
const { embeddings } = await embedMany({ model, values: products.map((p) => p.text) });
const { embedding } = await embed({ model, value: query });
// rank by cosine similarity; persist product vectors in a Wix Data collection to avoid re-embedding.GET /{provider}/v1/models is the source of truth. New provider models land on Wix a few days
after release; some ids are date-stamped. Tested-current picks (verify with /models):
gpt-5.2, gpt-5.2-pro, gpt-5.1, gpt-5, gpt-5-mini, gpt-5-nano, gpt-4.1,
gpt-4.1-mini, gpt-4.1-nano.text-embedding-3-small (1536), text-embedding-3-large, text-embedding-ada-002.claude-opus-4-8, claude-sonnet-5, claude-opus-4-7, claude-sonnet-4-6,
claude-haiku-4-5-20251001 — the dated id. claude-haiku-4-5 (undated) → 400 Unsupported model; use the dated id /models returns.Use REST if your backend isn’t JS/TS, or when you want the raw HTTP API. The gateway is a
transparent pass-through: base URL https://www.wixapis.com/{provider}/v1/... with the
provider’s native request/response bodies (model params, streaming, tool calls per the provider’s
own docs). Authenticate with the skill’s universal call shape (SETUP.md §1):
curl -sS -X POST "https://www.wixapis.com/openai/v1/chat/completions" \
-H "Authorization: Bearer $TOKEN" -H "wix-site-id: $SITE_ID" -H "Content-Type: application/json" \
-d '{"model":"gpt-5-nano","messages":[{"role":"user","content":"Write a 1-line product tagline"}]}'Endpoints: OpenAI POST /openai/v1/responses · /chat/completions · /embeddings; Anthropic
POST /anthropic/v1/messages.
-H "anthropic-version: 2023-06-01". Omitting it → 400 anthropic-version: header is required (the public doc’s curl example omits it — don’t copy that)."stream": true — response is SSE (data: lines), provider-native.wix-site-id is accepted-but-not-required for AI calls (the token is already site-scoped) — include
it for consistency with every other call in the skill.AI usage is billed to the site owner’s account, never to the end user. This is structural, not a setting:
Consequence: any AI feature exposed to end-users (a public chatbot, “generate my bio”, etc.) lets anonymous traffic drain the owner’s credits — and gives you no built-in way to attribute or cap usage per end-user. The platform will not solve this for you. The app must own a metering layer.
When AI is exposed to end-users, build these into the server boundary — don’t ship AI to end-users without them:
max_tokens/input size; large requests cost more credits.If the user wants true per-end-user AI budgets (e.g. “each member gets N generations/month”), that is an applicative feature to build — a usage-ledger collection keyed by member, enforced server-side — because Wix bills only the owner and offers no per-visitor pool. Call this out to the user rather than implying the platform meters end-users.
| Symptom | Cause → fix |
|---|---|
| Call rejected from the browser / with a visitor or member identity | Move the call server-side. AI never runs in the browser. |
403 Forbidden (server identity) | Building a Wix app: add the Invoke AI Models permission to the app (see the AI-APIs doc). |
400 anthropic-version: header is required | REST only — add -H "anthropic-version: 2023-06-01" (the SDK sets it for you). |
400 Unsupported model | Use the exact id from /{provider}/v1/models (Anthropic ids are often date-stamped, e.g. claude-haiku-4-5-20251001). |
Unknown Runware API error (images) | Transient, or the model rejects SDK params (google:4@2). Retry + fall back to bfl:5@1 / runware:100@1. |
| insufficient credits / quota | Account is out of AI credits — degrade soft; tell the owner. |
IMAGE_GENERATION.md — image generation (Runware) via the same gateway.dev.wix.com/docs/api-reference/articles/ai-tools/ai-apis/about-the-wix-ai-apis (+ …/set-up-the-wix-ai-sdk).