> This page is for Home.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developers.webflow.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developers.webflow.com/_mcp/server.

# Changelog

This is an overview of the changes to the Webflow APIs and related tools.
To filter the list, select one or more tags.

## Box element in the Designer API

> The new Box preset replaces seven legacy layout presets in the Designer API

The Designer API now includes a `Box` element preset. `Box` is a block element with a semantic HTML tag: `div`, `section`, `header`, `footer`, `nav`, `main`, `article`, `aside`, `address`, or `figure`.

## Creating Box elements

Use `webflow.elementPresets.Box` to create a Box element:

```typescript
const selectedElement = await webflow.getSelectedElement();

if (selectedElement?.children) {
  const box = await selectedElement.append(webflow.elementPresets.Box);

  if (box.type === 'Block') {
    await box.setTag('section');
  }
}
```

Creating an element by tag name also creates a Box element when you pass one of the 10 tags above, such as `element.append('div')` or `element.append('section')`.

## Deprecated presets

These presets still work but are deprecated. Use `Box` instead:

* `DivBlock`
* `Section`
* `BlockContainer`
* `Grid`
* `Row`
* `HFlex`
* `VFlex`

## Migrating from the Section preset

The `Section` preset no longer returns an element with the type `Section`. It now returns a `BlockElement` with the type `Block`, the same as `Box` and `DivBlock`.

If your app checks for `element.type === 'Section'` after creating an element with the `Section` preset, update the check to `Block`.

## Checking the HTML tag

A `Block` element can use any of the 10 tags, so the element type doesn't tell you the HTML element.
Narrow the element type, then use [`element.getTag()`](/designer/reference/get-tag) to read the tag. `getTag()` also works for custom elements.

```typescript
const element = await webflow.getSelectedElement();

if (element?.type === 'Block') {
  console.log(await element.getTag()); // for example, 'section'
}
```

For more information, see [Element presets](/designer/reference/element-presets) and [Get HTML tag](/designer/reference/get-tag).

## Detect empty slots with isEmptySlot

> Use isEmptySlot from @webflow/react to detect empty Slot props and render fallback content.

This update lets code component authors detect empty slots and render fallback content. Webflow now reserves prop names that start with `__wf_`.

**Packages:**

* `@webflow/react` `2.7.0`
* `@webflow/data-types` `2.6.0`

## Check for empty slots

Call [`isEmptySlot`](/code-components/reference/hooks/isEmptySlot) on a Slot prop value. It returns `true` when the slot has no children.

```tsx
import { isEmptySlot } from "@webflow/react";

<div>
  {content}
  {isEmptySlot(content) ? <p>Drop content here</p> : null}
</div>
```

Render fallback content next to the slot, not instead of it. Replacing the slot removes the Designer drop target.

Learn more in the [`isEmptySlot` reference](/code-components/reference/hooks/isEmptySlot).

## Reserved `__wf_` prop names

Webflow reserves prop names that start with `__wf_`, in any letter case. The CLI rejects a library that declares one when you bundle it. Rename the prop so it doesn't use that prefix.

## Update: AEO prompt executions no longer return competitorMentions

> List Prompt Executions and Get Prompt Execution no longer return the competitorMentions field.

The [List Prompt Executions](/data/v2.0.0-beta/reference/aeo-analytics/list-prompt-executions) and [Get Prompt Execution](/data/v2.0.0-beta/reference/aeo-analytics/get-prompt-execution) endpoints no longer return `competitorMentions`. The field was always an empty array. Remove it from any code or types that expect it. All other fields stay the same.

To see competitor citations, use [List Competitor Citations](/data/v2.0.0-beta/reference/aeo-analytics/list-competitor-citations).

## Update: Get Site Plan returns the Starter hosting plan and public plan names

> Get Site Plan now returns the site Starter hosting plan for Starter sites, and the public plan name in displayName.

The [Get Site Plan](/data/reference/sites/plans/get-site-plan) endpoint now returns the site's hosting plan consistently. This is a breaking change for any code that compares `id` or `displayName` against the previous values.

### Starter sites

Sites without a paid hosting plan used to return the Starter *workspace* plan. They now return the Starter *hosting* plan.

| Field         | Before                      | After                |
| ------------- | --------------------------- | -------------------- |
| `id`          | `workspace-starter-seat-v1` | `hosting-starter-v1` |
| `displayName` | `Starter Workspace`         | `Starter`            |

### Public plan names

`displayName` now returns the public plan name instead of the internal invoice name. As a result, the names of some plans change. For example, `Basic Hosting (circa 2016)` is now `Basic Hosting`, and `Enterprise` is now `Enterprise Hosting`.

## Update: Get Site Plan returns the Starter hosting plan and public plan names

> Get Site Plan now returns the site Starter hosting plan for Starter sites, and the public plan name in displayName.

The [Get Site Plan](/data/reference/sites/plans/get-site-plan) endpoint now returns the site's hosting plan consistently. This is a breaking change for any code that compares `id` or `displayName` against the previous values.

### Starter sites

Sites without a paid hosting plan used to return the Starter *workspace* plan. They now return the Starter *hosting* plan.

| Field         | Before                      | After                |
| ------------- | --------------------------- | -------------------- |
| `id`          | `workspace-starter-seat-v1` | `hosting-starter-v1` |
| `displayName` | `Starter Workspace`         | `Starter`            |

### Public plan names

`displayName` now returns the public plan name instead of the internal invoice name. As a result, the names of some plans change. For example, `Basic Hosting (circa 2016)` is now `Basic Hosting`, and `Enterprise` is now `Enterprise Hosting`.

## Update: Get Site Plan returns the Starter hosting plan and public plan names

> Get Site Plan now returns the site Starter hosting plan for Starter sites, and the public plan name in displayName.

The [Get Site Plan](/data/reference/sites/plans/get-site-plan) endpoint now returns the site's hosting plan consistently. This is a breaking change for any code that compares `id` or `displayName` against the previous values.

