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

DevLink engine file structure update

When you re-export your site with DevLink, you’ll see updated import paths in your exported components. Your components should continue to work without any code changes on your part.

What you’ll see after re-exporting

Updated import paths

Your exported components will have updated import paths for built-in Webflow elements:

Before:

1import Block from "../_Builtin/Block";

After:

1import Block from "../webflow_modules/Basic/components/Block";

Import paths have changed from ../_Builtin/Block to ../webflow_modules/Basic/components/Block, but your component code remains exactly the same.

Deprecated barrel export removed

The deprecated index.js barrel export file has been removed. This file previously re-exported all DevLink modules with a performance warning.

If you were importing from index.js, you’ll need to update your imports to use specific file paths instead.

Your components still work

No component code changes required — your component code, props, and behavior remain exactly the same

Same export format — component and global CSS file structure is unchanged

Easy update — simply run webflow devlink sync to update your components with the new structure

What changed internally

DevLink engine files have been reorganized from a flat structure into organized folders:

  • All internal components moved to webflow_modules/ folder
  • Components grouped by category (Dropdown, Form, Navbar, etc.)
  • Helper functions grouped with their related components

⚠️ If you’ve customized or directly imported DevLink internal files, you may need to update your code.

Recommendation: Avoid importing DevLink internal files directly. If you do, be aware that these files are not part of the external API and are subject to breaking changes with future updates.

For more information, see What DevLink Exports.


April 15, 2026

Comments API: replies, user search, and webhook enrichment

Three additions to the Comments API that enable integrations to participate in comment threads and build richer comment notifications.

New endpoint: Create comment reply

The Create Comment Reply endpoint lets you post a reply to an existing comment thread programmatically.

  • Method: POST /beta/sites/{site_id}/comments/{comment_thread_id}/replies
  • Scope: comments:write
  • Author attribution: The reply is always attributed to the user who authorized the OAuth token.
  • Mentions: To @mention a user in a reply, include their user ID in double square brackets in the content, field such as [[userId]]. Use the new Search Users by Email endpoint to look up user IDs.

Creating a reply automatically fires the comment_created webhook.

New endpoint: Search users by email

The Search Users by Email endpoint lets you look up a workspace user by their exact email address, returning their Webflow user ID for use in comment @mentions.

  • Method: GET /beta/sites/{site_id}/comments/users?email={email}
  • Scope: comments:read
  • Search type: Exact email match only — no partial or fuzzy search.
  • Returns an empty array if no user with the specified email address is found.

Webhook enrichment: comment location data

The comment_created webhook payload now includes three new fields that identify where a comment is anchored on a page.

FieldTypeDescription
objectIdstringThe ID of the page or CMS collection item the comment is on
objectTypepage | cms-itemWhether the comment is on a page or a CMS item
elementIdstringThe ID of the DOM element the comment pin is attached to

The existing pageId field is unchanged; it always contains the containing page ID. For comments on CMS items, objectId is the item ID, while pageId is the template page.

These fields are additive. Existing webhook consumers are not affected.


Publishing individual pages

You can now publish an individual page instead of the entire site.

By default, the Publish Site endpoint continues to publish the entire site. However, you can now pass the ID of a single page in the pageId parameter to publish only that page.

In the case of publishing an individual page, the API publishes:

  • The HTML, JSON, and CSS for the selected pages
  • All locales for the selected pages
  • Page-specific JavaScript for the selected pages
  • An updated static manifest that includes the new or updated pages
  • An updates sitemap that includes the selected pages
  • And updates manifest.json file to support detail pages (collection templates)

Global resources that have changed since last publish continue to show the version that was on the page in the Designer when the page was published.

Example

To publish an individual page, include the ID of the page to publish:

$curl -X POST https://api.webflow.com/v2/sites/{site_id}/publish \
> -H "Authorization: Bearer <token>" \
> -H "Content-Type: application/json" \
> -d '{
> "customDomains": ["660c6449dd97ebc7346ac629"],
> "publishToWebflowSubdomain": true,
> "pageId": "64abc123def4567890abcde1"
> }'

To publish the full site as usual, omit pageId:

$curl -X POST https://api.webflow.com/v2/sites/{site_id}/publish \
> -H "Authorization: Bearer <token>" \
> -H "Content-Type: application/json" \
> -d '{
> "customDomains": ["660c6449dd97ebc7346ac629"],
> "publishToWebflowSubdomain": true
> }'