### Starter sites

Sites without a paid hosting plan used to return the Starter *workspace* plan. They now return the Starter *hosting* plan.

| Field         | Before                      | After                |
| ------------- | --------------------------- | -------------------- |
| `id`          | `workspace-starter-seat-v1` | `hosting-starter-v1` |
| `displayName` | `Starter Workspace`         | `Starter`            |

### Public plan names

`displayName` now returns the public plan name instead of the internal invoice name. As a result, the names of some plans change. For example, `Basic Hosting (circa 2016)` is now `Basic Hosting`, and `Enterprise` is now `Enterprise Hosting`.

## New: AEO Analytics API (beta)

> Read AEO analytics through the Data API — AI bot traffic, tracked prompts and their responses, visibility score, and citations.

The AEO Analytics API (beta) lets you read how AI bots visit your site, and how answer engines mention and cite you. AEO, or answer engine optimization, is the practice of improving how your content appears in AI-generated answers. It works with sites that have the AEO analytics entitlement.

### Bot traffic

* **[Get Bot Traffic](/data/v2.0.0-beta/reference/aeo-analytics/get-bot-traffic)** — total requests from the AI bots Webflow tracks, by provider or category
* **[Get Bot Traffic by Page](/data/v2.0.0-beta/reference/aeo-analytics/get-bot-traffic-by-page)** — the pages and files bots requested most

### Prompts

* **[List Prompts](/data/v2.0.0-beta/reference/aeo-analytics/list-prompts)** — your tracked prompts, with each one's topic and status
* **[List Prompt Executions](/data/v2.0.0-beta/reference/aeo-analytics/list-prompt-executions)** — answer engine responses to your prompts, with their mentions and citations
* **[Get Prompt Execution](/data/v2.0.0-beta/reference/aeo-analytics/get-prompt-execution)** — one response, including its full text

### Visibility

* **[Get Visibility Score](/data/v2.0.0-beta/reference/aeo-analytics/get-visibility-score)** — the share of responses that mention your organization
* **[Get Visibility Score Breakdown](/data/v2.0.0-beta/reference/aeo-analytics/get-visibility-score-breakdown)** — the visibility score for each topic or prompt

### Citations

* **[Get Citation Rate](/data/v2.0.0-beta/reference/aeo-analytics/get-citation-rate)** — the share of responses with citations that cited your domains
* **[Get Top Cited Domains](/data/v2.0.0-beta/reference/aeo-analytics/get-top-cited-domains)** — the domains cited most, with each one's share of all citations
* **[Get Cited Paths for a Domain](/data/v2.0.0-beta/reference/aeo-analytics/get-cited-paths-for-a-domain)** — the cited paths on one domain
* **[Get Page Citation Share](/data/v2.0.0-beta/reference/aeo-analytics/get-page-citation-share)** — one page's share of citations to your domains
* **[List Competitor Citations](/data/v2.0.0-beta/reference/aeo-analytics/list-competitor-citations)** — responses that cited a competitor and not you
* **[List Citations](/data/v2.0.0-beta/reference/aeo-analytics/list-citations)** — every response, with all its citations and mentions

All endpoints require the `sites:read` scope. Every endpoint except the two bot traffic endpoints also requires Webflow AI to be enabled for the workspace.

## New: AEO Analytics API (beta)

> Read AEO analytics through the Data API — AI bot traffic, tracked prompts and their responses, visibility score, and citations.

The AEO Analytics API (beta) lets you read how AI bots visit your site, and how answer engines mention and cite you. AEO, or answer engine optimization, is the practice of improving how your content appears in AI-generated answers. It works with sites that have the AEO analytics entitlement.

### Bot traffic

* **[Get Bot Traffic](/data/v2.0.0-beta/reference/aeo-analytics/get-bot-traffic)** — total requests from the AI bots Webflow tracks, by provider or category
* **[Get Bot Traffic by Page](/data/v2.0.0-beta/reference/aeo-analytics/get-bot-traffic-by-page)** — the pages and files bots requested most

### Prompts

* **[List Prompts](/data/v2.0.0-beta/reference/aeo-analytics/list-prompts)** — your tracked prompts, with each one's topic and status
* **[List Prompt Executions](/data/v2.0.0-beta/reference/aeo-analytics/list-prompt-executions)** — answer engine responses to your prompts, with their mentions and citations
* **[Get Prompt Execution](/data/v2.0.0-beta/reference/aeo-analytics/get-prompt-execution)** — one response, including its full text

### Visibility

* **[Get Visibility Score](/data/v2.0.0-beta/reference/aeo-analytics/get-visibility-score)** — the share of responses that mention your organization
* **[Get Visibility Score Breakdown](/data/v2.0.0-beta/reference/aeo-analytics/get-visibility-score-breakdown)** — the visibility score for each topic or prompt

### Citations

* **[Get Citation Rate](/data/v2.0.0-beta/reference/aeo-analytics/get-citation-rate)** — the share of responses with citations that cited your domains
* **[Get Top Cited Domains](/data/v2.0.0-beta/reference/aeo-analytics/get-top-cited-domains)** — the domains cited most, with each one's share of all citations
* **[Get Cited Paths for a Domain](/data/v2.0.0-beta/reference/aeo-analytics/get-cited-paths-for-a-domain)** — the cited paths on one domain
* **[Get Page Citation Share](/data/v2.0.0-beta/reference/aeo-analytics/get-page-citation-share)** — one page's share of citations to your domains
* **[List Competitor Citations](/data/v2.0.0-beta/reference/aeo-analytics/list-competitor-citations)** — responses that cited a competitor and not you
* **[List Citations](/data/v2.0.0-beta/reference/aeo-analytics/list-citations)** — every response, with all its citations and mentions

All endpoints require the `sites:read` scope. Every endpoint except the two bot traffic endpoints also requires Webflow AI to be enabled for the workspace.