The response now includes a publishScope field to indicate whether the site or an individual page was published:

1{
2 "customDomains": [],
3 "publishToWebflowSubdomain": true,
4 "publishScope": "page"
5}

Webhooks

The Site Publish webhook event has a new publishScope field, which shows site if the entire site was published and page if an individual page was published. If this field is set to page, the pageId field shows the ID of the page.


MCP v1.2 - Elements, styles, variables, and more

Version 1.2 of the Webflow MCP server adds new element tools, expanded CSS coverage, full variable management, webhook support, and MCP Bridge App improvements. If you are already using the MCP server, your agents and prompts automatically use this new version.

Elements

  • Create more complex elements: Previously, the element builder could create nested elements only 3 levels deep, but now it can construct arbitrarily deep element trees in a single call. In addition, execution is faster and more element types are supported.

  • Before/after placement: Agents can now place elements before and after existing elements, giving them more precise control over where elements are inserted relative to their siblings.

  • Create elements from raw HTML: A new tool accepts a raw HTML string and converts it directly to Webflow elements.

  • Element query: A new query tool lets agents search and filter elements by type, class, tag, or attribute. Results are returned as a structured tree, not a flat array.

  • Cleaner get_all_elements response: The response is now a hierarchical tree with only essential data per node, reducing payload size.

  • Child depth control on get_selected_element: Agents can now control the number of levels of children returned when they retrieve an element by providing the depth parameter.

  • remove_element: Agents can now delete elements from the canvas.

Components

  • Component editor with slot support: A new component editor supports no depth limit and slot definition on edit, mirroring the capabilities of the updated element builder.

  • unregister_component: Agents can now remove a component from a site. The tool returns a clear error when the component does not exist or has active instances.

  • Read component instance slots: Agents can now read all slots defined on a component instance.

Styles

  • 500+ CSS properties: The Style tool now covers 500+ CSS properties. Properties that were previously unsupported no longer fail silently.

  • Improved style search: Style search now supports filtering by property, value, tag, and class name, returning more relevant results with less noise.

  • remove_style: Agents can now delete a style from a site. The tool returns a clear error when the style does not exist or is currently in use.

Variables

  • Custom variable creation: Agents can now create custom variables, including support for color-mix() and calc() expressions.

  • Read custom variables: Agents can now read all custom variables defined on a site, including their expressions and resolved values.

  • Search variables: A new search action on the Variable tool lets agents filter variables by name, type, or collection ID.

  • Rename and delete variables: Agents can now rename or delete variables. The tool returns a clear error when the variable does not exist or is currently in use.

Webhooks

  • data_webhook_tool: A new tool covers webhook management, including creating and deleting registrations for specific event trigger types.

Enterprise

  • list_site_activity: A new action on the Enterprise tool lets agents query site activity logs.

MCP Bridge App

  • Improved UI and observability: The MCP Bridge App now surfaces tool execution stages, status, and timing in real time. Agents and engineers can view tool arguments and responses, export logs, and access quick links for common debugging actions.

  • Improved heartbeat: The heartbeat interval is reduced to prevent premature timeouts. Agents are notified on connection loss and can reconnect without losing state.

Bug fixes

  • Asset: corrupt asset silent failure: Tools that accept asset IDs now return a clear error when the asset does not exist, instead of failing silently. This update applies across all tools.

  • CMS: locale ID required error: Fixed an error where the CMS tool incorrectly required a locale ID in contexts where it was not needed.

  • Site: custom domain required error on publish: Fixed an error where publishing failed when no custom domain was set on the site.

  • Styles: combo class creation bug: Creating a combo class when the base class already exists no longer fails. This behavior now matches the expected in-product behavior.

Resources


March 27, 2026

New component methods

These new functions are now available in the Designer API:

Beta

These methods are in public beta and may change with future releases.

Getting the selected component

You can now retrieve the component that is currently being edited with the new webflow.getCurrentComponent() function (Beta). If no component is being edited, the method returns null.

1const component = await webflow.getCurrentComponent();
2if (component) {
3 const name = await component.getName();
4 console.log(`Currently editing component: ${name}`);
5 // Example: get all elements inside the active component
6 const root = await component.getRootElement();
7 const children = await root.getChildren();
8 console.log(`Root has ${children.length} child element(s)`);
9} else {
10 console.log('Not currently editing a component.');
11}

For more information, see Get the selected component.

Getting an element’s parent component