## New: Optimize API (beta)

> Read Optimize optimizations and their results through the Data API — per-variation results, audience insights, performance over time, goals, and dimensions.

The Optimize API (beta) lets you read your optimizations and their results. It works with Webflow sites that have the Optimize add-on, and with non-Webflow sites that use Optimize.

### Optimize

* **[List Optimize IDs](/data/v2.0.0-beta/reference/optimize/list-optimize-ids)** — the `optimizeId` values your token can access, and the resource each one comes from
* **[List Optimizations](/data/v2.0.0-beta/reference/optimize/list-optimizations)** — each optimization's type, status, and intervals
* **[Get Optimization Results](/data/v2.0.0-beta/reference/optimize/get-optimization-results)** — each variation's sessions, users, conversions, and conversion rate for one goal
* **[Get Audience Insights](/data/v2.0.0-beta/reference/optimize/get-audience-insights)** — the same results, split by the segments of one dimension
* **[Get Performance Over Time](/data/v2.0.0-beta/reference/optimize/get-performance-over-time)** — the same results, by day or week
* **[List Optimization Goals](/data/v2.0.0-beta/reference/optimize/list-optimization-goals)** — an interval's goals, and which one is the target goal
* **[List Dimensions](/data/v2.0.0-beta/reference/optimize/list-dimensions)** — the dimensions you can group or filter reports by
* **[List Dimension Values](/data/v2.0.0-beta/reference/optimize/list-dimension-values)** — the values seen for a dimension, to use in filters

All endpoints require the `sites:read` scope. Webflow sites accept OAuth app tokens and Site API tokens. Non-Webflow sites accept only OAuth app tokens.

## New: Site Access and Workspace Members APIs

> Manage per-site access and workspace-wide membership programmatically — list, grant, change, and revoke Site Access, and list, invite, update, remove, and bulk-update Workspace Members.

Two new endpoint groups let you manage who has access to a Site or Workspace directly through the API, for Enterprise workspaces.

### Site Access

* **[List Site Members](/data/reference/enterprise/site-access/list-members)** — everyone with access to a Site and the role they hold
* **[Grant Site Access](/data/reference/enterprise/site-access/add-member)** — add a Workspace Member to a Site, by email or member ID
* **[Update Site Member Role](/data/reference/enterprise/site-access/update-member-role)** — change a Member's Site Role, by member ID or email
* **[Revoke Site Access](/data/reference/enterprise/site-access/remove-member)** — remove a Member's access to a Site, by member ID or email

### Workspace Members

* **[List Workspace Members](/data/reference/enterprise/workspace-members/list-members)** — Members and pending, declined, and expired invites
* **[Invite Workspace Member](/data/reference/enterprise/workspace-members/invite-member)** — invite by email, with a Workspace Role and either a default Site Role or per-Site access
* **[Update Workspace Member Role](/data/reference/enterprise/workspace-members/update-member-role)** — change a Member's Workspace Role and default Site Role
* **[Remove Workspace Member](/data/reference/enterprise/workspace-members/remove-member)** — remove a Member from the Workspace
* **[Bulk Update Workspace Member Roles](/data/reference/enterprise/workspace-members/bulk-update-member-roles)** — update up to 100 Members and invites in one request

## v2.9.0: Workspace folders for imported apps, and `devlink sync` removed

> webflow apps init --import --new can place a new app in a workspace folder with --folder-id. The removed webflow devlink sync command is gone for good, and the Server bundle manifest no longer lists components that don't render on the server.

v2.9.0 adds workspace folder placement when you import a Cloud app from GitHub, removes the leftover `webflow devlink sync` command, and fixes what the Server bundle's manifest lists.

### Place an imported app in a workspace folder

`webflow apps init --import --new` accepts a new `--folder-id` flag that puts the new standalone app in a workspace folder at creation time:

```bash
webflow apps init --import https://github.com/<owner>/<repo> --new --folder-id <folderId>
```

To find a folder's ID, open the folder in the dashboard and copy the value after `/folder/` in the URL. `--folder-id` only applies to new standalone apps, so it requires `--new` and can't be combined with `--site-id`.

### Fix: Server manifest no longer lists `ssr: false` components

The Server bundle's `wf-manifest.json` (`dist/Server/ssr-bundle.tar`) no longer lists components whose `options.ssr` is `false`. Its `components` map now matches the components actually imported into `Server/index.js`, instead of copying the Client bundle's full CSS index. The Client `wf-manifest.json` and `mf-manifest.json` are unchanged — they still list every component, including `ssr: false` ones, with their CSS.

### Removed: `webflow devlink sync`

The dead `webflow devlink sync` command is removed. Use [`webflow devlink export`](/cli/command-reference#devlink-export) instead. If you're upgrading an older project, see [Migrating to DevLink Export](/devlink/docs/reference/migrate-from-sync).

## Upgrading

```bash
npm install -g @webflow/webflow-cli@latest
```

## MCP v2.1: Interactions with GSAP, Webflow Cloud, and Campaigns

> Three new tools open to agents for the first time, a complete branch lifecycle, CMS field groups and custom-field filtering, and agent-generated instructions.

MCP v2.1 widens what agents can do on the Webflow platform. Three products open to agents for the first time, branch management becomes a complete loop, CMS collections gain field groups and custom-field filtering and sorting, and agents can now generate the instructions that guide their own work. No tool or action names changed, so anything built against v2.0.1 keeps working.

## New tools

MCP v2.1 introduces three new tools that open up areas of Webflow the MCP server couldn't reach before: Interactions with GSAP, Webflow Cloud, and Campaigns.

**Interactions with GSAP.** Agents can now bring pages to life with motion and interactivity. Interactions with GSAP is Webflow's visual animation tool, built on [GSAP](https://gsap.com/), the popular open source animation library, and MCP v2.1 opens it to agents for the first time. You keep complete authoring control over the result: an agent makes the first pass, and you tweak the details on the timeline and in the visual editor. Agents can now:

* **Create** an interaction from a complete definition, its triggers and its timelines, in a single call.
* Animate on **click**, **hover**, **page load**, **scroll**, **mouse move**, and **custom events**.
* **Update** an existing interaction, or **remove** one.
* **List** a site's interactions and **read** one with its timelines resolved.

**Webflow Cloud.** Agents can now take a broken deployment from error to fix without leaving the editor you work in. Webflow Cloud is Webflow's platform for building and hosting full-stack applications, and MCP v2.1 brings its apps, environments, and deployments into reach. An agent can read a failing build's logs, make the change, and redeploy, instead of you moving between the command line and the dashboard. Agents can now:

* **Create, list, and inspect apps** built from a GitHub repository, change an app's name, description, or source, and archive or permanently delete one.
* **Set up environments** that map a Git branch to a mount point on the app, then list, update, or delete them.
* **Deploy** the connected branch's latest commit, or **redeploy** an earlier deployment's exact commit to retry a failure or roll back.
* **Track deployments** by status, commit, build timings, build size, and framework, listed newest first.
* **Read build and runtime logs** to find out why a deploy failed or what an app is doing in production.
* **List environment variables**, which return values for non-secret entries only, and delete one by key.
* **List the custom domains** the app's site serves on.
* **Preview a destructive or deploy action with a dry run** before committing to it, and pass an idempotency key so a retried call does not deploy twice.

**Campaigns.** Agents can now help marketers get a campaign out the door. Campaigns is Webflow's new standalone tool for demand gen and performance marketers to create, launch, and measure on-brand campaigns with fewer handoffs, and MCP v2.1 opens it to agents from the start. An agent can turn a brief into a landing page, build personalized variations for each audience, and report on what the campaign did. Agents can now:

* **Find the sites** in a workspace that have Campaigns enabled, and list the campaigns on one.
* **Create a campaign and its landing page** from a markdown brief. The page generates in the background, and a task status action reports when it is finished.
* **Read and update a campaign's name and brief**, which does not regenerate the landing page, or delete a campaign along with its landing page record and generated assets.
* **Create page variations** from suggested audiences or from your own name, slug, and summary, then update up to 30 of them in a single call.
* **Personalize an element setting or a component instance prop** by creating a campaign field bound to it, then rename that field or remove it across every variation.
* **Measure a campaign** by daily sessions, users, or pageviews, form submission counts, the companies that engaged, and CRM opportunity totals for open and closed-won deals.

## Updates on existing tools

Two tools already in the server gained new actions or capabilities in v2.1:

* **`data_pages_tool`** adds the rest of the branch lifecycle. Alongside creating, listing, reading, and deleting branches, agents can now pull the latest changes from a site's main pages into a branch (`update_branch`), merge a branch back into main (`merge_branch`), publish a branch's preview to its staging domain (`publish_branch`), and read a branch's unresolved conflicts without attempting a merge (`get_branch_conflicts`). Branch actions require the site's workspace to be on an Enterprise plan, and the mutations run asynchronously, returning a task ID to poll with `get_branch_task_status`.
* **`data_cms_tool`** adds field groups and richer item queries. Agents can now read a collection's field groups along with the fields eligible for grouping (`get_collection_field_groups`), and replace the full ordered set (`update_collection_field_groups`) — a collection holds up to 50 groups, and field groups are not available on Ecommerce collections. `list_collection_items` can also filter and sort on custom fields: filter with bracket notation (`filter[price][gte]=10`), with operators that vary by field type (`eq`, `ne`, `in`, `nin`, `gt`/`gte`/`lt`/`lte` on numbers and dates, `contains`/`ncontains` on text, and `exists` everywhere), and sort with `sort[price]=desc` on sortable field types. A request allows up to 10 filter terms and 3 sort fields.

## Agent instructions

Agents can now write the guidance they work from. In v2.0, agents could search, read, create, update, move, and delete a site's rules and skills. MCP v2.1 adds generation, so an agent can produce an instruction from the site itself.

Four types can be generated: brand guidelines, design system, asset guidelines, and CMS guidelines. The first three read the current Webflow site by default and can take one public URL as supplementary evidence, which helps when the brand lives on a marketing site hosted elsewhere. CMS guidelines read a specific collection instead, and take no supplementary source.

Generation runs asynchronously: the first call returns a task ID, and the same action polls it until the job finishes or fails, at which point the result carries the draft's path and resource URI. Starting a generation needs `agent_instructions:write`, while polling needs only `agent_instructions:read`. Every generated instruction is saved as a draft, so review it before treating it as durable site guidance, since once in place it becomes context that every agent working on that site reads.

Generating an instruction consumes AI credits; polling does not. The credits are spent by the Webflow agents that analyze the site or collection and draft the instruction — the task status check is a plain read.

## Migrating from an earlier version

Nothing to do if you are already on v2.0.1. No tool or action names changed in v2.1, so skills, prompts, and automations written against 2.0.1 keep resolving, and everything in this release is additive.

## Known limitations

A few limitations to be aware of in this release:

* **Interactions with GSAP only.** Agents cannot see or edit Classic interactions. On a site that uses Classic, asking an agent for a site's interactions returns an empty result, which looks the same as a site that has none. An agent can still add an interaction there, which leaves the site running both versions but carries a performance cost. The Interactions panel shows one version at a time, so switch the version dropdown at the bottom of the panel to Interactions with GSAP to see what an agent created.
* **Webflow Cloud keeps secrets out of MCP.** Environment variable values cannot be set through MCP, and listing variables returns values for non-secret entries only. Set variables with the [Webflow CLI](/cli/reference/webflow-cli). Deployment through MCP works only on apps connected to a GitHub repository. Build and runtime logs are returned unsanitized and may contain secrets.
* **Campaigns is in Early Access.** The Campaigns tool works only on sites in the Early Access program. It covers building and measuring rather than launching: connecting marketing forms and pushing assets to ad platforms stay in the Campaigns interface. A published page variation cannot be deleted, and deleting a campaign permanently removes its landing page record and its generated assets.
* **Element snapshots still require the bridge app.** `element_snapshot_tool` captures a visual snapshot of an element, letting an agent understand the current state of a site and verify its own changes without publishing. This still depends on a live Designer session via the Webflow MCP Bridge App. We're working to make it headless, and until then we recommend letting the agent publish to a staging domain, which unlocks full agent loops that can run independently of the Designer.
* **Custom fonts don't cover remotely hosted Google or Adobe Fonts.** `data_fonts_tool` manages a site's uploaded font files only. Remotely hosted Google and Adobe Fonts must still be managed manually in site settings. For Google Fonts, you can download the font files locally and then upload and manage them through the MCP server.
* **Some uploads require direct access to Amazon S3.** Uploading an asset (`data_assets_tool.create_asset`) and uploading or replacing a custom font file (`data_fonts_tool.create_font` and `replace_font_file`) use a two-step flow: the tool returns a presigned Amazon S3 URL, and the client is expected to send the file's bytes directly to that URL. If the client's environment or network blocks outbound requests to S3, that second step cannot complete and the upload fails. When that happens, upload the file manually in Webflow (for example, the Designer's asset panel for assets, or site settings for fonts) rather than through the MCP server.
* **One workspace per authorization.** When you authorize the MCP server, you choose which workspace it can access, and only a single workspace can be selected. To use the MCP server with a different workspace, you will need to reauthenticate. In the case of Claude, OpenAI and others, this means removing the connector/app and reinstalling it.

## v2.8.0: `webflow apps`, the canonical namespace for Webflow Cloud

> A new webflow apps command family covers the full Webflow Cloud app lifecycle — init/deploy, environments, deployments, logs, and environment variables — with --json and --dry-run on every write, built for CI and AI agents as much as for humans.

v2.8.0 introduces `webflow apps`, the new canonical command namespace for managing Webflow Cloud apps. It replaces the piecemeal `webflow cloud` commands with one consistent surface across the whole app lifecycle, designed so a CI job or an AI agent can drive it end-to-end without scraping human-oriented output: structured `--json` on read commands, `--dry-run` previews on every write, and predictable exit codes throughout. Reads also retry transient rate limits (`429`) automatically with bounded backoff, so a busy CI runner doesn't need its own retry loop.

`webflow cloud init` and `webflow cloud deploy` keep working unchanged — they now print a one-time deprecation notice pointing at the `apps` equivalents.

An app is standalone by default — it gets its own subdomain and isn't tied to a Webflow site. Attaching to an existing site (mounted at a path, alongside a Designer-built site) is fully supported too; it's just one additional flag away.

### App lifecycle: `apps init` / `apps deploy`

```bash
# Standalone — the default. Owns its own subdomain, no Webflow site involved.
webflow apps init -n my-app -f astro --new -w <workspaceId>
webflow apps deploy -e main
```

Once `webflow.json` has an `app_id`, subsequent `apps deploy` calls need no flags at all — it's the standalone path that gets simpler over time, since there's no site or mount path to keep in sync.

`apps deploy` also takes `--dry-run` and `--json`, same as every other write in this namespace:

```bash
webflow apps deploy -e main --dry-run
webflow apps deploy -e main --json
```

`--dry-run` resolves everything from flags, `WEBFLOW_APP_ID`, and `webflow.json` — no network calls, no prompts, no changes — and reports which of `create` / `deploy` / `select` the real run would take. `--json` suppresses the build/upload progress output and emits a single document: `{appId, environmentId, deploymentId, deployUrl}` on success, an error document on failure, or the dry-run plan when combined with `--dry-run`.

Because `--json` means nobody is at the keyboard, it never opens a picker. A real deploy with `--json` therefore requires `--environment` and `--mount`, plus an identity it can resolve without asking — `--site-id`, `--workspace-id`, `WEBFLOW_SITE_ID`, or `siteId` in `webflow.json`. An invocation that would have prompted is refused up front with the flag to pass. A dry run needs none of these.

When creating a standalone app, `--access <everyone|restricted>` sets its site-specific access on `apps deploy` and on `apps init --import --new`. It is not accepted on the deprecated `webflow cloud` commands, and it is refused when the deploy targets an existing app.

Attaching to an existing Webflow site instead just adds `--site-id` and a `--mount` path at init:

```bash
# Site-attached — mounted at a path on an existing Webflow site.
webflow apps init -n my-app -f astro -s <siteId> -m /app
webflow apps deploy -e main --site-id <siteId> --mount /app
```

`apps init` also supports creating an app directly from an existing GitHub repository, either standalone or attached to a site:

```bash
webflow apps init --import https://github.com/<owner>/<repo> --new --dry-run
webflow apps init --import https://github.com/<owner>/<repo> --site-id <siteId> --mount /app --dry-run
webflow apps init --import https://github.com/<owner>/<repo> --new --skip-clone
webflow apps init --import https://github.com/<owner>/<repo> --branch staging --new --idempotency-key $GITHUB_RUN_ID-$REPOSITORY
```

The Webflow GitHub App must be installed on the repository and connected to your workspace. `--dry-run` previews the app that would be created; `--branch` picks which branch to build (defaults to the repository's default branch); `--skip-clone` creates the app from the remote repository without cloning it into a local directory. `--idempotency-key` is required for non-interactive runs (CI, `--no-input`) — reuse a retry-stable key unique to the repository and target so a retry replays the original app instead of creating a second one.

### Link an existing app: `apps link`

```bash
webflow apps link <appId> --workspace-id <workspaceId> --dry-run
```

Points the current directory at an app and environment that already exist by writing the resolved IDs into `webflow.json`. It only verifies the app — it doesn't create or deploy anything, so it's the fastest way to get a checked-out repo working with `apps deploy` / `apps env-vars` / `apps logs` against an app someone else created. A workspace ID is persisted only when `--workspace-id` is passed explicitly, since it can't be derived or verified from the app itself. Use `--dry-run` to preview.

### Inspect apps: `apps list` / `apps get` / `apps domains`

```bash
webflow apps list --json
webflow apps get <appId> --fields id,name,siteId,sourceUrl --json
webflow apps domains <appId>
```

`list` returns every app the token can see — standalone and site-attached alike — and optionally narrows with an exact `--site` or `--name`, or a case-insensitive substring `--q`; combine `--site` and `--name` to resolve to at most one app. All three support `--fields` to project columns and `--json` for machine-readable output.

### Manage apps: `apps update` / `apps delete`

```bash
webflow apps update <appId> --name "New name" --description "Internal tools dashboard" --dry-run --json
webflow apps update <appId> --github-source https://github.com/<owner>/<repo> --json
webflow apps delete <appId> --dry-run --json
webflow apps delete <appId> --yes --json
```

Update an app's name, description, and/or GitHub source (at least one of `--name` / `--description` / `--github-source` is required). `--github-source` attaches a repository to an app that has none, or repoints one that already has a different repo — it doesn't deploy on its own, so follow it with `apps deployments trigger`. `apps delete` deletes (archives) an app outright; it refuses to run non-interactively without `--yes` (a safe `--dry-run` preview is exempt).

Both commands preview with `--dry-run` before making any change, and both support `--json` on every path:

* `update --json` prints the plan (only the keys actually being changed, plus `dryRun: true`) on a dry run, and the full updated app object on a real run.
* `delete --json` prints one document shape on both the dry run and the real run — `{ appId, name, action: "archive" | "hard_delete", siteId, siteName, permanent, dryRun, message }` — so a caller can parse the same fields either way; `message` is `null` until the delete actually happens.

### Environments: `apps environments list/create/update/delete`

```bash
webflow apps environments list <appId> --branch main --json
webflow apps environments create <appId> --branch feature/checkout --mount /checkout --dry-run
webflow apps environments update <appId> <envId> --branch main --dry-run
webflow apps environments delete <appId> <envId> --dry-run
```

`list` filters by an exact `--branch` or a substring `--q` on branch name. `create` provisions a new environment bound to a branch and served at a mount path — it starts empty; run `apps deployments trigger` to build it. `update` changes an environment's branch and/or mount (at least one is required) but doesn't deploy the change itself. `delete` removes an environment. All three writes support `--dry-run`, and resolve the app/environment from positional args, `WEBFLOW_APP_ID` / `WEBFLOW_APP_ENVIRONMENT_ID`, `webflow.json`, or an interactive picker.

### Deployments: `apps deployments list/get/redeploy/trigger`

```bash
webflow apps deployments list --status failed --json
webflow apps deployments get <deploymentId> --wait --interval 10 --timeout 300 --json
webflow apps deployments trigger --wait --json
webflow apps deployments redeploy <deploymentId> --idempotency-key $GITHUB_RUN_ID --wait --json
```

`list --status` filters on an exact status (`success`, `failed`, `starting`, `building`, `deploying`, `canceled`, `unstaged`). `get --wait` polls until the deployment reaches a terminal status and exits `0`/`1` accordingly — built for CI gating; `--interval` and `--timeout` tune the poll (floored at 5s, capped at 30min). The default polling interval for deployment waits is now 20 seconds, up from 5.

`trigger` builds a GitHub-connected environment's current HEAD on demand; `redeploy` re-runs a past deployment at the same commit, the rollback path. Both require a GitHub-connected app (not eligible for apps deployed from local files via `apps deploy`) and now also take `--wait` (with the same `--interval`/`--timeout`): since enqueuing a build only returns a 202 with no deployment ID to poll, `--wait` identifies the new deployment itself and then blocks on it exactly like `deployments get --wait` — so a CI job can trigger a build and gate on its outcome in one command. All three writes support `--dry-run`.

### Logs: `apps logs build` / `apps logs runtime`

```bash
webflow apps logs build <deploymentId> --since <iso> --q <text>
webflow apps logs runtime [envId] --limit 200 --json
```

Both support `--fields`, `--json`, and cursor-based pagination via `--cursor`.

### Environment variables: `apps env-vars list/set/delete/import`

The headline addition this release: full, non-interactive management of Cloud app environment variables, so secrets no longer require a trip to the dashboard.

```bash
webflow apps env-vars list --fields key,isSecret --json
webflow apps env-vars list --q API --json
printf %s "$VALUE" | webflow apps env-vars set API_KEY --secret
webflow apps env-vars delete OLD_KEY --dry-run
webflow apps env-vars import .env --secret --dry-run
```

* `--app-id` / `--environment-id` default from `webflow.json` (`cloud.app_id` / `cloud.environment_id`) when present — as shown above — so most invocations inside a project directory need neither flag. Pass them explicitly (`--app-id <id> --environment-id <id>`) to target a different app, for example from a shared CI runner.
* `list` also takes an exact `--key` or a case-insensitive substring `--q`, same filtering pattern as `apps list` and `apps environments list`.
* `set <key> [value]` takes the value three ways, safest first: piped stdin (shown above — works in CI with no TTY), an interactive prompt (masked for secrets) if you omit the value entirely, or a positional argument. A positional secret still works but prints a warning, since it lands in your shell history and process list — stdin or the prompt avoid that.
* `--secret` marks a variable encrypted. **Secret values are never echoed back** — `set` on a secret confirms only that it was written, and `list` never returns a secret's value — it comes back masked. Non-secret values are hidden from the default output too, and shown only if you ask for them with `--fields value` or `--json`.
* `import <file>` bulk-loads a `.env` (or any `KEY=value`) file in one call instead of setting variables one by one. `--dry-run` parses and previews the resulting key set — secret values shown redacted — without making any API calls or writing anything.
* Every write command (`set`, `delete`, `import`) supports `--dry-run` and `--json`.

### Exit codes

Exit codes are now more specific, so scripts and agents can branch on why a command failed:

| Code  | Meaning                                                                                                                          |
| ----- | -------------------------------------------------------------------------------------------------------------------------------- |
| `0`   | Success                                                                                                                          |
| `1`   | Any other failure                                                                                                                |
| `2`   | A user-recoverable error you can fix yourself — bad input, a missing required flag, a resource locked by another process         |
| `3`   | An auth or permission failure — the API rejected the token (401/403), or the CLI has no valid session. Run `webflow auth login`. |
| `4`   | Rate limited                                                                                                                     |
| `5`   | A transient failure (5xx, 408, network) that exhausted its retries                                                               |
| `130` | Ctrl-C                                                                                                                           |

A script that only checks `$? -ne 0` sees no difference. One that checks `$? -eq 1` to mean "any failure" should switch to `$? -ne 0`.

With `--json`, error output also gains optional fields when available: `httpStatus`, `retryable`, `retryAfterMs`, `attempts`, `requestId`, and `authError`.

### Sign-in scope and session file

Logging in now requests one additional OAuth scope, `cloud_apps:read`, needed to read your Webflow Cloud apps. `webflow auth login` does nothing when a session already exists, so if you signed in before this release, run it once with `--force` to get a token that includes the new scope:

```bash
webflow auth login --force
```

`webflow auth login` and `logout` now write a v4 `auth.json` that separates the persistent default region from the stored session. An older CLI cannot read this shape — after downgrading, run `webflow auth login` again. A corrupt or unrecognized-version file now fails with a clear error naming the file, and `webflow auth logout` resets it.

On `@next` (beta) builds only, commands now honor the region you logged into. Stable `@latest` builds still route to the US region.

### Also in this release

* `apps init --site-id <id> --no-input` now correctly attaches the new app to the existing site and runs the DevLink export, instead of silently falling back to a standalone app without one.
* The `publicUrl` field on an environment (`apps environments list/create/update`) replaces the old `deployUrl` field name.
* Webflow Cloud Astro builds now keep the `build.*` options from your `astro.config.*` (for example `build.format` and `build.inlineStylesheets`) instead of discarding them. `build.assetsPrefix` is still owned by Webflow Cloud. `build.client`, `build.server`, and `build.serverEntry` are ignored with a build-log warning, because relocating Astro's output would break packaging.
* `webflow cloud deploy` no longer modifies your project's source `webflow.json` with deployment-generated metadata.
* `webflow skills install` now prints the exact command needed to resolve a blocked destination.
* `@webflow/react` 2.4.0 fixes a React 19 prerender abort race.
* `@webflow/functions` 2.4.0 extends `FunctionConfig` with an optional `access` (`public`).

## Upgrading

```bash
npm install -g @webflow/webflow-cli@latest
```

## New: AEO Recommendations API (beta)

> Document the beta AEO recommendations read surface — settings, list, get one, and summary.

The AEO Recommendations API (beta) is now documented for workspaces with the AEO recommendations entitlement.

### AEO recommendations

* **[Get Recommendation Settings](/data/v2.0.0-beta/reference/aeo-recommendations/get-settings)** — per-rule toggles and recurring audit state
* **[Update Recommendation Settings](/data/v2.0.0-beta/reference/aeo-recommendations/update-settings)** — partial update of settings
* **[List Recommendations](/data/v2.0.0-beta/reference/aeo-recommendations/list)** — filterable, cursor-paginated list
* **[Get Recommendations Summary](/data/v2.0.0-beta/reference/aeo-recommendations/summary)** — counts by status and priority
* **[Get Recommendation](/data/v2.0.0-beta/reference/aeo-recommendations/get)** — fetch one recommendation by id

## Webflow Cloud supports no-framework static apps

> Deploy plain HTML, CSS, and JavaScript apps on Webflow Cloud with no framework build step.

Webflow Cloud now supports no-framework static apps built with plain HTML, CSS, and JavaScript.

Use this path when your repository has no framework build step and you want to deploy committed files as static assets.

## Availability

* Requires `@webflow/webflow-cli` 2.4.0 or later.
* Deploy using `webflow cloud deploy`.

## Learn more

* [Static apps](/webflow-cloud/static-apps)
* [hello-world-static-app example](https://github.com/Webflow-Examples/hello-world-static-app)

## New: Branch API (beta)

> Document the Enterprise Branch API for page branching — list, create, update, merge, publish, delete, and async task polling.

The Branch API (beta) is now documented for Enterprise sites with page branching enabled.

### Branches

* **[Overview](/data/v2.0.0-beta/reference/enterprise/branches/overview)** — lifecycle, async tasks, conflicts, and entitlement requirements
* **[List Branches](/data/v2.0.0-beta/reference/enterprise/branches/list)** — paginated branch list with computed status and `nextActions`
* **[Create Branch](/data/v2.0.0-beta/reference/enterprise/branches/create)** — enqueue branch creation from a page
* **[Get Branch](/data/v2.0.0-beta/reference/enterprise/branches/get)** — single branch with status
* **[Delete Branch](/data/v2.0.0-beta/reference/enterprise/branches/delete)** — enqueue branch deletion (202 + task poll)
* **[Get Branch Conflicts](/data/v2.0.0-beta/reference/enterprise/branches/get-conflicts)** — unresolved style and component conflicts
* **[Update Branch](/data/v2.0.0-beta/reference/enterprise/branches/update)** — pull main changes into a branch
* **[Merge Branch](/data/v2.0.0-beta/reference/enterprise/branches/merge)** — merge a branch into main
* **[Publish Branch](/data/v2.0.0-beta/reference/enterprise/branches/publish)** — publish a branch preview to its staging domain
* **[Get Branch Task Status](/data/v2.0.0-beta/reference/enterprise/branches/get-task)** — poll async branch tasks

### Webhooks

* **`branch_created`**, **`branch_merged`**, and **`branch_deleted`** event schemas are documented under [All Events](/data/v2.0.0-beta/reference/all-events). Successful merges fire `branch_merged` only — not `branch_deleted`.

## `?translatable` on Get Page Content now filters component property overrides

> Get page content's translatable parameter now excludes a component instance's overridden property value when that property is excluded from translation, not just the whole page canvas.

**[Get page content](/data/reference/pages-and-components/pages/get-content)**'s `translatable` parameter previously only checked whether a page's entire canvas was excluded from translation. A component instance's overridden property values were always returned as-is, even when the specific property was excluded — inconsistent with [get component properties](/data/reference/pages-and-components/components/get-properties), which already filtered properties individually.

`translatable` now filters component property overrides the same way: an overridden value is omitted from a component instance's `propertyOverrides` if that property is excluded from translation for the requested locale. If a component instance's overrides are all excluded, the instance is omitted from the response entirely. A component instance with no overrides at all is unaffected.

Behavior that hasn't changed: only exclusion rules scoped to manual translation are respected, and omitting `translatable` returns the same response as before this parameter existed.

## v2.5.0: Global telemetry configuration and a code component crash fix

> webflow auth telemetry now writes global configuration by default, with a new --local flag for the old per-project behavior. @webflow/react also fixes a crash when a page combines code components built against different React major versions.

v2.5.0 changes where telemetry preferences are stored and fixes a crash affecting sites that combine code components from different sources.

### Global telemetry configuration

`webflow auth telemetry --enable/--disable` now writes to a global config file (`~/.config/webflow/telemetry.json` on macOS/Linux, `%APPDATA%\webflow\telemetry.json` on Windows) instead of the current project's `webflow.json`. Bare CLI invocations in a project without a manifest no longer create one just to record a telemetry preference.

A new `--local` flag opts back into the previous behavior for teams that want a per-project override:

```bash
webflow auth telemetry --disable --local
```

A `webflow.json` that already has a telemetry setting continues to be read and takes precedence over the global config for commands run in that directory. `DO_NOT_TRACK` continues to override everything.

### Fix: crash when combining code components from different sources

Fixed a crash — `Element type is invalid: expected a string ... but got: object` — that could occur when a published page loaded code components built against different React major versions. Upgrade `@webflow/react` to `2.1.1` and re-bundle libraries to pick up the fix.

### Also in this release

* Patched transitive `brace-expansion` and PostCSS dependencies addressing known vulnerabilities.
* `webflow cloud deploy` can now resolve its framework builder from a shared `@webflow/app` package when enabled server-side; the local `COSMIC_BUILD_ENGINE=v2|legacy` environment variable can override the selection for a single run.

## Upgrading

```bash
npm install -g @webflow/webflow-cli@latest
```

## v2.5.0: Global telemetry configuration and a code component crash fix

> webflow auth telemetry now writes global configuration by default, with a new --local flag for the old per-project behavior. @webflow/react also fixes a crash when a page combines code components built against different React major versions.

v2.5.0 changes where telemetry preferences are stored and fixes a crash affecting sites that combine code components from different sources.

### Global telemetry configuration

`webflow auth telemetry --enable/--disable` now writes to a global config file (`~/.config/webflow/telemetry.json` on macOS/Linux, `%APPDATA%\webflow\telemetry.json` on Windows) instead of the current project's `webflow.json`. Bare CLI invocations in a project without a manifest no longer create one just to record a telemetry preference.

A new `--local` flag opts back into the previous behavior for teams that want a per-project override:

```bash
webflow auth telemetry --disable --local
```

A `webflow.json` that already has a telemetry setting continues to be read and takes precedence over the global config for commands run in that directory. `DO_NOT_TRACK` continues to override everything.

### Fix: crash when combining code components from different sources

Fixed a crash — `Element type is invalid: expected a string ... but got: object` — that could occur when a published page loaded code components built against different React major versions. Upgrade `@webflow/react` to `2.1.1` and re-bundle libraries to pick up the fix.

### Also in this release

* Patched transitive `brace-expansion` and PostCSS dependencies addressing known vulnerabilities.
* `webflow cloud deploy` can now resolve its framework builder from a shared `@webflow/app` package when enabled server-side; the local `COSMIC_BUILD_ENGINE=v2|legacy` environment variable can override the selection for a single run.

## Upgrading

```bash
npm install -g @webflow/webflow-cli@latest
```

## `?translatable` now supported on Get Page Metadata

> The get page metadata endpoint now accepts a translatable parameter, matching the get page content, get component, and get CMS item endpoints.

**[Get page metadata](/data/reference/pages-and-components/pages/get-metadata)** now accepts `translatable`, alongside the endpoints that already supported it:

* **[Get page content](/data/reference/pages-and-components/pages/get-content)**
* **[Get component content](/data/reference/pages-and-components/components/get-content)** and **[get component properties](/data/reference/pages-and-components/components/get-properties)**
* **[List](/data/reference/cms/collection-items/staged-items/list-items)** and **[get](/data/reference/cms/collection-items/staged-items/get-item)** collection items, including their [live](/data/reference/cms/collection-items/live-items/list-items-live) counterparts

Pass the id of the secondary locale you're translating into to omit page-level fields (title, slug, SEO title/description, Open Graph title/description) excluded from translation for that locale — they're left out of the response entirely rather than returned as `null`. Behavior matches the other endpoints: the value must be a secondary locale id (`400` otherwise), and the request returns a `403` if translation exclusions aren't enabled for the site.

_Showing the 20 most recent of 163 entries. Append `/llms.txt` to the changelog URL for the complete index._