You can now retrieve the component that directly contains a given element with the new element.getParentComponent() function (Beta). If the element is not inside a component, the method returns null.

1const element = await webflow.getSelectedElement();
2if (element) {
3 const parentComponent = await element.getParentComponent();
4 if (parentComponent) {
5 const name = await parentComponent.getName();
6 console.log(`Element is inside component: ${name}`);
7 } else {
8 console.log('Element is not inside a component.');
9 }
10}

For more information, see Get the parent component.

Getting and setting component settings

The new component.getSettings() and component.setSettings() functions let you read and update a component’s name, group, and description in a single call:

1const components = await webflow.getAllComponents();
2const component = components[0];
3
4// Read all settings at once
5const settings = await component.getSettings();
6console.log(settings.name); // 'Hero Section'
7console.log(settings.group); // 'Sections'
8console.log(settings.description); // 'A reusable hero with heading and CTA'
9
10// Update only the description
11await component.setSettings({
12 description: 'Updated hero layout with video background',
13});
14
15// Update all settings at once
16await component.setSettings({
17 name: 'Hero Section v2',
18 group: 'Sections',
19 description: 'Redesigned hero component',
20});

For more information, see:


March 24, 2026

Search for Components

You can now use the webflow.searchComponents(options) method (Beta) to search for Components by name or description. If you don’t provide a search parameter, the method returns all Components. If you provide a string search parameter as in the following example, the method returns Components with matching names or descriptions.

1// Get all Components
2const allComponents = await webflow.searchComponents();
3/*
4[
5 {
6 id: 'xxxx',
7 name: 'Hero section',
8 group: 'Sections',
9 description: 'Lorem ipsum',
10 instances: 3,
11 canEdit: true,
12 library: null,
13 },
14 {
15 id: 'yyyy',
16 name: 'Nav Bar',
17 group: 'Navigation',
18 description: '',
19 instances: 5,
20 canEdit: false,
21 library: { name: 'Core Library', id: 'lib_123' },
22 },
23]
24*/
25
26// Search for Components by query
27const heroes = await webflow.searchComponents({ q: 'Hero' });
28/*
29[
30 {
31 id: 'xxxx',
32 name: 'Hero section',
33 group: 'Sections',
34 description: 'Lorem ipsum',
35 instances: 3,
36 canEdit: true,
37 library: null,
38 },
39]
40*/
Beta

These methods are in public beta and may change with future releases.

For more information, see Search for Components.


March 18, 2026

Open a canvas

You can now programmatically open a Component’s canvas or navigate to a page with the new webflow.openCanvas() method (Beta).

1// Open a component canvas by ID
2await webflow.openCanvas({ componentId: 'component-id' });
3
4// Open a component canvas by reference
5const components = await webflow.getAllComponents();
6await webflow.openCanvas(components[0]);
7
8// Navigate to a page by ID
9await webflow.openCanvas({ pageId: 'page-id' });
Beta

These methods are in public beta and may change with future releases.

Previously, Designer Extensions and MCP agents that needed to modify a Component’s internal structure had to rely on the user manually navigating to the component canvas. The openCanvas() method removes that manual step and enables fully automated Component workflows.

openCanvas() accepts a Component ID, a Component reference, or a ComponentElement (instance) reference to open the component canvas. It also accepts a page ID or Page reference to navigate to a page — equivalent to calling webflow.switchPage().

For more information, see Open a canvas.


March 17, 2026

Updates to components API

These new and updated functions are now available in the Designer API:

Beta

These methods are in public beta and may change with future releases.

Retrieving a component by name

You can now retrieve a component by its name and optionally its group with the new webflow.getComponentByName() function (Beta):

1// Fetch a component by name only
2const heroSection = await webflow.getComponentByName('Hero');
3console.log(heroSection.id);
4
5// Fetch a component scoped to a group
6const marketingHero = await webflow.getComponentByName('Marketing', 'Hero');
7console.log(marketingHero.id);

For more information, see Get component by name (Beta).

Getting component variants

The new functions component.getVariants() and component.getSelectedVariant() get the variants of a component and the selected variant of a component, as in these examples:

1const component = (await webflow.getAllComponents())[0];
2const variants = await component.getVariants();
3console.log(variants);
4// [
5// { id: 'base', name: 'Primary', isSelected: true },
6// { id: 'xxxx', name: 'Secondary', isSelected: false },
7// ]
8// Find which variant the user is currently editing
9const activeVariant = variants.find(v => v.isSelected);
10console.log(`Currently editing: ${activeVariant?.name}`);
1const selectedVariant = await heroComponent.getSelectedVariant();
2/*
3{
4 id: 'variant-123',
5 name: 'Secondary Hero',
6 isSelected: true,
7}
8*/
9// When no variant is explicitly selected, returns base
10const base = await heroComponent.getSelectedVariant();
11/*
12{
13 id: 'base',
14 name: 'Primary',
15 isSelected: true,
16}
17*/

For more information, see:


March 16, 2026

Updates to components and elements API

These new and updated functions are now available in the Designer API:

Also, these functions are updated to accept a tag name such as div, h2, or section instead of only a component or element preset:

Beta

These methods are in public beta and may change with future releases.

Creating functions without passing a root element

You can now create a component with the webflow.registerComponent() function without passing a root element. Instead, you can pass an object with the name for the new component and optionally a group and description, as in this example:

1// Create a hero component in the Sections group that is not within an existing element
2const hero = await webflow.registerComponent({
3 name: 'Hero Section',
4 group: 'Sections',
5 description: 'A reusable hero section with heading and CTA',
6});

For more information, see Create a component.

Getting components by ID

Previously, to access a component in the Designer API, you had to get a list of components with the webflow.getAllComponents() function and filter by ID. Now you can use the webflow.getComponent(id) function to get a component by its ID, as in this example:

1const componentId = '4a669354-353a-97eb-795c-4471b406e043';
2const component = await webflow.getComponent(componentId);
3console.log(component.id); // '4a669354-353a-97eb-795c-4471b406e043'
4
5const componentName = await component.getName();
6console.log(componentName); // 'Component Name'

For more information, see Get component by ID.

Getting the number of instances of a component

You can now get the total number of instances of a component across an entire site with the webflow.getInstanceCount() function:

1// Audit component usage across the site
2const components = await webflow.getAllComponents();
3for (const component of components) {
4 const name = await component.getName();
5 const count = await component.getInstanceCount();
6 console.log(`${name}: ${count} instances`);
7}
8// Guard against removing a component that's still in use
9const hero = components[0];
10const instanceCount = await hero.getInstanceCount();
11if (instanceCount > 0) {
12 console.log(`Cannot safely remove — ${instanceCount} instances exist`);
13} else {
14 await webflow.unregisterComponent(hero);
15}

For more information, see Get component instance count.

Inserting elements by tag name

Previously, when you used one of these functions to insert an element, you had to pass a component object or a preset from the webflow.elementPresets object:

  • element.before(newElement)
  • element.after(newElement)
  • element.prepend(newElement)
  • element.append(newElement)

Now, you can pass an element to create by the name of the tag, such as div, h2, or section, as in these examples:

1// Get Selected Element
2const selectedElement = await webflow.getSelectedElement();
3
4if (selectedElement) {
5 // Insert DIV after selected Element
6 const newDiv = await selectedElement.after('div');
7
8 // Print element details
9 console.log(`${JSON.stringify(newDiv)}`);
10}

For more information, see:


Renaming exported custom attributes

Similar to how it renames exported components and props, DevLink now renames or filters out exported custom attributes to ensure that the exported React code is valid.

  • HTML5 standard names such as tabindex and maxlength are capitalized according to React standards, in this example tabIndex and maxLength
  • Attributes that have a React equivalent, such as class and for, are converted to the React equivalent, in this example className and htmlFor
  • Attributes that match event handler names such as onClick and onMouseOver are filtered out, regardless of case
  • Attributes that start with numbers are filtered out
  • Attributes that are incomplete, such as data- and aria- are filtered out
  • Attributes named with an empty string are filtered out
  • Attributes containing invalid characters, such as my-😀-attr, are filtered out
  • Any other invalid HTML5 attributes are filtered out

DevLink prints a warning to your CLI console, and adds JSDoc Invalid Attribute comments, when it filters out attributes due to these rules, except when removing attributes with an empty string as their name. For example, this exported code shows a warning about a custom attribute that was filtered out:

1/**
2 * ComponentWithInvalidAttributes
3 *
4 * @warning
5 * The component could not be fully exported:
6 * - Invalid attribute: \`onClick\`
7 */
8export function ComponentWithInvalidAttributes() {
9 return <Builtin.Block tag="div" data-testid="my-block" aria-label="My Block" />;
10}

For more information, see What DevLink Exports.