# Table of Contents - [Authentication — Webflow API Documentation](#authentication-webflow-api-documentation) - [Site Token — Webflow API Documentation](#site-token-webflow-api-documentation) - [Introduction — Webflow API Documentation](#introduction-webflow-api-documentation) - [Rate Limits — Webflow API Documentation](#rate-limits-webflow-api-documentation) - [Migrating to v2 — Webflow API Documentation](#migrating-to-v2-webflow-api-documentation) - [Versioning — Webflow API Documentation](#versioning-webflow-api-documentation) - [Scopes — Webflow API Documentation](#scopes-webflow-api-documentation) - [Structure — Webflow API Documentation](#structure-webflow-api-documentation) - [Webflow v1 API Deprecation Notice — Webflow API Documentation](#webflow-v1-api-deprecation-notice-webflow-api-documentation) - [SDKs — Webflow API Documentation](#sdks-webflow-api-documentation) - [OAuth — Webflow API Documentation](#oauth-webflow-api-documentation) - [Get Authorization User Info — Webflow API Documentation](#get-authorization-user-info-webflow-api-documentation) - [Field Types & Item Values — Webflow API Documentation](#field-types-item-values-webflow-api-documentation) - [Getting started with Webflow Apps — Webflow API Documentation](#getting-started-with-webflow-apps-webflow-api-documentation) - [Create Webhook — Webflow API Documentation](#create-webhook-webflow-api-documentation) - [List Webhooks — Webflow API Documentation](#list-webhooks-webflow-api-documentation) - [Get Authorization Info — Webflow API Documentation](#get-authorization-info-webflow-api-documentation) - [Get Custom Domains — Webflow API Documentation](#get-custom-domains-webflow-api-documentation) - [Get Site — Webflow API Documentation](#get-site-webflow-api-documentation) - [List Sites — Webflow API Documentation](#list-sites-webflow-api-documentation) - [Remove Webhook — Webflow API Documentation](#remove-webhook-webflow-api-documentation) - [Publish Site — Webflow API Documentation](#publish-site-webflow-api-documentation) - [Get Webhook — Webflow API Documentation](#get-webhook-webflow-api-documentation) - [Register an App — Webflow API Documentation](#register-an-app-webflow-api-documentation) - [All Events — Webflow API Documentation](#all-events-webflow-api-documentation) - [FAQs and Troubleshooting — Webflow API Documentation](#faqs-and-troubleshooting-webflow-api-documentation) - [Working with Custom Code — Webflow API Documentation](#working-with-custom-code-webflow-api-documentation) - [Data Clients — Webflow API Documentation](#data-clients-webflow-api-documentation) - [Working with the CMS — Webflow API Documentation](#working-with-the-cms-webflow-api-documentation) - [Getting Started — Webflow API Documentation](#getting-started-webflow-api-documentation) - [Design Guidelines — Webflow API Documentation](#design-guidelines-webflow-api-documentation) - [Working with Assets — Webflow API Documentation](#working-with-assets-webflow-api-documentation) - [Getting Started — Webflow API Documentation](#getting-started-webflow-api-documentation) - [Hybrid Apps — Webflow API Documentation](#hybrid-apps-webflow-api-documentation) - [Working with Localization — Webflow API Documentation](#working-with-localization-webflow-api-documentation) - [User Authentication with ID Tokens — Webflow API Documentation](#user-authentication-with-id-tokens-webflow-api-documentation) - [Deep linking — Webflow API Documentation](#deep-linking-webflow-api-documentation) - [Localizing Components (Beta) — Webflow API Documentation](#localizing-components-beta-webflow-api-documentation) --- # Authentication — Webflow API Documentation In this guide, we’ll walk you through the options for authenticating requests to the Webflow API, including the different methods available and how to choose the best approach for your needs. ### Why authentication is important Authentication is a critical aspect of interacting with the Webflow API. It ensures that every request is secure and properly authorized, protecting both user data and the integrity of the platform. Here are the key reasons why authentication is essential: * **Identity verification** Authentication verifies the identity of the user or App making the request. This ensures that only authorized entities can access Webflow data. * **Access control** It ensures that the requester has the necessary permissions to perform the desired actions. This prevents unauthorized access and modifications to sensitive data. * **Data protection** By securing API requests, authentication helps protect user data from malicious activities. It ensures that data is accessed and modified only by those who are permitted. Getting a token --------------- To access the Webflow API, you need to authenticate your requests using a bearer token, which must be included in the authorization header of each API request. There are types of bearer tokens you can create: [Site Tokens](/v2.0.0/data/reference/site-token) and [OAuth tokens](/v2.0.0/data/reference/oauth-app) . Each method is suited to different use cases, and choosing the right one depends on your specific needs. [](/v2.0.0/data/reference/site-token) [![](https://dhygzobemt712.cloudfront.net/Icons/Dark/48px/KPIs.svg)![](https://dhygzobemt712.cloudfront.net/Icons/Light/48px/KPIs.svg)](/v2.0.0/data/reference/site-token) [Site Token](/v2.0.0/data/reference/site-token) [Site Tokens provide a simple way to authenticate API requests for a specific Webflow site.\ \ \ \ **When to use** \ Best suited for internal tools and single-site integrations where you control the environment.](/v2.0.0/data/reference/site-token) [Get a Site Token](/v2.0.0/data/reference/site-token) [](/v2.0.0/data/reference/oauth-app) [![](https://dhygzobemt712.cloudfront.net/Icons/Dark/48px/App.svg)![](https://dhygzobemt712.cloudfront.net/Icons/Light/48px/App.svg)](/v2.0.0/data/reference/oauth-app) [OAuth](/v2.0.0/data/reference/oauth-app) [OAuth Tokens are used for complex integrations that span multiple sites or require user-specific access.\ \ \ \ **When to use** \ Ideal for public integrations, Apps in the Webflow Marketplace, or any scenario requiring secure, user-specific access.](/v2.0.0/data/reference/oauth-app) [Get OAuth Token](/v2.0.0/data/reference/oauth-app) ##### Quickstart Tip If you’re eager to explore the API without setting up full authentication, use our API playground available in the [API reference.](https://developers.webflow.com/data/reference/sites/list) Authenticate once and make requests directly from the documentation. Sending a request ----------------- Sending a request to the Webflow API v2 is straightforward. Include your bearer token in the Authorization header: cURL ` | | | | --- | --- | | 1 | curl --request GET \ | | 2 | --url https://api.webflow.com/v2/sites \ | | 3 | --header 'accept: application/json' \ | | 4 | --header 'authorization: Bearer YOUR_TOKEN' | ` Replace `YOUR_TOKEN` with your actual API token. This setup authenticates your request, allowing access to Webflow resources. For information on handling responses, including potential errors, please refer to our [Error Handling](/v2.0.0/data/docs/working-with-webhooks#failure-conditions) section. Revoking a token ---------------- To maintain the security of your integration, it’s important to revoke access tokens when they are no longer needed or if you suspect they have been compromised. Revoking a token immediately invalidates it, ensuring that it can no longer be used to access the Webflow API. You can revoke tokens programmatically through the Webflow API or manage them directly within the Webflow dashboard. ###### Site Token ###### OAuth Token Webflow users can remove Site Tokens from the Site Settings. This ensures that unused tokens are securely revoked. ![Site Token Removal](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/2457dbd-Screenshot_2024-07-31_at_6.13.34_PM.png) Securing and storing your API tokens ------------------------------------ When working with the Webflow API, safeguarding your API tokens is critical to maintaining the security and integrity of your application. API tokens are like passwords for your application—they provide access to sensitive data and actions. Protecting them is essential to prevent unauthorized use and potential security breaches. ### Best practices for token security 1. **Use environment variables** Store API tokens in environment variables rather than in your source code. This reduces the risk of accidentally exposing tokens, especially if your code is shared or made public. 2. **Regular token rotation and revocation** Regularly rotate your API tokens to minimize risk. If you suspect a token has been compromised, revoke it immediately and generate a new one. Troubleshooting --------------- Despite best efforts, issues with API tokens can still occur. Here are common pitfalls and tips to resolve them: ###### Expired or invalid tokens * Implement a system to refresh tokens automatically before they expire, or prompt users to re-authenticate. * Check token validity and handle expired tokens gracefully in your application. ###### Scope and permission errors * Ensure your tokens include the correct scopes for the actions you intend to perform. Review the Webflow API documentation for an API endpoint to verify required scopes. #### Debugging tips * Log and review error messages to identify where the authentication process is breaking down. * Start with minimal scopes to test and gradually increase permissions as needed. * Verify that your requests include the authorization header with the token. [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Site Token — Webflow API Documentation A site token is a unique identifier that provides access to site-specific information via the Webflow Data API. When making a request, you’ll need to authenticate your request with an access token. Similar to a password, a site token (also known as an “API key” or “access token”) identifies the entity making a request to an API, as well as actions that entity can perform through its [scopes and permissions.](https://developers.webflow.com/data/reference/scopes) Creating a site token --------------------- **Note:** Only site administrators are authorized to create a site token. If you’re not a site administrator, please contact one to create the token for you. 1. Go to Site settings > Apps & integrations > API access. ![](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/d504f6c-image.png) 2. Click Generate token. 3. Enter a name for your API token. 4. Choose the permissions you want the API token to have for each of Webflow’s APIs (i.e., no access, read-only, or read and write). ![](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/67976fe-image.png) 5. Click Generate token. 6. Copy the generated token to your clipboard. ### Limitations * **API tokens expire after 365 consecutive days of inactivity.** Any API call made with the token before expiry will reset the inactivity period. * **Site tokens are created per site.** If you’re looking to build an integration that works across multiple sites, [consider creating a Webflow App.](https://developers.webflow.com/data/docs/getting-started-apps) * **Each site can have up to 5 tokens.** This limit ensures manageable token access and security. * **Site tokens do not grant access to the following endpoints:** * Authorization endpoints * Custom code endpoints Using a site token ------------------ Now that you have your site token, you can start making requests to the Webflow Data APIs. ###### cURL ###### JavaScript ###### Python The simplest way to make a request is by using cURL **Example** ` | | | | --- | --- | | 1 | curl --request GET \ | | 2 | --url https://api.webflow.com/v2/sites \ | | 3 | --header 'accept: application/json' \ | | 4 | --header 'authorization: Bearer YOUR_API_TOKEN' | ` This command retrieves a list of sites associated with your Webflow account. Replace `YOUR_API_TOKEN` with the site token you generated. ### Example API Response Here’s an example of what a response from the Webflow API might look like: Response ` | | | | --- | --- | | 1 | { | | 2 | "id": "42e98c9a982ac9b8b742", | | 3 | "workspaceId": "42e63e98c9a982ac9b8b742", | | 4 | "displayName": "The Hitchhiker's Guide to the Galaxy", | | 5 | "shortName": "hitchhikers-guide", | | 6 | "previewUrl": "https://screenshots.webflow.com/sites/6258612d1ee792848f805dcf/20231219211811_d5990556c743f33b7071300a03bf67e6.png", | | 7 | "timeZone": "Magrathea/FactoryFloor", | | 8 | "createdOn": "1979-10-12T12:00:00.000Z", | | 9 | "lastUpdated": "2023-04-02T12:42:00.000Z", | | 10 | "lastPublished": "2023-04-02T12:42:00.000Z", | | 11 | "parentFolderId": "1as2d3f4g5h6j7k8l9z0x1c2v3b4n5m6", | | 12 | "customDomains": [ | | 13 | { | | 14 | "id": "589a331aa51e760df7ccb89d", | | 15 | "url": "hitchhikersguide.galaxy" | | 16 | }, | | 17 | { | | 18 | "id": "589a331aa51e760df7ccb89e", | | 19 | "url": "heartofgold.spaceship" | | 20 | } | | 21 | ], | | 22 | "locales": { | | 23 | "value": { | | 24 | "primary": { | | 25 | "id": "653fd9af6a07fc9cfd7a5e57", | | 26 | "cmsLocaleId": "653ad57de882f528b32e810e", | | 27 | "enabled": false, | | 28 | "displayName": "English (United States)", | | 29 | "displayImageId": null, | | 30 | "redirect": true, | | 31 | "subdirectory": "", | | 32 | "tag": "en-US" | | 33 | }, | | 34 | "secondary": [ | | 35 | { | | 36 | "id": "653fd9af6a07fc9cfd7a5e56", | | 37 | "cmsLocaleId": "653fd9af6a07fc9cfd7a5e5d", | | 38 | "enabled": true, | | 39 | "displayName": "French (France)", | | 40 | "displayImageId": null, | | 41 | "subdirectory": "fr-fr", | | 42 | "tag": "fr-FR" | | 43 | }, | | 44 | { | | 45 | "id": "654112a3a525b2739d97664c", | | 46 | "cmsLocaleId": "654112a3a525b2739d97664f", | | 47 | "enabled": true, | | 48 | "displayName": "Spanish (Mexico)", | | 49 | "displayImageId": null, | | 50 | "subdirectory": "es-mx", | | 51 | "tag": "es-MX" | | 52 | } | | 53 | ] | | 54 | } | | 55 | } | | 56 | } | ` ### Best Practices * **Mint tokens for each use case**: Instead of reusing tokens, generate a new token for each specific use case to maintain better security and control. * **Rotate tokens periodically**: Regularly update and revoke old tokens to maintain security. * **Be Descriptive**: Name your tokens something descriptive and meaningful to easily identify their purpose. * **Minimal Scopes**: Generate tokens with the minimal scopes needed for your use case. Mint a new one if you need to add new scopes. This limits the potential impact if a token is compromised. Revoking a site token --------------------- Revoking a site token is an additional security measure for your Webflow site. This process disables the token, preventing any further access or use. You should consider revoking a site token in the following situations: * **Security Concerns:** If there’s a potential security issue, revoke the token immediately. * **Administrator Changes:** If an administrator leaves or their role changes, revoke their token to maintain security. * **Token Management:** Regularly review and revoke tokens that are no longer needed. To create a site token: 1. Go to Site settings > Apps & integrations > API access. 2. Find your API Key 3. Select the “revoke” button ![](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/4d03d0a-image.png) Troubleshooting and FAQs ------------------------ ###### How long is a site token valid? Site tokens are valid until they are manually revoked or after 365 days of inactivity. ###### Can I regenerate a site token? Yes, you can generate a new token at any time from the API access section in your site settings. ###### What happens if I lose my site token? You will need to generate a new one and update any integrations using the old token. [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Introduction — Webflow API Documentation Welcome to Webflow, the world’s leading visual development platform for building powerful websites without writing code. This documentation is designed for developers looking to create advanced tools and applications for Webflow users by using an extensive set of RESTful APIs. Start building -------------- [](/v2.0.0/data/reference/sites/list) [![](https://dhygzobemt712.cloudfront.net/Icons/Dark/48px/CodeBrackets.svg)![](https://dhygzobemt712.cloudfront.net/Icons/Light/48px/CodeBrackets.svg)](/v2.0.0/data/reference/sites/list) [Make your first API call](/v2.0.0/data/reference/sites/list) [](/v2.0.0/data/reference/sites/list) [Use the interactive API reference to make an API request directly from the docs.](/v2.0.0/data/reference/sites/list) [Call the API](/v2.0.0/data/reference/sites/list) [](/v2.0.0/data/reference/site-token) [![](https://dhygzobemt712.cloudfront.net/Icons/Dark/48px/KPIs.svg)![](https://dhygzobemt712.cloudfront.net/Icons/Light/48px/KPIs.svg)](/v2.0.0/data/reference/site-token) [Get a site token](/v2.0.0/data/reference/site-token) [](/v2.0.0/data/reference/site-token) [Secure an API token to integrate a single Webflow site with your internal systems.](/v2.0.0/data/reference/site-token) [Get a site token](/v2.0.0/data/reference/site-token) [](/v2.0.0/data/docs/register-an-app) [![](https://dhygzobemt712.cloudfront.net/Icons/Dark/48px/App.svg)![](https://dhygzobemt712.cloudfront.net/Icons/Light/48px/App.svg)](/v2.0.0/data/docs/register-an-app) [Build your first app](/v2.0.0/data/docs/register-an-app) [](/v2.0.0/data/docs/register-an-app) [Create an App to create integrations across multiple Webflow sites.](/v2.0.0/data/docs/register-an-app) [Create an App](/v2.0.0/data/docs/register-an-app) [](/v2.0.0/data/docs/working-with-webhooks) [![](https://dhygzobemt712.cloudfront.net/Icons/Dark/48px/CustomWebhooks.svg)![](https://dhygzobemt712.cloudfront.net/Icons/Light/48px/CustomWebhooks.svg)](/v2.0.0/data/docs/working-with-webhooks) [Create a webhook](/v2.0.0/data/docs/working-with-webhooks) [](/v2.0.0/data/docs/working-with-webhooks) [Get real-time updates when events occur on your site.](/v2.0.0/data/docs/working-with-webhooks) [Create a webhook](/v2.0.0/data/docs/working-with-webhooks) ##### Looking to build with Webflow’s advanced features? Apply for an [App Developer Workspace](/v2.0.0/data/docs/developer-workspace) to explore premium tools and APIs—without the cost. Get the access you need to create powerful Apps for Webflow’s most sophisticated users and teams. [Apply for a Developer Workspace](https://forms.gle/KTMVa9HLBmxC7iHLA) What can you do with the Data API? ---------------------------------- Webflow’s Data APIs empower developers to seamlessly interact with and manage the resources of a Webflow site. With endpoints that go beyond data retrieval, you can also create, update, and delete (CRUD) resources, offering a large degree of control over site management. Here are a few of the many things you can do with the API: [![](https://dhygzobemt712.cloudfront.net/Icons/Dark/48px/EditCanvas.svg)![](https://dhygzobemt712.cloudfront.net/Icons/Light/48px/EditCanvas.svg)\ \ Work with form data\ \ Connect native Webflow forms to external data sources.](/data/reference/forms/list) [![](https://dhygzobemt712.cloudfront.net/Icons/Dark/48px/CMS.svg)![](https://dhygzobemt712.cloudfront.net/Icons/Light/48px/CMS.svg)\ \ Manage the Webflow CMS\ \ Create and manage Webflow collections and items.](/v2.0.0/data/docs/working-with-the-cms) [![](https://dhygzobemt712.cloudfront.net/Icons/Dark/48px/Code.svg)![](https://dhygzobemt712.cloudfront.net/Icons/Light/48px/Code.svg)\ \ Add custom code to sites and pages\ \ Add and maintain custom JavaScript scripts on a Site or Page.](/v2.0.0/data/docs/custom-code) [![](https://dhygzobemt712.cloudfront.net/Icons/Dark/48px/Localization.svg)![](https://dhygzobemt712.cloudfront.net/Icons/Light/48px/Localization.svg)\ \ Localize site content\ \ Adjust page content for mutliple languages and locales.](/v2.0.0/data/docs/working-with-localization) [![](https://dhygzobemt712.cloudfront.net/Icons/Dark/48px/Image.svg)![](https://dhygzobemt712.cloudfront.net/Icons/Light/48px/Image.svg)\ \ Upload assets\ \ Add assets to the Webflow assets manager, or pull a list of all existing assets by ID or by Site.](/v2.0.0/data/docs/working-with-assets) ##### Need to work directly in the Designer? If you’re looking to build apps that create and enhance designs within Webflow, the [Designer APIs](https://developers.webflow.com/designer/reference/introduction) are the right tools for the job. These APIs enable you to add and modify elements, styles, assets, and more on your design canvas. [Explore the Designer APIs](https://developers.webflow.com/designer/reference/introduction) [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Rate Limits — Webflow API Documentation To ensure consistent performance and fair access to all users, Webflow enforces rate limits on its Data API. These limits vary based on your [site subscription plan](https://www.webflow.com/pricing) and are essential for maintaining the stability of our services. Your Webflow site plan determines your rate limit: | Plan | Request Per Minute | | --- | --- | | Starter and Basic | 60 | | CMS, eCommerce, and Business | 120 | | Enterprise | Custom | If you exceed your rate limit, Webflow’s API will return an HTTP `429` Too Many Requests error. Along with this response, the `Retry-After` header will tell you how long to wait before attempting new requests—typically, this reset time is 60 seconds. If your App or integration requires a higher limit, consider [exploring our enterprise options](https://webflow.com/pricing) to request increased access. ### Endpoint-specific limits While the general rate limits apply to most API requests, some endpoints have additional constraints. For example, [Site Publish](/v2.0.0/data/reference/webhooks/events/site-publish) operations are limited to **one successful publish per minute.** Any endpoint-specific rate limits will be identified within the endpoint’s documentation. How rate limits apply to Webflow APIs ------------------------------------- Rate limits are applied on a per API key basis. This means that each API key is subject to its own rate limit, independent of any other keys you may be using. Whether you’re running multiple applications or integrating various services, each API key’s usage is tracked separately. Tracking your API usage ----------------------- To help you monitor and manage your API usage, Webflow provides three key HTTP response headers with every API request: | HTTP Response Header | Description | | --- | --- | | X-RateLimit-Remaining | Contains the number of available requests remaining in the current minute | | X-RateLimit-Limit | Contains your current overall rate limit per minute | | Retry-After | Contains the time to wait before attempting new requests | ### Example Request To illustrate how these headers work, here’s an example using cURL to make a request to the Webflow Data API: cURL Request ` | | | | --- | --- | | 1 | curl --request GET \ | | 2 | --url https://api.webflow.com/v2/token/authorized_by \ | | 3 | --header 'accept: application/json' \ | | 4 | --header 'authorization: Bearer YOUR_API_TOKEN' | ` ### Example response headers ` | | | --- | | HTTP/1.1 200 OK | | Date: Sat, 14 May 2022 09:00:00 GMT | | Status: 200 OK | | X-RateLimit-Limit: 60 | | X-RateLimit-Remaining: 59 | | Retry-After: 60 | ` Exceeding rate limits --------------------- If your application exceeds the rate limit and encounters a `429 Too Many Requests` error, it’s important to handle retries effectively. [The Webflow SDK](https://developers.webflow.com/data/reference/sdks) includes built-in exponential backoff, automatically adjusting the wait time between retries to minimize further errors. If you’re not using the SDK, we recommend implementing your own retry logic that respects the `Retry-After` header to keep your application running smoothly. ### Example error ` | | | | --- | --- | | 1 | { | | 2 | "message": "Too Many Requests", | | 3 | "code": "too_many_requests", | | 4 | "externalReference": null, | | 5 | "details": [] | | 6 | } | ` If you are seeing these errors, you should ensure your application is built to limit the rate of requests it is performing. It could, for example, be triggered by polling aggressively when waiting for resources to be created or making a large number of highly concurrent API calls. ### Optimizing API usage with webhooks Frequent polling of the API can quickly lead to rate limit issues, especially if your application is waiting for specific changes or updates. To mitigate this, Webflow offers [Webhooks](https://developers.webflow.com/data/docs/working-with-webhooks) , which allow your application to receive real-time updates without the need for continuous API calls. [Implementing webhooks](https://developers.webflow.com/data/docs/working-with-webhooks) is a highly effective way to stay within your rate limits while still maintaining responsive applications. [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Migrating to v2 — Webflow API Documentation ##### Webflow API v1 deprecation 🗓️ The Webflow is deprecating API v1 on **March 31, 2025**. For more details about this deprecation, timeline, and its implications, please refer to the [Webflow API v1 deprecation notice](/v2.0.0/data/docs/webflow-v1-api-deprecation-notice) . v2 Apps and APIs ================ Webflow’s new v2 Apps and APIs enhance security, efficiency, and developer experience. With [scopes](/v2.0.0/data/reference/scopes) and an expanded [resources](/v2.0.0/data/reference/structure-1) , both developers and users gain more control and clarity over their Webflow data. Follow the sections below to migrate from v1 Apps, site tokens, webhooks, or APIs. Migrating to API v2 for site owners =================================== Did you receive a notification that your site may be using v1 APIs? Read the below section for instructions on how to transition to using v2 APIs by the deprecation date. ###### Migrating to v2 site tokens, webhooks, and v2 Apps ###### Site Tokens ###### Webhooks ###### Apps **Action Item:** Create a new v2 site token. * **Site tokens with third-party integrations** - Reach out to the external integration provider for guidance on how to use the v2 API Site Token with their Webflow integrations * **Site tokens for custom integrations** - Replace v1 Site Token with the new v2 Site Token and [update v1 API calls](/v2.0.0/changelog/webflow-api-changed-endpoints) to [v2 APIs](/v2.0.0/data/reference/token/authorized-by) ### Third-party integrations If you’re using v1 site tokens with third-party tools — for example, integrations or chrome extensions that have asked for your API Key — you’ll want to replace them with a new [v2 API site token](/v2.0.0/data/reference/site-token) to persist any critical workflows you have in place. These new tokens are more secure and can be used to call v2 Webflow APIs. To check for v1 API Site Tokens, go to **Apps & Integrations -> API access** in your site settings. v1 tokens will show a warning about using the legacy API. ![v1 Site Token warning](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/pages/v2.0.0/Resources/migrating-to-v2/v1-site-token-warning.png) First, check to see if the token is still needed by seeing if the “Last used” date is recent. If it is, you’ll want to generate a new v2 API token. To persist existing, active workflows, [generate a new v2 API token](https://help.webflow.com/hc/en-us/articles/33961356296723-Intro-to-Webflow-s-APIs) and update your integration to use the new token. When generating a new API token, you’ll have the option to select the needed [permissions](/v2.0.0/data/reference/scopes) for the token. If you’re not sure which permissions to set, reach out to the integration provider for guidance. ### Third-party tools that don’t support v2 site tokens If your third-party tool doesn’t accept v2 site tokens, contact their support team for guidance. You can also email [developers@webflow.com](mailto:developers@webflow.com) to let us know which tool you’re using so we can help ensure they add v2 support. Custom integrations ------------------- If your team built and/or owns a custom integration that uses a v1 site token, in addition to switching to use a v2 API site token, you’ll need to update the requests your integration is making from v1 APIs to v2 APIs. You can find more information about the changes from v1 to v2 in the [changelog](/v2.0.0/changelog/webflow-api-changed-endpoints) , and explore the new [v2 API structure and resources in the v2 API reference docs](/v2.0.0/data/reference/structure-1) . For more details on site tokens and how to use them for calling Webflow APIs, see the [site token guide](/v2.0.0/data/reference/site-token) . Migrating to API v2 for App developers ====================================== Are you a developer using v1 APIs and need guidance on implementing v2 APIs for a new v2 App? Read this section below. ###### Building v2 Apps We know migrating APIs can be challenging, but we’re excited to help you upgrade to v2. The new version brings powerful capabilities that will let you build even better experiences for your users. Let’s walk through how to migrate your existing v1 App: [1](/v2.0.0/data/docs/migrating-to-v2#register-a-new-v2-app) ### Register a new v2 App To use the v2 API, you’ll need to create a brand new App with a new Client ID and secret. Additionally, you’ll need to add permissions to your App to align with the [v2 API scopes](/v2.0.0/data/reference/scopes) . Please use this [App registraton guide to help create a new v2 App.](/v2.0.0/data/docs/register-an-app) [2](/v2.0.0/data/docs/migrating-to-v2#update-your-apps-oauth-flow) ### Update your App’s OAuth flow Update your App’s [OAuth flow](/v2.0.0/data/reference/oauth-app) to use your new client ID and secret. Additionally, you will need to use the new [v2 API scopes](/v2.0.0/data/reference/scopes) in your App’s Authorization URI. For a full guide on how to update your App’s OAuth flow, see the [OAuth flow guide](/v2.0.0/data/reference/oauth-app) . [3](/v2.0.0/data/docs/migrating-to-v2#update-your-app-to-use-v2-apis) ### Update your App to use v2 APIs Update the logic in your App to make requests to the new [v2 resources and endpoints.](/v2.0.0/data/reference/structure-1) Additionally, you can use the updated [JavaScript or Python SDKs](/v2.0.0/data/reference/sdks) to make requests to the new v2 APIs. [4](/v2.0.0/data/docs/migrating-to-v2#submit-your-v2-app-to-the-marketplace) ### Submit your v2 App to the Marketplace Once you’ve updated your App to use scopes and v2 endpoints, you can share these updates by [submitting your new App to the Marketplace](https://developers.webflow.com/submit) . Before submitting your App, please refer to Webflow’s [guidance on Marketplace submissions and listings](/v2.0.0/data/docs/marketplace-guidelines) to make sure your App is compliant with Webflow’s guidelines. ##### Avoiding disruption To avoid disrupting any existing workflows for users on the v1 App version, you’ll want to support both v1 and v2 Apps in production until you’ve migrated all users to the v2 App. [5](/v2.0.0/data/docs/migrating-to-v2#instruct-users-to-migrate-to-your-v2-app) ### Instruct users to migrate to your v2 App Webflow will not automatically migrate or notify users of your new v2 App. Instead, **users must create a new authorization for the v2 App**. It’s recommended that you reach out to existing v1 App users with migration instructions on how to safely migrate their existing workflows to your approved, v2 Marketplace App. This could include: * Notifications in your v1 App that tell users about the upcoming deprecation and the need to migrate to the v2 App * A link to your new v2 App Authorization page and/or a link to your v2 App in the Webflow App Marketplace * A migration tool in your v1 App that automatically replaces existing v1 integrations with v2 integrations * A blog post or migration guide on how to migrate from v1 to v2 v2 Apps and API changes ----------------------- * **v1 Apps are now named ‘Data Clients’** The v2 equivalent of v1 Apps are named [‘Data Clients’](/v2.0.0/data/docs/data-clients) . This is a change from the previous naming convention of ‘Apps’. Here’s a quick rundown of what that means: * Data Clients access site data, spanning from the [CMS](/v2.0.0/data/reference/cms/collection-items/staged-items/get-item) to [Ecommerce](/v2.0.0/data/reference/ecommerce/settings/get-settings) , as well as new resources like [assets](/v2.0.0/data/reference/assets/assets/list) , [pages](/data/reference/pages/list) , and [custom code](/v2.0.0/data/reference/custom-code) . For an overview of the v2 API resources, see the [v2 API reference docs](/v2.0.0/data/reference/structure-1) . * Data Clients leverage Webflow’s REST APIs to fetch this information. * For use cases that require real-time updates, Data Clients can send event notifications through [webhooks.](/v2.0.0/data/reference/webhooks/list) * **Data API changes** The v2 API includes significant changes to Webflow’s REST APIs, including updates, additions, and removals to key endpoints. For a thorough overview of what’s changed, visit the changelog of: * [Changed Endpoints](/v2.0.0/changelog/webflow-api-changed-endpoints) * [New Endpoints](/v2.0.0/changelog/webflow-api-new-endpoints) * [Removed Endpoints](/v2.0.0/changelog/webflow-api-removed-endpoints) To explore the current v2 API offerings, check out the [reference docs](https://developers.webflow.com/data/reference/token/authorized-by) . * **Introduction of scopes** The new version of the API incorporates [scopes](/v2.0.0/data/reference/scopes) into the authorization process. Scopes specify an App’s permissions, ensuring that users have clearer control over the data an App can access and act upon. It’s a step towards more transparency and security. For a granular approach to permissions, make sure you’re aligned with [Webflow’s guidance on scopes.](/v2.0.0/data/reference/scopes) * **Updates to the JavaScript SDK** We’re currently revamping the JavaScript SDK to provide robust support for the v2 APIs. In the meantime, if you’re using the [JavaScript SDK](https://github.com/webflow/js-webflow-api) , please: * Update to the most recent SDK version. * Use TypeScript/Intellisense in your code editor to guide API usage after instantiating a client. You may also find SDK snippets in the API reference docs examples. Here’s a brief example on usage: JavaScript ` | | | | --- | --- | | 1 | import { WebflowClient } from "webflow-api"; | | 2 | | | 3 | const webflow = new WebflowClient({ accessToken }); | | 4 | | | 5 | // Env. variables | | 6 | // in format of string, e.g.: "639656400769508adc12fe42" | | 7 | const siteId = process.env.SITE_ID; | | 8 | const customDomainId1 = process.env.CUSTOM_DOMAIN_ID_1; | | 9 | const customDomainId2 = process.env.CUSTOM_DOMAIN_ID_2; | | 10 | | | 11 | // Sites | | 12 | | | 13 | // List Sites | | 14 | const sites = await webflow.sites.list(); | | 15 | | | 16 | // Get Site | | 17 | const site = await webflow.sites.get(siteId); | | 18 | | | 19 | // Get Custom Domains | | 20 | const customDomains = await webflow.sites.getCustomDomain(siteId); | | 21 | | | 22 | // Publish Site | | 23 | const site = await webflow.sites.publish(siteId, { | | 24 | customDomains: [customDomainId1, customDomainId2], | | 25 | publishToWebflowSubdomain: true, | | 26 | }); | ` [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Versioning — Webflow API Documentation API v2 versioning is **explicit** as part of the API endpoint URI. Versions -------- API v2 is composed of two version namespaces: | Namespace | Description | | --- | --- | | `/beta/` | A monolithic version that houses all new APIs. | | `/v2/` | A subset of v2 APIs that are considered “production” | Auth tokens will be compatible across the v2 beta and v2 production namespaces URL --- An example of an API request to v2 beta: cURL ` | | | | --- | --- | | 1 | curl --request GET \ | | 2 | --url https://api.webflow.com/beta/token/authorized_by \ | | 3 | --header 'accept: application/json' | ` Webflow SDK ----------- Currently, the Webflow SDK does not support requests to beta endpoints. For access to these endpoints, please refer to the Webflow API documentation and make requests directly through an HTTP client or your preferred API tool. [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Scopes — Webflow API Documentation What are Scopes? ---------------- Scopes refer to the specific permissions or access levels that users can grant to your App when they authorize it to access their data or perform actions on their behalf. Each scope represents a particular set of privileges that your application can obtain - either reading or writing data for a specific resource, or both. ### Why are Scopes important? Scopes enhance user privacy and security by allowing a user to identify and approve the data an App can access and act on. ### Which Scopes do I need? We strongly recommend that your App only uses the necessary scopes it requires to function. By requesting only the necessary scopes, you’re able to minimize the exposure of user data and reduce the risk of unauthorized access or misuse. Users appreciate applications that follow the principle of least privilege, as it builds trust and provides a better user experience. On the flip-side, requesting excessive or unnecessary scopes could raise user concerns or deter them from granting access. Using Scopes in your Webflow App -------------------------------- ### Registration When creating an Data Client App, you’ll be asked to register the scopes for your App. ![Scope Registration](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/28e0ad2-Large_GIF_1064x696.gif) Scope Registration ### Authorization When users authorize your application, you must request the appropriate scopes based on the functionalities your application needs. To request scopes, you’ll need to include the required scopes in the `scopes` parameter of your Authorization URL. Learn more about the Authorization Flow in this guide. See the example below for how to properly construct your Authorization URL. ` https://webflow.com/oauth/authorize?response_type=code&client_id=739dc78b0704716e8aadab301466757fa41afbca5f31aa91a79a35e8708a5866&scope=assets%3Aread%20assets%3Awrite%20authorized_user%3Aread%20cms%3Aread%20cms%3Awrite%20custom_code%3Aread%20custom_code%3Awrite%20forms%3Aread%20forms%3Awrite%20pages%3Aread%20pages%3Awrite%20sites%3Aread%20sites%3Awrite ` The URL will result in an Authorization Request page outlining the scopes that your App will be able to access on behalf of an Authorized User. ![](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/3aa5532-Screenshot_2023-06-13_at_10.36.18_AM.png) Available Scopes ---------------- ##### Scopes & Endpoints Throughout our documentation, you’ll be able to see which scopes are needed to access a specific endpoint. | Resource | Scopes | Endpoints | | --- | --- | --- | | Assets | `assets:read`, `assets:write` | → [API Docs](/v2.0.0/data/reference/assets/assets/list) | | Authorized User | `authorized_user:read` | → [API Docs](/v2.0.0/data/reference/token/authorized-by) | | Authorization info | None required | → [API Docs](/v2.0.0/data/reference/token/introspect) | | CMS | `cms:read`, `cms:write` | → [API Docs](/v2.0.0/data/reference/cms/collections/list) | | Components | `components:read`, `components:write` | → [API Docs](/v2.0.0/data/reference/pages-and-components/components/list) | | Custom Code | `custom_code:read`, `custom_code:write` | → [API Docs](/v2.0.0/data/reference/custom-code/custom-code/list) | | Ecommerce | `ecommerce:read`, `ecommerce:write` | → [API Docs](/v2.0.0/data/reference/ecommerce/products/list) | | Forms | `forms:read`, `forms:write` | → [API Docs](/data/reference/forms/list) | | Pages | `pages:read`, `pages:write` | → [API Docs](/v2.0.0/data/reference/pages-and-components/pages/list) | | Sites | `sites:read`, `sites:write` | → [API Docs](/v2.0.0/data/reference/sites/list) | | Site Activity | `site_activity:read` | → [API Docs](/v2.0.0/data/reference/enterprise/site-activity/list) | | Site Configuration | `site_config:read`, `site_config:write` | → [API Docs](/v2.0.0/data/reference/enterprise/site-configuration/url-redirects/get) | | Users | `users:read`, `users:write` | → [API Docs](/v2.0.0/data/reference/users/users/list) | | Webhooks | Depends on `trigger_type` | → [API Docs](/v2.0.0/data/reference/webhooks/list) | | Workspace BETA | `workspace:read`, `workspace:write` | → [API Docs](/v2.0.0-beta/reference/enterprise/workspace-management/create) | [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Structure — Webflow API Documentation Webflow’s API follows a well-structured resource model, providing a clear hierarchy for accessing and manipulating data within a Webflow project. Each resource represents a distinct aspect of a Webflow project, which Apps can access to perform specific operations and retrieve relevant data. [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Webflow v1 API Deprecation Notice — Webflow API Documentation As part of Webflow’s ongoing commitment to enhancing your developer experience, we’re transitioning from the v1 APIs to the more advanced v2 APIs. This document outlines the deprecation timeline for v1 Apps, APIs, and Webhooks, and provides guidance on managing a smooth transition to v2. We recommend starting your migration as soon as possible to ensure uninterrupted service for your integrations. Key changes ----------- 1. **API Site Tokens:** * **Webflow has discontinued creation of v1 API Site Tokens.** For new integrations or updates, developers should use v2 API Site Tokens. API Tokens are distinct from [auth tokens](/v2.0.0/data/reference/oauth-app) generated via Webflow Apps. * See the [v2 migration guide](/v2.0.0/data/docs/migrating-to-v2#migrating-to-v2-site-tokens-webhooks-and-v2-apps) for more on migrating to v2 API Site Tokens 2. **Webhooks:** * **Webflow will no longer support manual creation of v1 Webhooks.** To continue receiving real-time notifications via webhooks, [register v2 webhooks](/v2.0.0/data/docs/working-with-webhooks) . * See the [v2 migration guide](/v2.0.0/data/docs/migrating-to-v2#migrating-to-v2-site-tokens-webhooks-and-v2-apps) for more on migrating to v2 Webhooks 3. **App Registrations:** * **Webflow no longer accepts App submissions for new v1 Apps.** To create new applications or update your existing v1 Apps to v2, use the [v2 App registration process](/v2.0.0/data/docs/migrating-to-v2#building-v2-apps) . * **Integrations/automations created by v1 Apps won’t work past March 31, 2025.** See the [v2 migration guide](/v2.0.0/data/docs/migrating-to-v2#migrating-to-v2-site-tokens-webhooks-and-v2-apps) for more on migrating to v2 Apps Important dates --------------- * **August 1, 2024**: De-listing of Marketplace Apps that are still reliant on v1 (non-scoped) authorization. * **February 20, 2025**: Short weekly timed shutdowns on v1 API calls begin, which may cause intermittent failures. * **March 17, 2025**: Short daily timed shutdowns on v1 API calls continue, which may cause intermittent failures. * **March 31, 2025**: Sunset date for the v1 API. From this date onward, v1 App Authorizations/APIs/Webhooks will no longer be operational. Transitioning to the v2 API ensures that developers have access to the latest features, enhanced security, and improved performance. We understand the challenges that come with such transitions, and are committed to supporting the Webflow developer community every step of the way. For any queries or support migrating to v2 APIs, Apps, and Webhooks, reach out to [developers@webflow.com](mailto:developers@webflow.com) . For other support matters, please reach out to Webflow’s [support team](https://support.webflow.com/) . [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # SDKs — Webflow API Documentation Our SDKs provide comprehensive tools and libraries tailored for efficient and easy integration with our suite of APIs, enabling developers to quickly build and scale applications across various platforms. ### JavaScript Leverage the Webflow JavaScript SDK for intuitive integration within Node.js environments. [View SDK](https://www.npmjs.com/package/webflow-api) ### Python Use the Webflow Python SDK to seamlessly incorporate Webflow functionalities into your Python projects. [View SDK](https://pypi.org/project/webflow/) [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # OAuth — Webflow API Documentation This tutorial guides you through setting up an [OAuth 2.0](https://oauth.net/2/) authentication flow. This flow allows users to grant limited permissions to your App and enables your App to request an access token to perform actions on behalf of the user. By the end of this tutorial, your Webflow App will be able to obtain an access token on behalf of a user using the [Authorization Code Grant flow.](https://developer.okta.com/blog/2018/04/10/oauth-authorization-code-grant-type) [](https://github.com/Webflow-Examples/cms-examples) [![](https://dhygzobemt712.cloudfront.net/Icons/Dark/48px/Apps.svg)![](https://dhygzobemt712.cloudfront.net/Icons/Light/48px/Apps.svg)](https://github.com/Webflow-Examples/cms-examples) [Quickstart](https://github.com/Webflow-Examples/cms-examples) [Our example Apps come with the OAuth 2.0 flow already set up for you. Start building your Webflow App quickly by using one of our pre-configured example apps.](https://github.com/Webflow-Examples/cms-examples) [CMS Explorer](https://github.com/Webflow-Examples/cms-examples) ### Authorization Code Grant Flow Webflow uses the [Authorization Code Grant flow](https://developer.okta.com/blog/2018/04/10/oauth-authorization-code-grant-type) to provide access tokens to Apps. This flow involves a series of interactions between Webflow’s authorization server and your web app. Here’s how the process works when a user visits your site for the first time: 1. **User sign-up/Login**: A user signs up or logs in to your App. At some point, they may need to perform an action that requires using the Webflow API. 2. **Authorization request**: To make requests to the Webflow API on the user’s behalf, your App redirects the user to an authorization screen. Here, they can review the permissions your App is requesting and authorize access to specific Webflow Sites or a Workspace. 3. **User authorization**: Once the user grants authorization, Webflow redirects them back to your App via a redirect URI specified during the app setup, adding a `code` parameter to the query string. 4. **Token Request**: Your app uses the `code` to make a secure request to Webflow’s authorization server to obtain an access token. If the request is valid, Webflow responds with an access token. 5. **API Requests**: Your app can now use this access token to make requests to the Webflow API on behalf of the user. Get an access token =================== #### Requirements Before you begin, ensure you have the following: * A Webflow App created with the “Data Client” building block. [Learn more here](https://developers.webflow.com/data/docs/getting-started-apps) * Your app’s client credentials: `client_id` and `client_secret.` **Note:** Only workspace administrators are authorized to view a client secret. If you’re not a site administrator, please contact one to get the secret for you. ###### 1\. Set up your server Before you can request an access token, you’ll need to set up your server to handle the OAuth 2.0 flow. We recommend using JavaScript or Python, as we provide SDKs for these languages that can help simplify the authentication process. Follow the below examples in Node.js or Python to help you create a server that can accept requests and communicate with the Webflow authorization server. ###### Node.js ###### Python 1. **Install the necessary packages** Ensure all required libraries and dependencies are installed. ` | | | | --- | --- | | $ | npm install express dotenv webflow-api | ` 2. **Store environment variables** Create a `.env` file to store your sensitive information like the `CLIENT_ID` and `CLIENT_SECRET`. .env ` | | | --- | | CLIENT_ID=your_client_id | | CLIENT_SECRET=your_client_secret | | REDIRECT_URI=your_redirect_uri #optional | | STATE=your_unique_state #optional | ` 3. **Initialize server** Set up the server to listen on a specific port. server.js `` | | | | --- | --- | | 1 | require('dotenv').config(); | | 2 | const express = require('express'); | | 3 | const { WebflowClient } = require('webflow-api'); | | 4 | | | 5 | const app = express(); | | 6 | const port = 3000; | | 7 | | | 8 | /* | | 9 | We'll add the necessary endpoints here in the steps below. | | 10 | */ | | 11 | | | 12 | app.listen(port, () => { | | 13 | console.log(`Server is running at http://localhost:${port}`); | | 14 | }); | `` ###### 2\. Create an authorization link To enable users to install your App, you need to create an authorization link. This link directs users to a Webflow authorization screen where they can grant your App permission to access their Webflow data. ##### Where do I put this link? **App Marketplace Submission:** Supply this link in your application to the App marketplace. Users will use it to install your App from the marketplace. **Your Site:** Place this link on your site to direct users to try out or install your App. You can create the authorization link using various methods, with the recommended approach being through our JavaScript and Python SDKs. ### Request Parameters To create the authorization link, you will need the following information: client\_id stringRequired Unique ID for your application. Can be found in the dashboard. response\_type stringRequired This value should always be “code”. redirect\_uri stringRequired The URI to redirect the user once they’ve granted authorization. This must match what’s used in your App settings. state string A token value provided by your application to prevent [CSRF attacks.](https://owasp.org/www-community/attacks/csrf#:~:text=CSRF%20attacks%20target%20functionality%20that,the%20response%2C%20the%20victim%20does.) If passed, the authorization server should respond with this parameter. ### Constructing the authorization link #### Using the SDK To simplify the process of creating authorization links and handling OAuth flows, you can use the provided JavaScript and Python SDKs. These SDKs offer convenient methods to generate the authorization URL with the required parameters. ###### Node.js ###### Python server.js `` | | | | --- | --- | | 1 | require('dotenv').config(); | | 2 | const express = require('express'); | | 3 | const { WebflowClient } = require('webflow-api'); | | 4 | | | 5 | const app = express(); | | 6 | const port = 3000; | | 7 | | | 8 | // Endpoint to redirect to the authorization link | | 9 | app.get('/auth', (req, res) => { | | 10 | const authorizeUrl = WebflowClient.authorizeURL({ | | 11 | state: process.env.STATE, | | 12 | scope: 'sites:read', | | 13 | clientId: process.env.CLIENT_ID, | | 14 | redirectUri: process.env.REDIRECT_URI, | | 15 | }); | | 16 | | | 17 | res.redirect(authorizeUrl); | | 18 | }); | | 19 | | | 20 | app.listen(port, () => { | | 21 | console.log(`Server is running at http://localhost:${port}`); | | 22 | }); | `` ###### Manually create the authorization link If you prefer not to use the SDKs, you can manually construct the authorization link by adding the necessary query parameters to the authorization URL: ` https://webflow.com/oauth/authorize ` Construct the authorization URL using the gathered parameters: ` https://webflow.com/oauth/authorize?response_type=code&client_id=YOUR_CLIENT_ID&scope=assets%3Aread%20assets%3Awrite%20authorized_user%3Aread%20cms%3Aread%20cms%3Awrite%20custom_code%3Aread%20custom_code%3Awrite%20forms%3Aread%20forms%3Awrite%20pages%3Aread%20pages%3Awrite%20sites%3Aread%20sites%3Awrite ` * When URL encoding multiple scopes, they should be connected by a space (`%20`). * Scopes are written in the format `scope:action`, so the colon (`:`) should be encoded as `%3A`. For example passing the following scopes: `sites:read`, `sites:write`, and `pages:read` should look like `sites%3Aread%20sites%3Awrite%20pages%3Aread` ###### Copy the link from the Dashboard Additionally, you can copy an auto-generated installation link from your App’s settings. In your Workspace Dashboard: 1. Select to “Apps and Integrations” in the left-hand menu 2. Scroll to the “App Development” section and find your App 3. Copy the link from the “Install” button ![](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/390600a-Screenshot_2024-08-01_at_4.13.54_PM.png) ###### 3\. Handle redirect to the callback URI When users click on the authorization link, they will be taken to a screen where they can review and grant the necessary permissions for your App. ![](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/bcd2d30-image.png) After the user authorizes the App, Webflow redirects them to your server using the redirect URI specified in your App settings. This `GET` request to your server includes the following query parameters: * `code` - A single-use authorization code that you’ll exchange for an access token. This code is only valid for 15 minutes. * `state` : _optional_ - The unique state value you provided in the initial request. Ensure this value matches the original to protect against CSRF attacks. * * * Let’s set up an endpoint to handle the callback request and store these parameters, as you’ll need them in the next step to request an access token from Webflow. See the example below for details on completing the following steps: 1. **Setup the callback endpoint** Create a route to handle the redirect from Webflow 2. **Verify `state` parameter** Optionally, check that the state parameter matches the one sent in the authorization request. 3. **Extract authorization code** Retrieve the code from the query parameters. #### Example ###### Node.js ###### Python server.js `` | | | | --- | --- | | 1 | require('dotenv').config(); | | 2 | const express = require('express'); | | 3 | const { WebflowClient } = require('webflow-api'); | | 4 | | | 5 | const app = express(); | | 6 | const port = 3000; | | 7 | | | 8 | // Endpoint to redirect to the authorization link | | 9 | app.get('/auth', (req, res) => { | | 10 | const authorizeUrl = WebflowClient.authorizeURL({ | | 11 | state: process.env.STATE, | | 12 | scope: 'sites:read', | | 13 | clientId: process.env.CLIENT_ID, | | 14 | redirectUri: process.env.REDIRECT_URI, | | 15 | }); | | 16 | | | 17 | res.redirect(authorizeUrl); | | 18 | }); | | 19 | | | 20 | // Endpoint to receive info from the callback URL | | 21 | app.get('/callback', async (req, res) => { | | 22 | const { code, state } = req.query; // Store code and state parameters as variables | | 23 | | | 24 | if (state !== process.env.STATE) { | | 25 | return res.status(400).send('State does not match'); | | 26 | } | | 27 | }); | | 28 | | | 29 | app.listen(port, () => { | | 30 | console.log(`Server is running at http://localhost:${port}`); | | 31 | }); | `` ###### 4\. Request an access token Now that you have the authorization code you can exchange it for an access token. The access token request should be made as soon as possible after authorization as an unconfirmed authorization code is only valid for 15 minutes. Let’s walk through the steps to create a smooth flow for a user: 1. **Request an access token from Webflow’s authorization server** In the same endpoint we just set up, create a request to Webflow with the following parameters. Webflow requires these parameters to ensure that the entity requesting the access token is the same entity that received the authorization code. #### Authorization server endpoint `POST https://api.webflow.com/oauth/access_token` #### Request Parameters client\_id stringRequired Unique ID for your application. Can be found in the dashboard. client\_secret stringRequired Private value unique to your application. Can be found in the dashboard. code stringRequired Authorization code used to retrieve an access\_token for the user. Can only be used once. 2. **Store the access token securely** For demonstration purposes, we’re storing the access token in a variable and printing it to the terminal. However, this approach is not secure for production. You should store the access token securely in a database or environment variables. For comprehensive guidance on securely storing tokens, please refer to our example apps on [GitHub](https://github.com/Webflow-Examples) . 3. **Redirect the user within your App** After successfully obtaining the access token, redirect the user to an appropriate location within your app. This could be a dashboard, a welcome page, or any other relevant section. Ensure that the user experience is smooth and they are informed about the successful authentication. #### Example ###### Node.js ###### Python server.js ``| | | | --- | --- | | 1 | require('dotenv').config(); | | 2 | const express = require('express'); | | 3 | const { WebflowClient } = require('webflow-api'); | | 4 | | | 5 | const app = express(); | | 6 | const port = 3000; | | 7 | | | 8 | // Endpoint to redirect to the authorization link | | 9 | app.get( '/auth', (req, res) => { | | 10 | const authorizeUrl = WebflowClient.authorizeURL({ | | 11 | state: process.env.STATE, | | 12 | scope: 'sites:read', | | 13 | clientId: process.env.CLIENT_ID, | | 14 | redirectUri: process.env.REDIRECT_URI, // If the redirect URI is included in the auth link, it must also be included in the request for an access token | | 15 | }); | | 16 | | | 17 | res.redirect(authorizeUrl); | | 18 | }); | | 19 | | | 20 | // Endpoint to receive info from the callback URL | | 21 | app.get('/callback', async (req, res) => { | | 22 | const { code, state } = req.query; | | 23 | | | 24 | if (state !== process.env.STATE) { | | 25 | return res.status(400).send('State does not match'); | | 26 | } | | 27 | | | 28 | try { | | 29 | // Request an access token | | 30 | const accessToken = await WebflowClient.getAccessToken({ | | 31 | clientId: process.env.CLIENT_ID, | | 32 | clientSecret: process.env.CLIENT_SECRET, | | 33 | code: code, | | 34 | redirect_uri: process.env.REDIRECT_URI, | | 35 | }); | | 36 | | | 37 | // Store the access token securely, e.g., in a database or session (not shown here for brevity) | | 38 | console.log(accessToken) | | 39 | | | 40 | // Redirect the user to your App | | 41 | res.redirect('/dashboard') | | 42 | | | 43 | | | 44 | } catch (error) { | | 45 | console.error('Error during OAuth process:', error); | | 46 | res.status(500).send('Internal Server Error'); | | 47 | } | | 48 | | | 49 | }); | | 50 | | | 51 | // Dashboard route for demonstraton purposes | | 52 | app.get('/dashboard', async (req, res) => { | | 53 | res.send('Welcome to your dashboard!') | | 54 | }); | | 55 | | | 56 | app.listen(port, () => { | | 57 | console.log(`Server is running at http://localhost:${port}`); | | 58 | }); | | 59 | |`` ###### 5\. Start your server and test the authentication flow You’re ready to test your newly created authentication flow! In this step, we’ll start our server, navigate to the authorization screen, and get an access token from Webflow. 1. **Create a secure tunnel using [ngrok](https://ngrok.com/) _(OPTIONAL)_** ###### using ngrok ngrok can be used to create a secure tunnel to your localhost, providing you with an HTTPS link that can be used as a valid redirect URI. 1. **Install ngrok** Download and install ngrok using a package manager or [directly from their website](https://developers.webflow.com/data/reference/oauth-app) . ###### Homebrew ###### Choco ` | | | | --- | --- | | $ | brew install ngrok/ngrok/ngrok | ` 2. **Authorize the ngrok agent** [Copy your authentication token](https://dashboard.ngrok.com/get-started/your-authtoken) from ngrok, and enter the following command in your terminal. ` ngrok config add-authtoken $YOUR_AUTHTOKEN ` 3. **Create a secure tunnel** In a new terminal window, run the following command to create a tunnel to your local server: ` ngrok http 3000 ` Ngrok will provide you with a public HTTPS URL that forwards to your local server running on port 3000. It should look something like this: ` https://your-ngrok-url.ngrok.io ` 4. **Update your redirect URI in your App’s settings** 5. In your workspace settings, navigate to Apps & Integrations > App Development 6. Find your App and click the “Edit App” button 7. Navigate to the “Building Blocks” menu 8. Update the Redirect URI with your Ngrok URL, ensuring that you include the correct endpoint. For example, if your endpoint is `/callback`, your Redirect URI should look something like `https://your-ngrok-url.ngrok.io/callback`. 9. **Update the redirect URI in your `.env` file** Be sure to also update your redirect URI in your `.env` file if you’re passing your callback URI when creating an authorization link. ` REDIRECT_URI=https://your-ngrok-url.ngrok.io/callback ` 2. **Start your server** Enter the following command into your terminal to start your server. ###### Node.js ###### Python ` node server.js ` 3. **Start the authorization flow** 1. **Start the authentication process** Open your browser and go to `http://localhost:3000/auth`. You will be redirected to Webflow’s authorization screen for your App. 2. **Authorize your app** Select the workspace or sites you want your app to access, and click the “Authorize” button. 3. **Redirect to your app** Upon successful authorization, you will be redirected to your app’s dashboard. 4. **Verify the access token** Check your terminal to see the access token printed out. Didn’t see what you expected? [Read the troubleshooting guide below](https://developers.webflow.com/data/reference/oauth-app#troubleshooting) . Revoke an access token ====================== To revoke an access token that has been issued to your application, make a POST request to the following endpoint with the below parameters: ` https://webflow.com/oauth/revoke_authorization ` ### Request Parameters client\_id stringRequired The unique identifier for your OAuth application. client\_secret stringRequired The secret key associated with your OAuth application. access\_token stringRequired The access token that you wish to revoke. ### Example Request cURL ` | | | | --- | --- | | 1 | curl -X POST https://webflow.com/oauth/revoke_authorization \ | | 2 | -H "Content-Type: application/json" \ | | 3 | -d '{ | | 4 | "client_id": "2ccc1b455c782fd60093590c83ee5e315b36bd6640507bb48570e5d0265c2854", | | 5 | "client_secret": "d26ec60528020e1caf426db1a20dceaf5f4e3581bb29bc659b2886d46a7160ed", | | 6 | "access_token": "53db404efe82daea0c65c635a49bc9388e470146b4d800f559cb9a7f3daf83f1" | | 7 | }' | ` ### Response If the request is successful, the access token will be revoked, and the response will return an HTTP status code of `200` OK with the following response body: ` | | | | --- | --- | | 1 | { | | 2 | "did_revoke": true | | 3 | } | ` ### Possible Errors | Error Type | Description | | --- | --- | | `invalid_client` | The `client_id` or `client_secret` is invalid or does not match the provided credentials. | | `invalid_token` | The `access_token` provided does not exist or has already been revoked. | | `invalid_request` | The request is missing one or more required parameters, or is otherwise malformed. | Troubleshooting =============== ###### My authorization link shows 400 Bad Request If your authorization link returns a 400 Bad Request error, ensure the following: * The `client_id` is correct and matches the one provided in your app’s settings. * The scopes you are requesting are registered and valid for your app in the dashboard. * If you are including the `redirect_uri` parameter, verify that it matches the one registered for your app in the dashboard. * Ensure that the URL is properly constructed and encoded if you are creating it manually. ###### My server responds with an invalid\_grant error * If you included a `redirect_uri` in your authorization link, you must also include it in your request for an access token. * Ensure your environment variables are loading, and you’re sending the correct `client_id` and `client_secret`. * Make sure you have a fresh `code` value, these tokens are single-use and can not be used again. Also, the token is only valid for 15 minutes after it has been granted. [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Get Authorization User Info — Webflow API Documentation Information about the Authorized User Required Scope | `authorized_user:read` ### Response Request was successful idstringOptional The unique ID of the user emailstringOptional`format: "email"` The user’s email address firstNamestringOptional The user’s first name lastNamestringOptional The user’s last name ### Errors 401 Unauthorized 403 Forbidden [Get Authorization Info\ \ Up Next](/v2.0.0/data/reference/token/introspect) [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Field Types & Item Values — Webflow API Documentation Each collection has a schema, which defines the fields that can be added to items in the collection. Each field has a type, which determines the data that can be stored in the field. To see a list of field types included in your collection, make a request to the [Get Collection](/v2.0.0/data/reference/cms/collections/get) endpoint. ##### Field Type Names Some field types may use slightly different names in the Webflow UI. For these fields, they have an “alt name” listed, which is the name of the field displayed in Webflow. The API uses the name of the field type. [Plain Text](https://university.webflow.com/lesson/plain-text-field) --------------------------------------------------------------------- Basic text content that doesn’t need special formatting. ###### Format ###### Example ` string ` [Rich Text](https://university.webflow.com/lesson/rich-text-field) ------------------------------------------------------------------- A long text field that can span multiple lines. Accepts HTML Formatting. ###### Format ###### Example ` string ` [ImageRef / Image](https://university.webflow.com/lesson/image-field) ---------------------------------------------------------------------- The image field allows you to upload a single image for your Collection items and use it in your designs. Images must be hosted on a publicly accessible URL to be uploaded via the API. The maximum file size for images is 4MB. You can also add an image that already exists in the CMS by referencing its `fileId`. ###### Field Format: Read ###### Field Format: Write ` | | | | --- | --- | | 1 | { | | 2 | fileId: string, | | 3 | url: string, | | 4 | alt?: string | | 5 | } | ` [ImageRefSet / Multi-Image](https://university.webflow.com/lesson/multi-image-field-overview) ---------------------------------------------------------------------------------------------- The multi-image field allows you to upload multiple images for a Collection item and use it in your designs. Images must be hosted on a publicly accessible URL to be uploaded via the API. The maximum file size for images is 4MB. You can also add images that already exist in the CMS by referencing the `fileId`. ###### Field Format: Read ###### Field Format: Write ` | | | | --- | --- | | 1 | Array<{ | | 2 | fileId: string, | | 3 | url: string, | | 4 | alt?: string | | 5 | }> | ` VideoLink --------- Adds videos hosted on platforms such as YouTube or Vimeo through a URL. These are usually connected to a video element. ###### Field Format ###### Example ` string ` [Link](https://university.webflow.com/lesson/link-field) --------------------------------------------------------- Adds a generic link that can be connected to any link element such as a button, a text link, or a link block. ###### Field Format ###### Example ` string ` [Email](https://university.webflow.com/lesson/email-field) ----------------------------------------------------------- Adds an email address field to collection items. ###### Field Format ###### Example ` string ` [Phone](https://university.webflow.com/lesson/phone-field) ----------------------------------------------------------- ###### Field Format ###### Example ` string ` [Number](https://university.webflow.com/lesson/number-field) ------------------------------------------------------------- Add any kind of number (integer, decimal) to your collection items. ###### Field Format ###### Example ` number ` [DateTime](https://university.webflow.com/lesson/date-time-field) ------------------------------------------------------------------ Add a date and time picker to your collection items. ###### Field Format: Read ###### Field Format: Write ###### Example ` string ` [Switch](https://university.webflow.com/lesson/switch-field) ------------------------------------------------------------- A boolean field that allows you to toggle between true and false. ###### Field Format ` boolean ` [Color](https://university.webflow.com/lesson/color-field-overview) -------------------------------------------------------------------- Adds a unique color to each collection item which can be applied as text color, background color, and border color in your designs. Accepts a HEX code as a string. ###### Field Format ###### Example ` string ` Accepts the following formats * #RGB * #RGBA * #RRGGBB * #RRGGBBAA * rgb(red,green,blue) * rgba(red,green,blue,alpha) * hsl(hue,saturation,lightness) * hsla(hue,saturation,lightness,alpha) * orchid, aqua, black, … * transparent [Option](https://university.webflow.com/lesson/option-field) ------------------------------------------------------------- Creates a list of predefined values to choose from for each collection item. When creating an option field, use the [Create Field](/v2.0.0/data/reference/cms/collection-fields/create) endpoint and pass an array of `options` to the `metadata` property. ###### Field Format ###### Example ` | | | | --- | --- | | 1 | [{"name": string}, {"name": string}, {"name": string}] | ` File ---- Adds a file to your collection items that you can connect to any link element in your project. Files must be hosted on a publicly accessible URL to be uploaded via the API. ###### Field Format: Read ###### Field Format: Write ###### Example ` | | | | --- | --- | | 1 | { | | 2 | fileId: string, | | 3 | url: string, | | 4 | alt?: string | | 5 | } | ` [ItemRef / Reference](https://university.webflow.com/lesson/reference-field) ----------------------------------------------------------------------------- Link to a collection item from the same or different collections. When creating a reference field, get the `collectionId` of the collection you’re looking to reference. Then, when creating the field using the [Create Field](/v2.0.0/data/reference/cms/collection-fields/create) endpoint, pass the `collectionId` to the `metadata` property as `"collectionId": `. ###### Field Format ###### Example ` string ` [Set / Multi-Reference](https://university.webflow.com/lesson/multi-reference-field) ------------------------------------------------------------------------------------- Link to multiple collection items from the same or different collections. When creating a reference field, get the `collectionId` of the collection you’re looking to reference. Then, when creating the field using the [Create Field](/v2.0.0/data/reference/cms/collection-fields/create) endpoint, pass the `collectionId` to the `metadata` property as `"collectionId": `. ###### Field Format ###### Example ` string ` User ---- Unique User ID that is set by Webflow. Only used for `created-by` and `updated-by` fields. ###### Field Format ###### Example ` string ` [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Getting started with Webflow Apps — Webflow API Documentation Webflow Apps give developers the power to extend Webflow’s capabilities, making it easier for Visual Designers and Marketing teams to streamline workflows and achieve better results. Build powerful apps that transform how users design, develop, and manage their Webflow sites. Through automation and seamless integrations, you can create tools that enhance productivity and unlock new possibilities for Designers and Marketers. Whether it’s automating content updates across multiple pages, enabling advanced style customizations with AI, or building integrations with popular marketing and analytics tools, your apps can empower users to build and maintain exceptional websites with ease - bringing Webflow’s vision of giving web development superpowers to everyone. ![](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/24005_API Documentation_Introduction_v3_24fps.gif) App capabilities ================ [![](https://dhygzobemt712.cloudfront.net/Icons/Dark/64px/Switch.svg)![](https://dhygzobemt712.cloudfront.net/Icons/Light/64px/Switch.svg)\ \ Data Clients\ \ ##### Harness your site’s data\ \ Sync CMS content, form submissions, and translations between Webflow and your favorite tools. Push blog posts to social media, send form responses to your CRM, and keep content in sync across platforms using Webflow’s Data APIs.](/v2.0.0/data/docs/data-clients) [![](https://dhygzobemt712.cloudfront.net/Icons/Dark/64px/Styles.svg)![](https://dhygzobemt712.cloudfront.net/Icons/Light/64px/Styles.svg)\ \ Designer Extensions\ \ ##### Supercharge the design workflow\ \ Build extensions that automate complex design tasks in Webflow. Help users focus on creativity by streamlining repetitive work - from importing and transforming design assets to applying sophisticated styles and managing content updates across pages.](/v2.0.0/data/docs/designer-extensions) [![](https://dhygzobemt712.cloudfront.net/Icons/Dark/64px/PublishDesigner.svg)![](https://dhygzobemt712.cloudfront.net/Icons/Light/64px/PublishDesigner.svg)\ \ Hybrid Apps\ \ ##### Create seamless experiences\ \ Combine the power of Data Clients and Designer Extensions to create comprehensive solutions. Build apps that seamlessly integrate content management through APIs while providing direct design controls in the Webflow Designer - giving users a unified experience to manage their entire workflow.](/v2.0.0/data/docs/hybrid-apps) Start building ============== Ready to unleash the full potential of Webflow? Follow these steps to create and launch an app that enhances Webflow’s capabilities and wows users. Let’s get started! [1](/v2.0.0/data/docs/getting-started-apps#choose-a-development-workspace) ### Choose a development workspace Start building apps in any workspace where you have Admin access - no special workspace is required to get started. When you’re ready to unlock premium features and APIs, apply for a [Developer Workspace](/v2.0.0/data/docs/developer-workspace) that gives you free access to build more advanced functionality for Webflow’s power users and teams. [Claim your workspace](https://docs.google.com/forms/d/1XaqSQSQd_pXCgJBsMLM2qM7kwHcWbMLnmRbCjmSDBzM) [2](/v2.0.0/data/docs/getting-started-apps#create-your-first-app) ### Create your first app Start building an app that integrates seamlessly with Webflow, enabling custom solutions that elevate user experiences. Register an App in Webflow to get started. [Register an app](/docs/register-an-app) [3](/v2.0.0/data/docs/getting-started-apps#tap-into-webflows-cms-data) ### Tap into Webflow’s CMS Data Access the power of Webflow’s CMS directly within your app. Dive into dynamic data, pull content on demand, and build experiences that adapt in real-time. [Explore CMS data](/v2.0.0/data/docs/working-with-the-cms) [4](/v2.0.0/data/docs/getting-started-apps#transform-the-canvas-with-your-app) ### Transform the canvas with your app Step into the Designer and start creating apps that interact directly with the Canvas. From manipulating styles to custom functionality, unleash the full potential of Webflow’s design environment. [Dive into Designer Extensions](/v2.0.0/designer/docs/getting-started-designer-extensions) [5](/v2.0.0/data/docs/getting-started-apps#share-your-app) ### Share your app Publishing your app lets you share your creation with others. Launch publicly in the Webflow Marketplace to reach thousands of users and unlock monetization opportunities, or publish privately to create custom solutions for your organization and select clients. Whether public or private, your published app can transform how users work in Webflow. [Publish your app](/docs/publish-an-app) [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Create Webhook — Webflow API Documentation Create a new Webhook. Limit of 75 registrations per `triggerType`, per site. Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients) . Required scope | `sites:write` ### Path parameters site\_idstringRequired Unique identifier for a Site ### Request This endpoint expects an object. idstringOptional Unique identifier for the Webhook registration triggerTypeenumOptional The type of event that triggered the request. See the the documentation for details on [supported events](/data/reference/all-events) . Show 15 enum values urlstringOptional URL to send the Webhook payload to workspaceIdstringOptional Unique identifier for the Workspace the Webhook is registered in siteIdstringOptional Unique identifier for the Site the Webhook is registered in filterobjectOptional Only supported for the `form_submission` trigger type. Filter for the form you want Webhooks to be sent for. Show property lastTriggereddatetimeOptional Date the Webhook instance was last triggered createdOndatetimeOptional Date the Webhook registration was created ### Response Request was successful idstringOptional Unique identifier for the Webhook registration triggerTypeenumOptional The type of event that triggered the request. See the the documentation for details on [supported events](/data/reference/all-events) . Show 15 enum values urlstringOptional URL to send the Webhook payload to workspaceIdstringOptional Unique identifier for the Workspace the Webhook is registered in siteIdstringOptional Unique identifier for the Site the Webhook is registered in filterobjectOptional Only supported for the `form_submission` trigger type. Filter for the form you want Webhooks to be sent for. Show property lastTriggereddatetimeOptional Date the Webhook instance was last triggered createdOndatetimeOptional Date the Webhook registration was created ### Errors 400 Bad Request 401 Unauthorized 404 Not Found 429 Too Many Requests 500 Internal Server Error [Remove Webhook\ \ Up Next](/v2.0.0/data/reference/webhooks/delete) [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # List Webhooks — Webflow API Documentation List all App-created Webhooks registered for a given site Required scope | `sites:read` ### Path parameters site\_idstringRequired Unique identifier for a Site ### Response Request was successful webhookslist of objectsOptional Show 8 properties paginationobjectOptional Pagination object Show 3 properties ### Errors 400 Bad Request 401 Unauthorized 404 Not Found 429 Too Many Requests 500 Internal Server Error [Get Webhook\ \ Up Next](/v2.0.0/data/reference/webhooks/get) [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Get Authorization Info — Webflow API Documentation Information about the authorization token Access to this endpoint requires a bearer token from a [Data Client App](/data/docs/getting-started-data-clients) . ### Response Request was successful authorizationobjectOptional The Authorization object Show 7 properties applicationanyOptional ### Errors 401 Unauthorized [List Sites\ \ Up Next](/v2.0.0/data/reference/sites/list) [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Get Custom Domains — Webflow API Documentation Get a list of all custom domains related to site. Required scope | `sites:read` ### Path parameters site\_idstringRequired Unique identifier for a Site ### Response Request was successful customDomainslist of objectsOptional Show 3 properties ### Errors 401 Unauthorized 403 Forbidden 404 Not Found 429 Too Many Requests 500 Internal Server Error [Publish Site\ \ Up Next](/v2.0.0/data/reference/sites/publish) [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Get Site — Webflow API Documentation Get details of a site. Required scope | `sites:read` ### Path parameters site\_idstringRequired Unique identifier for a Site ### Response Request was successful idstring Unique identifier for the Site workspaceIdstringOptional Unique identifier for the Workspace createdOndatetimeOptional Date the Site was created displayNamestringOptional Name given to Site shortNamestringOptional Slugified version of name lastPublisheddatetimeOptional Date the Site was last published lastUpdateddatetimeOptional Date the Site was last updated previewUrlstringOptional`format: "uri"` URL of a generated image for the given Site timeZonestringOptional Site timezone set under Site Settings parentFolderIdstring or nullOptional The ID of the parent folder the Site exists in customDomainslist of objectsOptional Show 3 properties localesobjectOptional Show 2 properties dataCollectionEnabledbooleanOptional Indicates if data collection is enabled for the site. dataCollectionTypeenumOptional Allowed values: alwaysoptOutdisabled The type of data collection enabled for the site. ### Errors 400 Bad Request 401 Unauthorized 404 Not Found 429 Too Many Requests 500 Internal Server Error [Get Custom Domains\ \ Up Next](/v2.0.0/data/reference/sites/get-custom-domain) [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # List Sites — Webflow API Documentation List of all sites the provided access token is able to access. Required scope | `sites:read` ### Response Request was successful siteslist of objectsOptional Show 14 properties ### Errors 401 Unauthorized 404 Not Found 429 Too Many Requests [Get Site\ \ Up Next](/v2.0.0/data/reference/sites/get) [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Remove Webhook — Webflow API Documentation Remove a Webhook Required scope: `sites:read` ### Path parameters webhook\_idstringRequired Unique identifier for a Webhook ### Response Request was successful. No Content is returned. No content ### Errors 400 Bad Request 401 Unauthorized 404 Not Found 429 Too Many Requests 500 Internal Server Error [All Events\ \ Up Next](/v2.0.0/data/reference/all-events) [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Publish Site — Webflow API Documentation Publishes a site to one or more more domains. ##### Endpoint-specific rate limit This endpoint has a limit of one successful publish queue per minute. Required scope | `sites:write` ### Path parameters site\_idstringRequired Unique identifier for a Site ### Request This endpoint expects an object. customDomainslist of stringsOptional Array of Custom Domain IDs to publish publishToWebflowSubdomainbooleanOptionalDefaults to `false` Choice of whether to publish to the default Webflow Subdomain ### Response Request accepted customDomainslist of objectsOptional Array of domains objects Show 3 properties publishToWebflowSubdomainbooleanOptionalDefaults to `false` Flag for publishing to webflow.io subdomain ### Errors 400 Bad Request 401 Unauthorized 403 Forbidden 404 Not Found 429 Too Many Requests [List Pages\ \ Up Next](/v2.0.0/data/reference/pages-and-components/pages/list) [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Get Webhook — Webflow API Documentation Get a specific Webhook instance Required scope: `sites:read` ### Path parameters webhook\_idstringRequired Unique identifier for a Webhook ### Response Request was successful idstringOptional Unique identifier for the Webhook registration triggerTypeenumOptional The type of event that triggered the request. See the the documentation for details on [supported events](/data/reference/all-events) . Show 15 enum values urlstringOptional URL to send the Webhook payload to workspaceIdstringOptional Unique identifier for the Workspace the Webhook is registered in siteIdstringOptional Unique identifier for the Site the Webhook is registered in filterobjectOptional Only supported for the `form_submission` trigger type. Filter for the form you want Webhooks to be sent for. Show property lastTriggereddatetimeOptional Date the Webhook instance was last triggered createdOndatetimeOptional Date the Webhook registration was created ### Errors 400 Bad Request 401 Unauthorized 404 Not Found 429 Too Many Requests 500 Internal Server Error [Create Webhook\ \ Up Next](/v2.0.0/data/reference/webhooks/create) [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Register an App — Webflow API Documentation To start developing a Webflow App, you’ll first need to register an App to a Webflow Workspace. This guide will walk you through creating and registering your App with Webflow. Prerequisites ------------- * A Webflow account. * A Webflow Workspace with Admin permissions. Need a workspace? [Apply for a free Developer Workspace.](/v2.0.0/data/docs/developer-workspace) ##### Admin access required To protect your workspace’s security and maintain compliance, only Workspace admins have privileged access to: * Create and configure new Apps * View and rotate client secrets * Upload App bundles * Modify App permissions and details Register an App --------------- ![Webflow Dashboard](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/pages/v2.0.0/Apps/getting-started-apps/register-an-app/Webflow-Dashboard.png) [1](/v2.0.0/data/docs/register-an-app#open-the-webflow-dashboard) ### Open the Webflow Dashboard Login to your Webflow account and navigate to your Dashboard. [2](/v2.0.0/data/docs/register-an-app#choose-a-workspace) ### Choose a Workspace Select the Workspace for your App. While you can use any workspace, we recommend creating a dedicated development Workspace to keep your Apps organized and separate from production environments. ##### New to Webflow? Get started with our [free Developer Workspace](/v2.0.0/data/docs/developer-workspace) designed for testing and developing Apps. [3](/v2.0.0/data/docs/register-an-app#navigate-to-workspace-settings) ### Navigate to Workspace settings From the “settings” menu on the left sidebar, select the “Apps & Integrations” tab. Scroll down to the “App Development” section and click the “Create an App” button. This will open the App creation modal. ![App Development section](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/pages/v2.0.0/Apps/getting-started-apps/register-an-app/App-Development.png) [4](/v2.0.0/data/docs/register-an-app#add-app-details) ### Add App details ![App Details](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/pages/v2.0.0/Apps/getting-started-apps/register-an-app/App-Details.png) Here, you’ll add the following basic information for your App: * **Name:** The name of your App * **Description:** A brief summary of your App’s purpose (140 characters max) * **Icon:** An icon to represent your App * **Homepage URL:** A valid HTTPS link to your App’s website For more details on how your App will appear in the Marketplace, see our [App Listing guide](/v2.0.0/data/docs/listing-your-app) . ###### Installation settings (optional) If you’d prefer to restrict your App’s installation to a specific site, you can configure your App’s installation settings by toggling this option in the modal. This setting allows users to authorize your App for a single site, rather than the default behavior of authorizing it for multiple sites or an entire Workspace. [5](/v2.0.0/data/docs/register-an-app#define-app-capabilities) ### Define App capabilities Click the “Continue” button to define your App’s capabilities. ![App Capabilities](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/pages/v2.0.0/Apps/getting-started-apps/register-an-app/select-scopes.gif) Here, you’ll select the capabilities your App needs to function. You can choose from the following capabilities: * **[Designer Extension](/v2.0.0/data/docs/designer-extensions) :** Enables your App to interact with the Webflow Designer. * **[Data Client](/v2.0.0/data/docs/data-clients) :** Enables your App to access and update data from Webflow’s servers. You can select one or both of these capabilities. [Selecting both will allow your App to interact with both Webflow’s servers and the Webflow Designer as a hybrid app.](/v2.0.0/data/docs/hybrid-apps) ###### Data Client: OAuth configuration If you’ve selected the Data Client capability, you’ll need to configure the scopes and redirect URIs for your App. 1. Select the scopes your App needs to function. [Learn more about scopes in our short guide.](https://developers.webflow.com/data/reference/scopes) 2. Add a valid redirect URI for the OAuth authorization flow. This URI is where users will be redirected after authorizing your App. [Learn more about OAuth and Redirect URIs](/v2.0.0/data/reference/oauth-app) . You can always update this URI later. Once you’ve configured your App’s capabilities, click the “Create app” button to complete the registration process. [6](/v2.0.0/data/docs/register-an-app#review-your-app) ### Review your App ![App details](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/pages/v2.0.0/Apps/getting-started-apps/register-an-app/Completed-App-Details.png) Congratulations! You’ve successfully registered your App in Webflow. On successful registration, your App will be displayed in the App Development section. You’ll see key details including the Client ID and Client Secret. From here, you can also update your App’s details, capabilities, and installation settings. ###### Designer Extension: App information If you’ve selected the Designer Extension capability, you’ll see additional information specific to Designer Extensions: * **Publish Extension Version:** This button will open a modal where you can upload a new version of your Designer Extension and add version notes. For detailed publishing instructions, see our [Publishing Designer Extensions guide](/v2.0.0/designer/docs/publishing-your-app) . * **Designer Extension URI:** The URI where your extension will be served within the Webflow Designer iframe. This URI is important when configuring CORS settings for your extension. * **Versions:** View all previously published versions of your Designer Extension. This helps you track your extension’s version history and rollback if needed. ##### App Security * Never commit your Client Secret to version control * Rotate your Client Secret if it’s ever exposed * Store secrets in environment variables or a secure secret management system * Implement proper CORS policies for Designer Extensions Troubleshooting --------------- ###### Why am I getting an Invalid Redirect URI error? Ensure your redirect URI: * Uses HTTPS. If you’re developing locally, consider using [ngrok](/v2.0.0/data/docs/getting-started-data-clients#working-with-ngrok) to create a secure tunnel to your local server. * Matches exactly what you’ve registered ###### Why can't I see the App Development section? Verify that: * You’re in the correct Workspace * You have Admin permissions on the Workspace * Your account has been verified and has 2-factor authentication enabled Next Steps ---------- To see your new App in action, follow these Quickstart guides, which will get your App up and running in Webflow. [Data Client\ \ Access and manipulate data from Webflow’s servers.](/v2.0.0/data/docs/getting-started-data-clients) [Designer Extension\ \ Interact with the Webflow Designer.](/v2.0.0/designer/docs/getting-started-designer-extensions) [Hybrid App\ \ Use both the Data Client and Designer Extension in tandem.](/data/docs/getting-started-3) [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # All Events — Webflow API Documentation `form_submission` ----------------- Details about a form submission #### Required Scope | `forms:read` #### Properties | Field | Type | Description | | --- | --- | --- | | `name` | string | The name of the form | | `siteId` | string | The id of the site that the form was submitted from | | `data` | object | The data submitted in the form (key-value pairs for each field) | | `submittedAt` | string | The timestamp the form was submitted | | `formId` | string | The id of the form submission | #### Example Payload ` | | | | --- | --- | | 1 | { | | 2 | "triggerType": "form_submission", | | 3 | "payload": { | | 4 | "name": "Contact Us", | | 5 | "siteId": "65427cf400e02b306eaa049c", | | 6 | "data": { | | 7 | "First Name": "Zaphod", | | 8 | "Last Name": "Beeblebrox", | | 9 | "email": "zaphod@heartofgold.ai", | | 10 | "Phone Number": 15550000000 | | 11 | }, | | 12 | "schema": [ | | 13 | { | | 14 | "fieldName": "First Name", | | 15 | "fieldType": "FormTextInput", | | 16 | "fieldElementId": "285042f7-d554-dc7f-102c-aa10d6a2d2c4" | | 17 | }, | | 18 | { | | 19 | "fieldName": "Last Name", | | 20 | "fieldType": "FormTextInput", | | 21 | "fieldElementId": "285042f7-d554-dc7f-102c-aa10d6a2d2c5" | | 22 | }, | | 23 | { | | 24 | "fieldName": "email", | | 25 | "fieldType": "FormTextInput", | | 26 | "fieldElementId": "285042f7-d554-dc7f-102c-aa10d6a2d2c6" | | 27 | }, | | 28 | { | | 29 | "fieldName": "Phone Number", | | 30 | "fieldType": "FormTextInput", | | 31 | "fieldElementId": "285042f7-d554-dc7f-102c-aa10d6a2d2c7" | | 32 | } | | 33 | ], | | 34 | "submittedAt": "2022-09-14T12:35:16.117Z", | | 35 | "id": "6321ca84df3949bfc6752327", | | 36 | "formId": "65429eadebe8a9f3a30f62d0", | | 37 | "formElementId": "4e038d2c-6a1e-4953-7be9-a59a2b453177" | | 38 | } | | 39 | } | ` * * * `site_publish` -------------- Details about a site publish event #### Required Scope | `sites:read` #### Properties | Field | Type | Description | | --- | --- | --- | | `siteId` | string | The identifier for the site that was published | | `publishedOn` | string | The timestamp of the publish event (ISO8601 string) | | `domains` | \[string\] | The domains that the site was published to | | `publishedBy` | object | The name of the user who published the site | #### Example Payload ` | | | | --- | --- | | 1 | { | | 2 | "triggerType": "site_publish", | | 3 | "payload": { | | 4 | "siteId": "62749158efef318abc8d5a0f", | | 5 | "publishedOn": "2023-07-31T12:34:56.789Z", | | 6 | "domains": ["my-website.webflow.io"], | | 7 | "publishedBy": { | | 8 | "displayName": "Some One" | | 9 | } | | 10 | } | | 11 | } | ` * * * `page_created` -------------- Details about a new page event #### Required Scope | `pages:read` #### Properties | Field | Type | Description | | --- | --- | --- | | `siteId` | string | ID of the Site that the page is on | | `pageId` | string | ID of the new page | | `pageTitle` | string | Title of the page | | `createdOn` | string | Timestamp of when the page was created, as an ISO8601 string | #### Example ` | | | | --- | --- | | 1 | { | | 2 | "triggerType": "page_created", | | 3 | "payload": { | | 4 | "siteId": "63499e4e6e9ed55a17e42b68", | | 5 | "pageId": "641371d477a18c936fe237cd", | | 6 | "pageTitle": "This is a New Page", | | 7 | "createdOn": "2023-03-16T19:45:24.311Z" | | 8 | } | | 9 | } | ` * * * `page_metadata_updated` ----------------------- Metadata of page is updated and published. #### Required Scope | `pages:read` #### Properties | Field | Type | Description | | --- | --- | --- | | `siteId` | string | ID of the Site that the page is on | | `pageId` | string | ID of the new page | | `pageTitle` | string | Title of the page | | `lastUpdated` | string | Timestamp of when the page was updated as an ISO8601 string | #### Example ` | | | | --- | --- | | 1 | { | | 2 | "triggerType": "page_metadata_updated", | | 3 | "payload": { | | 4 | "siteId": "63499e4e6e9ed55a17e42b68", | | 5 | "pageId": "641371d477a18c936fe237cd", | | 6 | "pageTitle": "Home", | | 7 | "lastUpdated": "2023-03-16T19:48:48.499Z" | | 8 | } | | 9 | } | ` * * * `page_deleted` -------------- The information about a deleted page #### Required Scope | `pages:read` #### Properties | Field | Type | Description | | --- | --- | --- | | `siteId` | string | ID of the Site that the page is on | | `pageId` | string | ID of the new page | | `pageTitle` | string | Title of the page | | `deletedOn` | string | Timestamp of when the page was deleted as an ISO8601 string | #### Example ` | | | | --- | --- | | 1 | { | | 2 | "triggerType": "page_deleted", | | 3 | "payload": { | | 4 | "siteId": "63499e4e6e9ed55a17e42b68", | | 5 | "pageId": "63499e4e6e9ed5abbfe42b69", | | 6 | "pageTitle": "Old Home", | | 7 | "deletedOn": "2023-03-16T19:51:33.068Z" | | 8 | } | | 9 | } | ` * * * `ecomm_new_order` ----------------- The information about the new order #### Required Scope | `ecommerce:read` #### Properties | Field | Type | Description | | --- | --- | --- | | `orderId` | string | The order id. Will usually be 6 hex characters, but can also be 9 hex characters if the site has a very large number of orders. Randomly assigned. | | `status` | string | One of `pending`, `unfulfilled`, `fulfilled`, `disputed`, `dispute-lost`, or `refunded` | | `comment` | string | A comment string for this order editable by API user (not used by Webflow). | | `orderComment` | string | A comment that the customer left when making their order | | `acceptedOn` | string | The ISO8601 timestamp that an order was placed. | | `disputedOn` | string | If an order was disputed by the customer, then this key will be set with the ISO8601 timestamp that Stripe notifies Webflow. Null if not disputed. | | `disputeUpdatedOn` | string | If an order was disputed by the customer, then this key will be set with the ISO8601 timestamp of the last time that we got an update. Null if not disputed. | | `disputeLastStatus` | string | If an order was disputed by the customer, then this key will be set with the [dispute’s status](https://stripe.com/docs/api#dispute_object-status)
. | | `fulfilledOn` | string | If an order was marked as ‘fulfilled’, then this is the ISO8601 timestamp when that happened. | | `refundedOn` | string | If an order was refunded, this is the ISO8601 of when that happened. | | `customerPaid` | [OrderAmount](/v2.0.0/data/reference/all-events#orderamount) | An instance of the [OrderAmount](/v2.0.0/data/reference/all-events#orderamount)
object. | | `netAmount` | [OrderAmount](/v2.0.0/data/reference/all-events#orderamount) | An instance of the [OrderAmount](/v2.0.0/data/reference/all-events#orderamount)
object. | | `requiresShipping` | boolean | A boolean indicating whether the order contains one or more purchased items that require shipping. | | `shippingProvider` | string | A string editable by the API user to note the shipping provider used (not used by Webflow). | | `shippingTracking` | string | A string editable by the API user to note the shipping tracking number for the order (not used by Webflow). | | `customerInfo` | [OrderCustomerInfo](/v2.0.0/data/reference/all-events#ordercustomerinfo) | An instance of the [OrderCustomerInfo](/v2.0.0/data/reference/all-events#ordercustomerinfo)
object. | | `allAddresses` | \[[OrderAddress](/v2.0.0/data/reference/all-events#orderaddress)
\] | All addresses provided by the customer during the ordering flow. | | `shippingAddress` | [OrderAddress](/v2.0.0/data/reference/all-events#orderaddress) | An instance of the [OrderAddress](/v2.0.0/data/reference/all-events#orderaddress)
object. | | `billingAddress` | [OrderAddress](/v2.0.0/data/reference/all-events#orderaddress) | An instance of the [OrderAddress](/v2.0.0/data/reference/all-events#orderaddress)
object. | | `purchasedItems` | \[[OrderPurchasedItem](/v2.0.0/data/reference/all-events#orderpurchaseditem)
\] | An array of all things that the customer purchased. | | `stripeDetails` | [StripeDetails](/v2.0.0/data/reference/all-events#stripedetails) | An instance of the [StripeDetails](/v2.0.0/data/reference/all-events#stripedetails)
object. | | `stripeCard` | [StripeCard](/v2.0.0/data/reference/all-events#stripecard) | An instance of the [StripeCard](/v2.0.0/data/reference/all-events#stripecard)
object. | | `totals` | [OrderTotals](/v2.0.0/data/reference/all-events#ordertotals) | An instance of the [OrderTotals](/v2.0.0/data/reference/all-events#ordertotals)
object. | | `customData` | \[object\] | An array of additional inputs for custom order data gathering. Each object in the array represents an input with a name, and a textInput, textArea, or checkbox value. | | `downloadFiles` | \[[OrderDownloadedFile](/v2.0.0/data/reference/all-events#orderdownloadedfile)
\] | An array of downloadable file objects. | #### Example Payload ` | | | | --- | --- | | 1 | { | | 2 | "triggerType": "ecomm_new_order", | | 3 | "payload": { | | 4 | "orderId": "dfa-3f1", | | 5 | "status": "unfulfilled", | | 6 | "comment": "", | | 7 | "orderComment": "", | | 8 | "acceptedOn": "2018-12-03T22:06:15.761Z", | | 9 | "disputedOn": null, | | 10 | "disputeUpdatedOn": null, | | 11 | "disputeLastStatus": null, | | 12 | "fulfilledOn": null, | | 13 | "refundedOn": null, | | 14 | "customerPaid": { | | 15 | "unit": "USD", | | 16 | "value": 6099, | | 17 | "string": "$60.99" | | 18 | }, | | 19 | "netAmount": { | | 20 | "unit": "USD", | | 21 | "value": 5892, | | 22 | "string": "$58.92" | | 23 | }, | | 24 | "requiresShipping": true, | | 25 | "shippingProvider": null, | | 26 | "shippingTracking": null, | | 27 | "customerInfo": { | | 28 | "fullName": "Customerio Namen", | | 29 | "email": "renning+customer@webflow.com" | | 30 | }, | | 31 | "allAddresses": [ | | 32 | { | | 33 | "type": "billing", | | 34 | "addressee": "Customerio Namen", | | 35 | "line1": "123 Example Rd", | | 36 | "line2": "", | | 37 | "city": "Examplesville", | | 38 | "state": "CA", | | 39 | "country": "US", | | 40 | "postalCode": "90012" | | 41 | }, | | 42 | { | | 43 | "type": "shipping", | | 44 | "addressee": "Customerio Namen", | | 45 | "line1": "123 Example Rd", | | 46 | "line2": "", | | 47 | "city": "Examplesville", | | 48 | "state": "CA", | | 49 | "country": "US", | | 50 | "postalCode": "90012" | | 51 | } | | 52 | ], | | 53 | "shippingAddress": { | | 54 | "type": "shipping", | | 55 | "addressee": "Customerio Namen", | | 56 | "line1": "123 Example Rd", | | 57 | "line2": "", | | 58 | "city": "Examplesville", | | 59 | "state": "CA", | | 60 | "country": "US", | | 61 | "postalCode": "90012" | | 62 | }, | | 63 | "billingAddress": { | | 64 | "type": "billing", | | 65 | "addressee": "Customerio Namen", | | 66 | "line1": "123 Example Rd", | | 67 | "line2": "", | | 68 | "city": "Examplesville", | | 69 | "state": "CA", | | 70 | "country": "US", | | 71 | "postalCode": "90012" | | 72 | }, | | 73 | "purchasedItems": [ | | 74 | { | | 75 | "count": 1, | | 76 | "rowTotal": { | | 77 | "unit": "USD", | | 78 | "value": 5500, | | 79 | "string": "$55.00" | | 80 | }, | | 81 | "productId": "5eb9fd05caef491eb9757183", | | 82 | "productName": "White Cup", | | 83 | "productSlug": "white-cup", | | 84 | "variantId": "5eb9fcace279761d8199790c", | | 85 | "variantName": "white-cup_default_sku", | | 86 | "variantSlug": "white-cup-default-sku", | | 87 | "variantImage": { | | 88 | "fileId": "5bfedb42bab0ad90fa7dad2e", | | 89 | "url": "https://d1otoma47x30pg.cloudfront.net/5bfedb42bab0ad90fa7dac03/5bfedb42bab0ad90fa7dad2e_5bb3d019b3465c6e8a324dd7_458036-unsplas.png" | | 90 | }, | | 91 | "variantPrice": { | | 92 | "unit": "USD", | | 93 | "value": 5500, | | 94 | "string": "$55.00" | | 95 | }, | | 96 | "height": 7, | | 97 | "length": 2, | | 98 | "weight": 5, | | 99 | "width": 4 | | 100 | } | | 101 | ], | | 102 | "purchasedItemsCount": 1, | | 103 | "stripeDetails": { | | 104 | "refundReason": null, | | 105 | "refundId": null, | | 106 | "disputeId": null, | | 107 | "chargeId": "ch_1DdPYQKMjGA7k9mI2AKiBY6u", | | 108 | "customerId": "cus_E5ajeiWNHEtcAW" | | 109 | }, | | 110 | "stripeCard": { | | 111 | "last4": "4242", | | 112 | "brand": "Visa", | | 113 | "ownerName": "Customerio Namen", | | 114 | "expires": { | | 115 | "year": 2023, | | 116 | "month": 12 | | 117 | } | | 118 | }, | | 119 | "totals": { | | 120 | "subtotal": { | | 121 | "unit": "USD", | | 122 | "value": 5500, | | 123 | "string": "$55.00" | | 124 | }, | | 125 | "extras": [ | | 126 | { | | 127 | "type": "tax", | | 128 | "name": "State Taxes", | | 129 | "description": "CA Taxes (6.25%)", | | 130 | "price": { | | 131 | "unit": "USD", | | 132 | "value": 344, | | 133 | "string": "$3.44" | | 134 | } | | 135 | }, | | 136 | { | | 137 | "type": "tax", | | 138 | "name": "County Taxes", | | 139 | "description": "LOS ANGELES Taxes (1.00%)", | | 140 | "price": { | | 141 | "unit": "USD", | | 142 | "value": 55, | | 143 | "string": "$0.55" | | 144 | } | | 145 | }, | | 146 | { | | 147 | "type": "tax", | | 148 | "name": "Special District Taxes", | | 149 | "description": "Special District Taxes (2.25%)", | | 150 | "price": { | | 151 | "unit": "USD", | | 152 | "value": 124, | | 153 | "string": "$1.24" | | 154 | } | | 155 | }, | | 156 | { | | 157 | "type": "shipping", | | 158 | "name": "Flat Rate", | | 159 | "description": "", | | 160 | "price": { | | 161 | "unit": "USD", | | 162 | "value": 599, | | 163 | "string": "$5.99" | | 164 | } | | 165 | }, | | 166 | { | | 167 | "type": "discount", | | 168 | "name": "Discount (SAVE5)", | | 169 | "description": "", | | 170 | "price": { | | 171 | "unit": "USD", | | 172 | "value": -500, | | 173 | "string": "-$ 5.00 USD" | | 174 | } | | 175 | } | | 176 | ], | | 177 | "total": { | | 178 | "unit": "USD", | | 179 | "value": 6122, | | 180 | "string": "$61.22" | | 181 | } | | 182 | }, | | 183 | "customData": [ | | 184 | { | | 185 | "textInput": "(415) 123-4567", | | 186 | "name": "Telephone" | | 187 | }, | | 188 | { | | 189 | "textArea": "Happy birthday Mom!", | | 190 | "name": "Gift note" | | 191 | }, | | 192 | { | | 193 | "checkbox": true, | | 194 | "name": "Send as gift" | | 195 | } | | 196 | ], | | 197 | "downloadFiles": [ | | 198 | { | | 199 | "id": "5e9a5eba75e0ac242e1b6f64", | | 200 | "name": "The modern web design process - Webflow Ebook.pdf", | | 201 | "url": "https://webflow.com/dashboard/download-digital-product?payload=5d93ba5e38c6b0160ab711d3;e7634a;5eb1aac72912ec06f561278c;5e9a5eba75e0ac242e1b6f63:ka2nehxy:4a1ee0a632feaab94294350087215ed89533f2f530903e3b933b638940e921aa" | | 202 | }, | | 203 | { | | 204 | "id": "5e9a5eba75e0ac242e1b6f63", | | 205 | "name": "The freelance web designers guide - Webflow Ebook.pdf", | | 206 | "url": "https://webflow.com/dashboard/download-digital-product?payload=5d93ba5e38c6b0160ab711d3;e7634a;5dd44c493543b37d5449b3cd;5e9a5eba75e0ac242e1b6f63:ka2nehxy:6af5adf7c6fff7a3b0f54404fac1be492ac6f1ed5340416f1fe27c5fd4dd8079" | | 207 | } | | 208 | ] | | 209 | } | | 210 | } | ` * * * `ecomm_order_changed` --------------------- The information about the order that changed #### Required Scope | `ecommerce:read` #### Properties | Field | Type | Description | | --- | --- | --- | | `orderId` | string | The order id. Will usually be 6 hex characters, but can also be 9 hex characters if the site has a very large number of orders. Randomly assigned. | | `status` | string | One of `pending`, `unfulfilled`, `fulfilled`, `disputed`, `dispute-lost`, or `refunded` | | `comment` | string | A comment string for this order editable by API user (not used by Webflow). | | `orderComment` | string | A comment that the customer left when making their order | | `acceptedOn` | string | The ISO8601 timestamp that an order was placed. | | `disputedOn` | string | If an order was disputed by the customer, then this key will be set with the ISO8601 timestamp that Stripe notifies Webflow. Null if not disputed. | | `disputeUpdatedOn` | string | If an order was disputed by the customer, then this key will be set with the ISO8601 timestamp of the last time that we got an update. Null if not disputed. | | `disputeLastStatus` | string | If an order was disputed by the customer, then this key will be set with the [dispute’s status](https://stripe.com/docs/api#dispute_object-status)
. | | `fulfilledOn` | string | If an order was marked as ‘fulfilled’, then this is the ISO8601 timestamp when that happened. | | `refundedOn` | string | If an order was refunded, this is the ISO8601 of when that happened. | | `customerPaid` | [OrderAmount](/v2.0.0/data/reference/all-events#orderamount) | An instance of the [OrderAmount](/v2.0.0/data/reference/all-events#orderamount)
object. | | `netAmount` | [OrderAmount](/v2.0.0/data/reference/all-events#orderamount) | An instance of the [OrderAmount](/v2.0.0/data/reference/all-events#orderamount)
object. | | `requiresShipping` | boolean | A boolean indicating whether the order contains one or more purchased items that require shipping. | | `shippingProvider` | string | A string editable by the API user to note the shipping provider used (not used by Webflow). | | `shippingTracking` | string | A string editable by the API user to note the shipping tracking number for the order (not used by Webflow). | | `customerInfo` | [OrderCustomerInfo](/v2.0.0/data/reference/all-events#ordercustomerinfo) | An instance of the [OrderCustomerInfo](/v2.0.0/data/reference/all-events#ordercustomerinfo)
object. | | `allAddresses` | \[[OrderAddress](/v2.0.0/data/reference/all-events#orderaddress)
\] | All addresses provided by the customer during the ordering flow. | | `shippingAddress` | [OrderAddress](/v2.0.0/data/reference/all-events#orderaddress) | An instance of the [OrderAddress](/v2.0.0/data/reference/all-events#orderaddress)
object. | | `billingAddress` | [OrderAddress](/v2.0.0/data/reference/all-events#orderaddress) | An instance of the [OrderAddress](/v2.0.0/data/reference/all-events#orderaddress)
object. | | `purchasedItems` | \[[OrderPurchasedItem](/v2.0.0/data/reference/all-events#orderpurchaseditem)
\] | An array of all things that the customer purchased. | | `stripeDetails` | [StripeDetails](/v2.0.0/data/reference/all-events#stripedetails) | An instance of the [StripeDetails](/v2.0.0/data/reference/all-events#stripedetails)
object. | | `stripeCard` | [StripeCard](/v2.0.0/data/reference/all-events#stripecard) | An instance of the [StripeCard](/v2.0.0/data/reference/all-events#stripecard)
object. | | `totals` | [OrderTotals](/v2.0.0/data/reference/all-events#ordertotals) | An instance of the [OrderTotals](/v2.0.0/data/reference/all-events#ordertotals)
object. | | `customData` | \[object\] | An array of additional inputs for custom order data gathering. Each object in the array represents an input with a name, and a textInput, textArea, or checkbox value. | | `downloadFiles` | \[[OrderDownloadedFile](/v2.0.0/data/reference/all-events#orderdownloadedfile)
\] | An array of downloadable file objects. | #### Example Payload ` | | | | --- | --- | | 1 | { | | 2 | "triggerType": "ecomm_order_changed", | | 3 | "payload": { | | 4 | "orderId": "dfa-3f1", | | 5 | "status": "unfulfilled", | | 6 | "comment": "", | | 7 | "orderComment": "", | | 8 | "acceptedOn": "2018-12-03T22:06:15.761Z", | | 9 | "disputedOn": null, | | 10 | "disputeUpdatedOn": null, | | 11 | "disputeLastStatus": null, | | 12 | "fulfilledOn": null, | | 13 | "refundedOn": null, | | 14 | "customerPaid": { | | 15 | "unit": "USD", | | 16 | "value": 6099, | | 17 | "string": "$60.99" | | 18 | }, | | 19 | "netAmount": { | | 20 | "unit": "USD", | | 21 | "value": 5892, | | 22 | "string": "$58.92" | | 23 | }, | | 24 | "requiresShipping": true, | | 25 | "shippingProvider": null, | | 26 | "shippingTracking": null, | | 27 | "customerInfo": { | | 28 | "fullName": "Customerio Namen", | | 29 | "email": "renning+customer@webflow.com" | | 30 | }, | | 31 | "allAddresses": [ | | 32 | { | | 33 | "type": "billing", | | 34 | "addressee": "Customerio Namen", | | 35 | "line1": "123 Example Rd", | | 36 | "line2": "", | | 37 | "city": "Examplesville", | | 38 | "state": "CA", | | 39 | "country": "US", | | 40 | "postalCode": "90012" | | 41 | }, | | 42 | { | | 43 | "type": "shipping", | | 44 | "addressee": "Customerio Namen", | | 45 | "line1": "123 Example Rd", | | 46 | "line2": "", | | 47 | "city": "Examplesville", | | 48 | "state": "CA", | | 49 | "country": "US", | | 50 | "postalCode": "90012" | | 51 | } | | 52 | ], | | 53 | "shippingAddress": { | | 54 | "type": "shipping", | | 55 | "addressee": "Customerio Namen", | | 56 | "line1": "123 Example Rd", | | 57 | "line2": "", | | 58 | "city": "Examplesville", | | 59 | "state": "CA", | | 60 | "country": "US", | | 61 | "postalCode": "90012" | | 62 | }, | | 63 | "billingAddress": { | | 64 | "type": "billing", | | 65 | "addressee": "Customerio Namen", | | 66 | "line1": "123 Example Rd", | | 67 | "line2": "", | | 68 | "city": "Examplesville", | | 69 | "state": "CA", | | 70 | "country": "US", | | 71 | "postalCode": "90012" | | 72 | }, | | 73 | "purchasedItems": [ | | 74 | { | | 75 | "count": 1, | | 76 | "rowTotal": { | | 77 | "unit": "USD", | | 78 | "value": 5500, | | 79 | "string": "$55.00" | | 80 | }, | | 81 | "productId": "5eb9fd05caef491eb9757183", | | 82 | "productName": "White Cup", | | 83 | "productSlug": "white-cup", | | 84 | "variantId": "5eb9fcace279761d8199790c", | | 85 | "variantName": "white-cup_default_sku", | | 86 | "variantSlug": "white-cup-default-sku", | | 87 | "variantImage": { | | 88 | "fileId": "5bfedb42bab0ad90fa7dad2e", | | 89 | "url": "https://d1otoma47x30pg.cloudfront.net/5bfedb42bab0ad90fa7dac03/5bfedb42bab0ad90fa7dad2e_5bb3d019b3465c6e8a324dd7_458036-unsplas.png" | | 90 | }, | | 91 | "variantPrice": { | | 92 | "unit": "USD", | | 93 | "value": 5500, | | 94 | "string": "$55.00" | | 95 | }, | | 96 | "height": 7, | | 97 | "length": 2, | | 98 | "weight": 5, | | 99 | "width": 4 | | 100 | } | | 101 | ], | | 102 | "purchasedItemsCount": 1, | | 103 | "stripeDetails": { | | 104 | "refundReason": null, | | 105 | "refundId": null, | | 106 | "disputeId": null, | | 107 | "chargeId": "ch_1DdPYQKMjGA7k9mI2AKiBY6u", | | 108 | "customerId": "cus_E5ajeiWNHEtcAW" | | 109 | }, | | 110 | "stripeCard": { | | 111 | "last4": "4242", | | 112 | "brand": "Visa", | | 113 | "ownerName": "Customerio Namen", | | 114 | "expires": { | | 115 | "year": 2023, | | 116 | "month": 12 | | 117 | } | | 118 | }, | | 119 | "totals": { | | 120 | "subtotal": { | | 121 | "unit": "USD", | | 122 | "value": 5500, | | 123 | "string": "$55.00" | | 124 | }, | | 125 | "extras": [ | | 126 | { | | 127 | "type": "tax", | | 128 | "name": "State Taxes", | | 129 | "description": "CA Taxes (6.25%)", | | 130 | "price": { | | 131 | "unit": "USD", | | 132 | "value": 344, | | 133 | "string": "$3.44" | | 134 | } | | 135 | }, | | 136 | { | | 137 | "type": "tax", | | 138 | "name": "County Taxes", | | 139 | "description": "LOS ANGELES Taxes (1.00%)", | | 140 | "price": { | | 141 | "unit": "USD", | | 142 | "value": 55, | | 143 | "string": "$0.55" | | 144 | } | | 145 | }, | | 146 | { | | 147 | "type": "tax", | | 148 | "name": "Special District Taxes", | | 149 | "description": "Special District Taxes (2.25%)", | | 150 | "price": { | | 151 | "unit": "USD", | | 152 | "value": 124, | | 153 | "string": "$1.24" | | 154 | } | | 155 | }, | | 156 | { | | 157 | "type": "shipping", | | 158 | "name": "Flat Rate", | | 159 | "description": "", | | 160 | "price": { | | 161 | "unit": "USD", | | 162 | "value": 599, | | 163 | "string": "$5.99" | | 164 | } | | 165 | }, | | 166 | { | | 167 | "type": "discount", | | 168 | "name": "Discount (SAVE5)", | | 169 | "description": "", | | 170 | "price": { | | 171 | "unit": "USD", | | 172 | "value": -500, | | 173 | "string": "-$ 5.00 USD" | | 174 | } | | 175 | } | | 176 | ], | | 177 | "total": { | | 178 | "unit": "USD", | | 179 | "value": 6122, | | 180 | "string": "$61.22" | | 181 | } | | 182 | }, | | 183 | "customData": [ | | 184 | { | | 185 | "textInput": "(415) 123-4567", | | 186 | "name": "Telephone" | | 187 | }, | | 188 | { | | 189 | "textArea": "Happy birthday Mom!", | | 190 | "name": "Gift note" | | 191 | }, | | 192 | { | | 193 | "checkbox": true, | | 194 | "name": "Send as gift" | | 195 | } | | 196 | ], | | 197 | "downloadFiles": [ | | 198 | { | | 199 | "id": "5e9a5eba75e0ac242e1b6f64", | | 200 | "name": "The modern web design process - Webflow Ebook.pdf", | | 201 | "url": "https://webflow.com/dashboard/download-digital-product?payload=5d93ba5e38c6b0160ab711d3;e7634a;5eb1aac72912ec06f561278c;5e9a5eba75e0ac242e1b6f63:ka2nehxy:4a1ee0a632feaab94294350087215ed89533f2f530903e3b933b638940e921aa" | | 202 | }, | | 203 | { | | 204 | "id": "5e9a5eba75e0ac242e1b6f63", | | 205 | "name": "The freelance web designers guide - Webflow Ebook.pdf", | | 206 | "url": "https://webflow.com/dashboard/download-digital-product?payload=5d93ba5e38c6b0160ab711d3;e7634a;5dd44c493543b37d5449b3cd;5e9a5eba75e0ac242e1b6f63:ka2nehxy:6af5adf7c6fff7a3b0f54404fac1be492ac6f1ed5340416f1fe27c5fd4dd8079" | | 207 | } | | 208 | ] | | 209 | } | | 210 | } | ` * * * `ecomm_inventory_changed` ------------------------- The information about the inventory item that changed #### Required Scope | `ecommerce:read` #### Properties | Field | Type | Description | | --- | --- | --- | | `id` | string | Unique identifier for a SKU item | | `quantity` | number | Total quantity of items remaining in inventory (if finite) | | `inventoryType` | string | String enum of `infinite` or `finite` | #### Example Payload ` | | | | --- | --- | | 1 | { | | 2 | "triggerType": "ecomm_inventory_changedr", | | 3 | "payload": { | | 4 | "id": "5bfedb42bab0ad90fa7dad39", | | 5 | "quantity": 83, | | 6 | "inventoryType": "finite" | | 7 | } | | 8 | } | ` * * * `user_account_added` -------------------- The information about the user account that was added #### Required Scope | `users:read` #### Properties | Field | Type | Description | | --- | --- | --- | | `id` | string | Unique identifier for the User | | `isEmailVerified` | boolean | Indicates whether the user has verified their email address | | `lastUpdated` | string | The timestamp the user was updated | | `createdOn` | string | The timestamp the user was created | | `status` | string | The status of the user | #### Example Payload ` | | | | --- | --- | | 1 | { | | 2 | "triggerType": "user_account_added", | | 3 | "payload": { | | 4 | "id": "6287ec36a841b25637c663df", | | 5 | "isEmailVerified": true, | | 6 | "lastUpdated": "2022-05-20T13:46:12.093Z", | | 7 | "createdOn": "2022-05-20T13:46:12.093Z", | | 8 | "status": "verified", | | 9 | "accessGroups": [ | | 10 | { | | 11 | "slug": "webflowers", | | 12 | "type": "admin" | | 13 | } | | 14 | ], | | 15 | "data": { | | 16 | "accept-privacy": false, | | 17 | "accept-communications": false, | | 18 | "email": "Some.One@home.com", | | 19 | "name": "Some One" | | 20 | } | | 21 | } | | 22 | } | ` * * * `user_account_updated` ---------------------- The information about the user account that was updated #### Required Scope | `users:read` #### Properties | Field | Type | Description | | --- | --- | --- | | `id` | string | Unique identifier for the User | | `isEmailVerified` | boolean | Indicates whether the user has verified their email address | | `lastUpdated` | string | The timestamp the user was updated | | `createdOn` | string | The timestamp the user was created | | `status` | string | The status of the user | | `accessGroups` | array | A list of access groups the user belongs to | #### Example Payload ` | | | | --- | --- | | 1 | { | | 2 | "triggerType": "user_account_updated", | | 3 | "payload": { | | 4 | "id": "6287ec36a841b25637c663df", | | 5 | "isEmailVerified": true, | | 6 | "lastUpdated": "2022-05-20T13:46:12.093Z", | | 7 | "createdOn": "2022-05-20T13:46:12.093Z", | | 8 | "status": "verified", | | 9 | "accessGroups": [ | | 10 | { | | 11 | "slug": "webflowers", | | 12 | "type": "admin" | | 13 | } | | 14 | ], | | 15 | "data": { | | 16 | "accept-privacy": false, | | 17 | "accept-communications": false, | | 18 | "email": "Some.One@home.com", | | 19 | "name": "Some One" | | 20 | } | | 21 | } | | 22 | } | ` * * * `user_account_deleted` ---------------------- The information about the user account that was deleted #### Required Scope | `users:read` #### Properties | Field | Type | Description | | --- | --- | --- | | `id` | string | Unique identifier for the User | | `isEmailVerified` | boolean | Indicates whether the user has verified their email address | | `lastUpdated` | string | The timestamp the user was updated | | `createdOn` | string | The timestamp the user was created | | `status` | string | The status of the user | | `accessGroups` | array | A list of access groups the user belongs to | #### Example Payload ` | | | | --- | --- | | 1 | { | | 2 | "triggerType": "user_account_deleted", | | 3 | "payload": { | | 4 | "id": "6287ec36a841b25637c663df", | | 5 | "isEmailVerified": true, | | 6 | "lastUpdated": "2022-05-20T13:46:12.093Z", | | 7 | "createdOn": "2022-05-20T13:46:12.093Z", | | 8 | "status": "verified", | | 9 | "accessGroups": [ | | 10 | { | | 11 | "slug": "webflowers", | | 12 | "type": "admin" | | 13 | } | | 14 | ], | | 15 | "data": { | | 16 | "accept-privacy": false, | | 17 | "accept-communications": false, | | 18 | "email": "Some.One@home.com", | | 19 | "name": "Some One" | | 20 | } | | 21 | } | | 22 | } | ` * * * `collection_item_created` ------------------------- The information about the collection item that was created #### Required Scope | `cms:read` #### Properties | Field | Type | Description | | --- | --- | --- | | `id` | string | Unique identifier for the Item | | `siteId` | string | Unique identifier for the Site where the Collection lives | | `workspaceId` | string | Unique identifier for the Workspace where the Site lives | | `collectionId` | string | Unique identifier for the Collection | | `lastPublished` | string | Date and time of when the item was last published, will be null if the item has never been published. | | `lastUpdated` | string | Date and time of when the item was last updated | | `createdOn` | string | Date and time of when the item was created | | `isArchived` | boolean | Boolean determining if the Item is set to archived | | `isDraft` | boolean | Boolean determining if the Item is set to draft | | `fieldData` | object | Object containing the item details structured within the Collection’s schema. If the item is localized, an object with item data for each locale will be returned. | #### Example Payload ###### Single Locale ###### Multiple Locales ` | | | | --- | --- | | 1 | { | | 2 | "triggerType": "collection_item_created", | | 3 | "payload": { | | 4 | "id": "582b900cba19143b2bb8a759", | | 5 | "siteId": "1111111", | | 6 | "workspaceId": "1111111", | | 7 | "collectionId": "1111111", | | 8 | "lastPublished": null, | | 9 | "lastUpdated": "2023-03-27T22:26:40.926Z", | | 10 | "createdOn": "2023-03-27T22:26:40.926Z", | | 11 | "archived": false, | | 12 | "draft": true, | | 13 | // depends on the field schema | | 14 | "fieldData": { | | 15 | "name": "hello world", | | 16 | "slug": "hello-world", | | 17 | "favoriteColor": "#ff00ff" | | 18 | } | | 19 | } | | 20 | } | ` * * * `collection_item_changed` ------------------------- The information about the collection item that was changed #### Required Scope | `cms:read` #### Properties | Field | Type | Description | | --- | --- | --- | | `id` | string | Unique identifier for the Item | | `siteId` | string | Unique identifier for the Site where the Collection lives | | `workspaceId` | string | Unique identifier for the Workspace where the Site lives | | `collectionId` | string | Unique identifier for the Collection | | `lastPublished` | string | Date and time of when the item was last published, will be null if the item has never been published. | | `lastUpdated` | string | Date and time of when the item was last updated | | `createdOn` | string | Date and time of when the item was created | | `isArchived` | boolean | Boolean determining if the Item is set to archived | | `isDraft` | boolean | Boolean determining if the Item is set to draft | | `fieldData` | object | Object containing the item details structured within the Collection’s schema. | #### Example Payload ###### Single Locale ###### Multiple Locales ` | | | | --- | --- | | 1 | { | | 2 | "triggerType": "collection_item_changed", | | 3 | "payload": { | | 4 | "id": "582b900cba19143b2bb8a759", | | 5 | "siteId": "1111111", | | 6 | "workspaceId": "1111111", | | 7 | "collectionId": "1111111", | | 8 | "lastPublished": null, | | 9 | "lastUpdated": "2023-03-27T22:26:40.926Z", | | 10 | "createdOn": "2023-03-27T22:26:40.926Z", | | 11 | "archived": false, | | 12 | "draft": true, | | 13 | "fieldData": { | | 14 | "name": "hello world", | | 15 | "slug": "hello-world", | | 16 | "favoriteColor": "#ff00ff" | | 17 | } | | 18 | } | | 19 | } | ` * * * `collection_item_deleted` ------------------------- The results from deleting the collection item #### Required Scope | `cms:read` #### Properties | Field | Type | Description | | --- | --- | --- | | `id` | string | The unique identifier of the collection item that was deleted | | `siteId` | string | The unique identifier of the Site the Collection belongs to | | `workspaceId` | string | The unique identifier of the Workspace the related Site belongs to | | `collectionId` | string | The unique identifier of the Collection the deleted item belongs to | #### Example Payload ##### Multiple Locales If you delete an object across multiple locales, the Webhook will trigger for each locale. ` | | | | --- | --- | | 1 | { | | 2 | "triggerType": "collection_item_deleted", | | 3 | "payload": { | | 4 | "id": "647f35d49f499fe22e6dc173", | | 5 | "siteId": "63692ab61fb28552c22ba8e3", | | 6 | "workspaceId": "63499d0dd2f3b4e46108efa3", | | 7 | "collectionId": "63692ab61fb285e2ff2ba8f3" | | 8 | } | | 9 | } | ` * * * `collection_item_unpublished` ----------------------------- The results from unpublishing the collection item #### Required Scope | `cms:read` #### Properties | Field | Type | Description | | --- | --- | --- | | `id` | string | The unique identifier of the collection item that was deleted | | `siteId` | string | The unique identifier of the Site the Collection belongs to | | `workspaceId` | string | The unique identifier of the Workspace the related Site belongs to | #### Example Payload ` | | | | --- | --- | | 1 | { | | 2 | "triggerType": "collection_item_unpublished", | | 3 | "payload": { | | 4 | "id": "647f35d49f499fe22e6dc173", | | 5 | "siteId": "63692ab61fb28552c22ba8e3", | | 6 | "workspaceId": "63499d0dd2f3b4e46108efa3", | | 7 | "collectionId": "63692ab61fb285e2ff2ba8f3" | | 8 | } | | 9 | } | ` [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # FAQs and Troubleshooting — Webflow API Documentation **Frequently asked questions** ------------------------------ ### Designer Extensions ###### What frameworks and libraries can I use to build my Designer Extension? You can use any framework to build your extension as long as the output can run in a browser environment, outputs static resources, and fits within the iframe dimensions provided by Webflow. ###### How can I test my Designer Extension? You can test your Designer Extension in two ways. First, by running a local development version using the CLI command `npm run dev` and viewing your local development app on a test site. Additionally after bundling, you can upload it to Webflow to see how it runs on our CDN by installing it on a test site. ### Marketplace Apps ###### Do I have to publicly share my app on the Marketplace? To share your app beyond your development workspace, you’ll need to publish your app to the Marketplace. However, **you can choose to keep your app private and control who you share it with.** To do this, follow the submission guidelines and select the **“Private”** option on “Marketplace Visibility” section of the submission form. All private apps are reviewed in the same process as public apps by Webflow before they’re published. [Learn more about options for publishing your app in the Webflow Marketplace](/docs/submitting-your-app) . ###### Can I update my app after it's been published? Yes, you can submit updates for your Designer Extension at any time. Updates will go through the same review process as the initial submission. Use the “Submit an App” form and choose “App Update” in the “Submission Type” dropdown. **Troubleshooting** ------------------- ###### My App isn't showing up in Webflow. * Ensure that you’ve correctly bundled your App via the Webflow CLI, and uploaded your Designer Extension via the Webflow Dashboard. * Make sure you’ve added the Designer Extension to your project. You can do this in the Extensions section of the project settings. ###### I can't view/update my app credentials including the Client Secret. Only Workspace admins can edit app details, create apps, and view client secret keys. This ensures that Workspace owners and admins maintain control over permissions, app details, and new bundle uploads. Please make sure you are working on the App as a Workspace Admin, or ask your Workspace admin to share those details. ###### I can't upload a new version of my Designer Extension Bundle. Only Workspace admins can edit upload new bundles to Webflow. Please make sure you are working on the App as a Workspace Admin, or ask your Workspace admin to share those details. ###### My App isn't interacting with Webflow as expected. * Double-check your use of the Webflow Designer APIs. Make sure you’re correctly creating, modifying, and saving elements. * Be aware that the Designer APIs only allow access to content that is on the current page of the Designer, and not to any other site pages or components that don’t belong to the site. ###### I'm seeing errors in my app, but I'm not sure why. * Check the browser console for error messages. These can provide valuable information about what’s going wrong. * Make sure all of your extension’s dependencies are correctly included and accessible. ###### My app looks different in Webflow than I expected. * Remember that your Designer Extension runs in an iframe with a width determined by your App’s settings, or by using the [resizing methods included in the Designer APIs](https://developers.webflow.com/designer/reference/resize-extension) . * Check your CSS rules to make sure they’re not conflicting with Webflow’s styles. If you continue to face issues, don’t hesitate to reach out for support. [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Working with Custom Code — Webflow API Documentation This guide will demonstrate how to add custom code to a pre-configured example site. You will learn how to register scripts to a site, apply them to a page, and publish the site, illustrating the complete process of managing scripts via the API. Prerequisites ------------- * A clone of our [Code Example Site.](https://webflow.com/made-in-webflow/website/webflow-developers---script-ex-097863) * A [Webflow App](https://developers.webflow.com/data/docs/register-an-app) or a [Site Token](https://university.webflow.com/lesson/intro-to-webflow-apis?topics=cms-dynamic-content#how-to-create-an-api-token) with the following scopes: `sites:read`, `sites:write`, `pages:read`, `pages:write`, `custom_code:read`, and `custom_code:write` * An [Ngrok account and authentication token](http://ngrok.com/) . We use Ngrok to set up a secure tunnel for our App. ###### 1\. Clone the Example Site 1. **Clone the Example Webflow Project:** Clone the example Webflow site where scripts will be applied. 2. **Publish the site:** Publish the site and explore it in your browser. 3. **Navigate to the “Pointer Tracking” example:** The page will have an overview description of the example, and instructions on how to implement the code. In our finished version, once custom code is applied to the page, the “Pointer Tracking” example will show an animation that follows your pointer across the page. ###### Without Custom Code ###### With Custom Code ![Without Custom Code](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/6d4b083-Large_GIF_1230x624.gif) ###### 2\. Setup the Development Environment 1. **Clone the Project Repository** Run the following commands in your IDE to clone the example repository and install dependencies: Bash ` | | | | --- | --- | | $ | git clone https://github.com/Webflow-Examples/custom-code-examples/tree/main | | > | cd custom-code-examples | | > | npm install | | > | npm run install-project | ` 2. **Configure Environment Variables** Fill out a `.env` file with the necessary environment variables: .env ` | | | | --- | --- | | 1 | WEBFLOW_CLIENT_ID=YOUR_CLIENT_ID | | 2 | WEBFLOW_CLIENT_SECRET=YOUR_CLIENT_SECRET | | 3 | NGROK_AUTH_TOKEN=YOUR_NGROK_AUTH_TOKEN | | 4 | PORT=8080 | ` ###### 3\. Start and Authorize Your App 1. **Start the Project** Run the following command in your IDE to start the project: Bash ` | | | | --- | --- | | $ | npm run dev | ` 2. **Update App’s Redirect URI** Once the server is running, copy the Redirect URI provided in the terminal. Navigate to your Webflow Workspace dashboard, go to “Apps & Integrations,” and update the Redirect URI in your App settings. Save the changes. ###### Terminal Output ###### Update App Redirect URI ![Terminal Output](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/f684278-Screenshot_2024-06-25_at_3.07.27_PM.png) 3. **Authorize App** We’ll need to authorize the App to access the newly cloned example site. We’ve already set up the authorization flow in this example App. Navigate to `localhost:8080` and choose the workspaces or sites you want your App to access. Once authorized, you’ll be redirected to the App’s frontend. To see how we configured authorization for this App, navigate to the `backend` folder and review `controllers/authController.js`, `routes/authRoutes.js`, and `webflowClientMiddleware.js`. For more information on setting up authorization, [read through our authorization guide.](https://developers.webflow.com/data/reference/authorization) ###### 4\. Register Scripts In this step, you will register scripts necessary for implementing custom functionality on your Webflow site. The App provides three example scripts that correspond to functionalities you can implement on the example site. We’ll start with **Pointer Tracking**, a script that enables an animation to follow your pointer around on the screen. We’d like to give Jeff McAvoy at RiveFlow a special thanks for contributing this example to the Webflow developer community. 1. **Choose the Pointer Tracking Example** From the list of example scripts, select “Pointer Tracking.” Once selected, you’ll see a list of scripts to register that are marked inline or hosted. ###### Hosted Scripts ###### Inline Scripts Hosted scripts require a `hostedLocation` (the URL where the script is hosted) and an `integrityHash` to verify the script’s contents. The following controller logic in the example app automates this process: * it fetches the script from the `hostedLocation` * generates an `integrityHash` to ensure the script hasn’t been tampered with * and then uploads this information to the Webflow endpoint. This verification step ensures the script’s integrity before it’s applied to your Webflow site. backend/controllers/scriptController.js ` | | | | --- | --- | | 1 | export const registerHostedScript = async (req, res) => { | | 2 | try { | | 3 | const siteId = req.params.siteId; | | 4 | | | 5 | async function generateSRI(url) { | | 6 | const response = await fetch(url); | | 7 | const data = await response.text(); | | 8 | const integrity = Sri(data, ["sha256"]); | | 9 | return integrity; | | 10 | } | | 11 | | | 12 | const hostedLocation = req.body.hostedLocation; | | 13 | const integrityHash = await generateSRI(hostedLocation); | | 14 | | | 15 | const script = { | | 16 | hostedLocation: hostedLocation, | | 17 | integrityHash: integrityHash, | | 18 | canCopy: true, | | 19 | version: req.body.version, | | 20 | displayName: req.body.displayName | | 21 | }; | | 22 | | | 23 | const data = await req.webflow.scripts.registerHosted(siteId, script); | | 24 | res.json(data); | | 25 | } catch (error) { | | 26 | console.error("Error registering hosted script:", error); | | 27 | res.status(500).send("Failed to register hosted script"); | | 28 | } | | 29 | }; | ` 2. **Provide script details** To upload a script via the API, you’ll need to provide the following details: * **`displayName`** (_string_): The name of your script * **`version`** (_string_): The semantic version of your script. Each script must have a unique combination of `displayName` and `version`. You cannot overwrite scripts at this time. * **`canCopy`** (_Boolean_): Define whether the script can be copied on site duplication and transfer For the example we’ve already included the `hostedLocation` if it’s a hosted script, or the `sourceCode` if it’s an inline script. 3. **Click register** Depending on the type of script, inline or hosted, this button will send your script to the backend server, and then to the appropriate Webflow endpoint. * POST [https://api.webflow.com/v2/sites/{site\_id}/registered\_scripts/inline](https://developers.webflow.com/data/reference/custom-code/custom-code/register-inline) * POST [https://api.webflow.com/v2/sites/{site\_id}/registered\_scripts/hosted](https://developers.webflow.com/data/reference/custom-code/custom-code/register-hosted) 4. Once you’re finished registering your scripts, click the “Next” button. ###### 5\. Apply Scripts Now that a script has been registered to the Webflow site, you can use the API to apply scripts to either the entire site or a specific page. In this step, you will apply each script to the appropriate page for the chosen example. Scripts can be applied to one of two locations: * **Header**: Within the `` tag. * **Footer**: Right before the closing `` tag. 1. **Select a Page** Choose the page where you’ll apply the script. For this example, we’ll select the “Pointer Tracking” page. 2. **View Registered Scripts** You will see a list of scripts that have been registered to your site, populated by the [Get Scripts](https://developers.webflow.com/data/reference/custom-code/custom-code/list) endpoint. * The list includes the script ID, version, and `hostedLocation`. * Note that even inline scripts have `hostedLocation` URLs, as Webflow uploads these scripts to its CDN for serving. 3. **Apply Scripts** * **Header**: Apply the Rive.js script to the header. * **Footer**: Apply the pointer-tracking.js script to the footer. To apply the scripts we’ve registered to the page, we’ll use the [Add/Update Custom Code](https://developers.webflow.com/data/reference/custom-code/custom-code-pages/upsert-custom-code) endpoint. This endpoint requires you to add all custom code blocks to the page. Therefore, we’ll also use the [Get Custom Code](https://developers.webflow.com/data/reference/custom-code/custom-code-pages/get-custom-code) endpoint to retrieve any existing applied scripts, also known as custom code blocks, and upload a complete list of code that should be on the site. We’ve applied this logic in our example app in `backend/controllers/scriptControllers.js` JavaScript ` | | | | --- | --- | | 1 | export const upsertPageCustomCode = async (req, res) => { | | 2 | const pageId = req.params.pageId; | | 3 | const { selectedScript, version } = req.body; | | 4 | | | 5 | const applyScripts = async (scriptApplyList) => { | | 6 | try { | | 7 | const data = await req.webflow.pages.scripts.upsertCustomCode(pageId, scriptApplyList); | | 8 | res.json(data); | | 9 | } catch (error) { | | 10 | console.error("Error adding/updating page-level custom code:", error); | | 11 | res.status(500).send("Failed to add/update page-level custom code"); | | 12 | } | | 13 | }; | | 14 | | | 15 | try { | | 16 | const response = await req.webflow.pages.scripts.getCustomCode(pageId); | | 17 | const existingScripts = response.scripts \| []; | | 18 | const newScript = { | | 19 | id: selectedScript, | | 20 | location: req.query.location, | | 21 | version: version, | | 22 | }; | | 23 | existingScripts.push(newScript); | | 24 | const scriptApplyList = { | | 25 | scripts: existingScripts, | | 26 | }; | | 27 | | | 28 | console.log(scriptApplyList); | | 29 | await applyScripts(scriptApplyList); | | 30 | } catch (error) { | | 31 | console.error("Failed to fetch scripts", error); | | 32 | const scriptApplyList = { | | 33 | scripts: [ | | 34 | { | | 35 | id: selectedScript, | | 36 | location: req.query.location, | | 37 | version: version, | | 38 | }, | | 39 | ], | | 40 | }; | | 41 | await applyScripts(scriptApplyList); | | 42 | } | | 43 | }; | ` 4. **Bonus: Check the Page in the Designer** The Webflow Designer allows users to see how apps integrate code into their sites. After applying a script to a site or page, you can view it in the Designer’s settings. * Open the Webflow Designer. * Go to the page settings for “Pointer Tracking.” * Scroll down to the Custom Code section to see the script your app added. ![custom-code-app-details](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/c8671c0-Google_Keep.png) ###### 6\. Publish and View Your Site Before you can see your scripts in action, you’ll need to publish your entire site. Click the “Publish Site” button to publish your site using the [Publish Site](https://developers.webflow.com/data/reference/sites/publish) endpoint. Once your site is published, click “View Page” to go directly to your Pointer Tracking page. You should now see a fun animation that follows your pointer around the page. ![With Custom Code](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/0fbf9c8-Large_GIF_1238x662.gif) Next Steps ========== Awesome! Now that you’ve got the hang of custom code, here are some other cool things you can do: * **Apply More Examples**: Use the app to explore and apply more example scripts. * **Add Your Own Custom Code**: Use the API to add your own custom code examples and see them in action on your Webflow site. Keep experimenting and enhancing your Webflow site with custom scripts! [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Data Clients — Webflow API Documentation Data Client Apps unlock the full capabilities of Webflow’s [REST APIs](/v2.0.0/data/reference/rest-introduction) through powerful server-side applications. Build apps and integrations that automatically localize content across a site, create custom publishing workflows, or manage thousands of CMS items programmatically. These OAuth-authenticated clients run on your server, giving you secure, reliable access to a site’s resources through clean, straightforward API calls. Want to extend the experience even further? Combine Data Clients with Designer Extensions to create comprehensive solutions that enhance both backend automation and frontend interactions - enabling you to build professional-grade applications that transform how teams work with Webflow. [Get started with Data Clients](/v2.0.0/data/docs/getting-started-data-clients) [Explore Hybrid Apps](/v2.0.0/data/docs/hybrid-apps) Data API Resources ------------------ Below is a comprehensive overview of all the resources available through Webflow’s Data API. This diagram illustrates the various data types and endpoints you can access and manipulate. Developer Resources ------------------- ![](https://dhygzobemt712.cloudfront.net/Icons/Dark/48px/Docs.svg)![](https://dhygzobemt712.cloudfront.net/Icons/Light/48px/Docs.svg) Data API Reference Explore the reference to discover available endpoints, understand request/response formats, and test API calls directly in your browser. [![](https://dhygzobemt712.cloudfront.net/Icons/Dark/48px/SecurityCertified.svg)![](https://dhygzobemt712.cloudfront.net/Icons/Light/48px/SecurityCertified.svg)\ \ OAuth Authentication\ \ Learn how to authenticate your Data Client with Webflow using OAuth 2.0.](https://developers.webflow.com/data/reference/oauth-app) [![](https://dhygzobemt712.cloudfront.net/Icons/Dark/48px/CodeBrackets.svg)![](https://dhygzobemt712.cloudfront.net/Icons/Light/48px/CodeBrackets.svg)\ \ Sample Data Client\ \ Get started with a simple Data Client app that demonstrates how to interact with Webflow’s API.](https://github.com/Webflow-Examples/webflow-app-starter-v2) [![](https://dhygzobemt712.cloudfront.net/Icons/Dark/48px/TBD.svg)![](https://dhygzobemt712.cloudfront.net/Icons/Light/48px/TBD.svg)\ \ SDKs\ \ Access Webflow’s JavaScript and Python SDKs to help you build Data Clients more quickly and efficiently.](/v2.0.0/data/reference/sdks) [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Working with the CMS — Webflow API Documentation What you’ll build ----------------- This guide will walk you through using a Data Client App to interact with Webflow’s CMS APIs. The Data Client App enables you to make calls to Webflow’s backend data APIs, and through this guide, you’ll learn how use the API to: 1. Create collections and fields 2. Create, read, update, and delete items 3. Publish and unpublish collection items To make visualizing your Collections and Items easier, you’ll also build a simple frontend using React. Prerequisites ------------- * A Webflow site. If you’re not sure where to start, clone the [Astral Fund site](https://webflow.com/made-in-webflow/website/astralfund-919afdc1091df68b8dc1347f952a?searchValue=astral) with defined CMS collections. * A registered [Webflow App](https://developers.webflow.com/data/docs/register-an-app) or a [Site Token](https://university.webflow.com/lesson/intro-to-webflow-apis?topics=cms-dynamic-content#how-to-create-an-api-token) with the following scopes: `sites:read`, `cms:read`, and `cms:write` * An [Ngrok account](http://ngrok.com/) and an authentication token * [Node.js](https://nodejs.org/en) and an IDE of your choice * Additionally, you should have basic knowledge of Node.js and Express ###### 1\. Quickstart Reference the [starter code](https://github.com/Webflow-Examples/cms-examples) for to follow along with the guide. This code already takes care of the OAuth Handshake and initializes the Webflow Client as shown in the [Authentication guide.](https://developers.webflow.com/data/reference/authorization) You’ll be able to start this App, authenticate the App, and start making requests to the Webflow CMS API. 1. **Clone the starter code.** Run the following commands in your IDE to clone the [example repository](https://github.com/Webflow-Examples/cms-examples) and install dependencies: Shell ` | | | | --- | --- | | $ | git clone https://github.com/Webflow-Examples/cms-examples.git | | > | cd cms-examples | | > | npm install | ` 2. **Add Environment Variables** Add your credentials to the `.env` file. If you’re using an App, input your App’s `CLIENT_ID` and `CLIENT_SECRET`. If using a Site Token, input the token as `SITE_TOKEN`. 3. **Add Ngrok Auth Token** Ngrok is required because Webflow Apps must run on `https://` URLs, and Ngrok provides a secure tunnel for your local server. Get your Ngrok auth token from the [Ngrok dashboard](https://dashboard.ngrok.com/tunnels/authtokens) . Then, add your token to your environment variables in `.env`: Shell ` | | | | --- | --- | | $ | NGROK_AUTH_TOKEN=your-ngrok-auth-token | ` 4. **Start the Server** Start the server by running `npm start` in your terminal. This will output list of URLs in the terminal to access your server and your frontend. ![](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/ngrok-table.png) 5. **Update your Redirect URI in Webflow** Copy the redirect URI from your terminal output. Navigate to your App in the Webflow Dashboard Settings and update the Redirect URI to the URL of your server. ![](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/update-redirect-uri.png) 6. **Authenticate the App** Open the URL of your server in the browser. You’ll be prompted to authenticate the App with Webflow. You have the option to authenticate a single site or all sites on a single workspace. 7. **Start making requests** Once authenticated, you’ll be redirected to the App frontend where you can select an authorized site and start making requests to the Webflow CMS API. ![](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/cms-example-app.png) ###### 2\. Shaping requests The backend is built using Express and Node.js, and designed to handle requests from the frontend. When a request the server receives a request, it’s first passed to the middleware function defined in `webflowClientMiddleware.js`. This function initializes and authenticates the Webflow Client and attaches it to the request object, so you don’t have to re-authenticate in each request. This client is then used in the controllers to make requests to the Webflow CMS API. In the controller files, **requests are prefixed with `req.`** followed by the standard Webflow SDK methods. For example, to interact with collections you would use `req.webflow.collections.items.listItems()`. webflowClientMiddleware.js ` | | | | --- | --- | | 1 | import { WebflowClient } from "webflow-api"; | | 2 | import { getToken } from "./auth/tokens.js"; | | 3 | | | 4 | // Middleware function to initialize the Webflow client and attach it to the request object | | 5 | const webflowClientMiddleware = async (req, res, next) => { | | 6 | try { | | 7 | // Retrieve the access token for the user using Auth Logic defined in our auth guide (https://developers.webflow.com/data/reference/authorization) | | 8 | const accessToken = await getToken("user"); | | 9 | if (!accessToken) { | | 10 | // If the access token is not found, log an error and send a 401 Unauthorized response | | 11 | console.log("Access token not found for user"); | | 12 | return res.status(401).send("Access token not found"); | | 13 | } | | 14 | | | 15 | // Initialize the Webflow client with the retrieved access token | | 16 | req.webflow = new WebflowClient({ accessToken }); | | 17 | // Proceed to the next middleware or route handler | | 18 | next(); | | 19 | } catch (error) { | | 20 | // Log any errors that occur during initialization and send a 500 Internal Server Error response | | 21 | console.error("Error initializing Webflow client:", error); | | 22 | res.status(500).send("Failed to initialize Webflow client"); | | 23 | } | | 24 | }; | | 25 | | | 26 | // Export the middleware function for use in other parts of the application | | 27 | export default webflowClientMiddleware; | ` ###### 3\. Creating collections and fields Now that you’ve handled setting up authorized requests, take a look at how the app makes requests to interact with collections and fields. All of the logic for interacting with the Webflow CMS API is located in the `Controllers` folder. `collectionsController.js` has defined five methods for interacting with collections. Review each method in detail: ###### 4\. Creating collection items With our collections set up, we can start creating items within them. In `itemsController.js`, we’ve defined methods for creating, reading, updating, and deleting items. ###### 5\. Publishing items Lastly, we’ll take a look at how we can publish and unpublish items using the Webflow CMS API. ### Publishing items * **A full site publish**: When you publish your entire site, any collection items with `isDraft` set to `false` will be published. You can publish the site through Webflow or using the [publish site endpoint](https://developers.webflow.com/v2.0.0/data/reference/sites/publish) . * **Single-item publish**: You can publish an item immediately, without publishing the full site, using the [publish item endpoint](https://developers.webflow.com/v2.0.0/data/reference/cms/collection-items/staged-items/publish-item) . Even if an item is set to `isDraft: true`, it will be published when using this endpoint. * **Live Item Creation**: The CMS API offers two options for item creation, creating a [staged item](/v2.0.0/data/reference/cms/collection-items/staged-items/create-item) or a [live item](/v2.0.0/data/reference/cms/collection-items/live-items/create-item-live) . Creating a staged item will set the `isDraft` property to `true`, while creating a live item will set it to `false` and immediately publish the item upon creation. This endpoint is useful for immediately publishing items from an external CMS or other data sources. ### Unpublishing items Webflow also allows you to **unpublish** collection items by using the [unpublish item endpoint](https://developers.webflow.com/v2.0.0/data/reference/cms/collection-items/live-items/delete-item-live) . This will remove the item from the live site, and set the `isDraft` property to `true`. ##### Updated publishing behavior Starting December 2024, Webflow is introducing an improved publishing workflow for collection items. When a live item’s `isDraft` property is set to `true`, it will continue to remain published on the live site even after a full site publish. This allows users to make updates to the collection item in a draft state without changing what is visible on the live site. To remove an item from the live site, you must now explicitly call the [unpublish endpoint](https://developers.webflow.com/v2.0.0/data/reference/cms/collection-items/live-items/delete-item-live) . This change gives developers more precise control over the publishing state of individual items. ###### Publishing 'Status' in Webflow ![](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/webflow-statuses.png) The Webflow UI shows a status for each collection item. This status is derived from the `isDraft` and `lastPublished` properties of the item. See the table below for more details of which status is shown based on these properties. | lastPublished | isDraft | Derived status | | --- | --- | --- | | `null` | `false` | Queued to publish | | exists | `false` | Queued to publish | | `null` | `true` | Draft | | exists | `true` | Draft changes | Conclusion ---------- Congratulations! You’ve successfully navigated through the process of setting up and using the Webflow API with a fully functional backend and frontend application. Here’s a quick recap of what you’ve accomplished: 1. **Webflow Client and Backend Configuration:** You configured the WebflowClient, set up middleware, and created routes and controllers for managing collections and items. 2. **Working with Collections:** You learned how to create, retrieve, and delete collections, including handling different field types. 3. **Working with Items:** You explored how to create, retrieve, update, and delete items within a collection, managing various item states and field types. 4. **Publishing and Unpublishing:** You learned how to publish and unpublish items, and how the `isDraft` property affects the publishing state of items. Next Steps ---------- * **Extend Functionality:** Enhance your application by adding new endpoints - try updating an item - or incorporating additional data processing logic. * **Explore Localization:** Managing content localization is a crucial part of working with the Webflow CMS. Check out our [localization guide](https://developers.webflow.com/data/docs/working-with-localization) for more details on how to localize your content effectively. [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Getting Started — Webflow API Documentation In this guide, you’ll create your first Data Client App to authorize with Webflow and make your first API request. ##### Prerequisites To successfully follow along with this guide, please ensure you have the following: * A Webflow site for development and testing * A registered App on your Workspace. If you haven’t registered an App, [follow along with our registration guide](/v2.0.0/data/docs/register-an-app) to create and register your first App with Webflow. * The `sites:read` scope enabled on your App * Node.js installed on your machine. ###### Quick Start (5 minutes) [1](/v2.0.0/data/docs/getting-started-data-clients#clone-the-starter-app) ### Clone the starter app ` | | | | --- | --- | | $ | git clone https://github.com/Webflow-Examples/webflow-app-starter-v2 | | > | cd webflow-app-starter-v2 | | > | npm install | ` [2](/v2.0.0/data/docs/getting-started-data-clients#add-your-credentials-to-env) ### Add your credentials to .env Navigate to your Workspace settings in the Webflow dashboard and find your Client ID and Secret in the Apps & Integrations -> App Development section. Replace the placeholder values in the `.env.example` file with your own Client ID and Secret. Then save the file as `.env`. ` | | | | --- | --- | | 1 | WEBFLOW_CLIENT_ID=your_client_id | | 2 | WEBFLOW_SECRET=your_client_secret | ` [3](/v2.0.0/data/docs/getting-started-data-clients#start-the-server) ### Start the server ` | | | | --- | --- | | $ | npm run dev | ` [4](/v2.0.0/data/docs/getting-started-data-clients#create-a-tunnel-to-your-local-server) ### Create a tunnel to your local server Create a tunnel to your local server using [ngrok](https://ngrok.com/) or [localtunnel](https://theboroer.github.io/localtunnel-www/) and update your Webflow App’s Redirect URL to point to your tunnel ###### Working with Ngrok [1](/v2.0.0/data/docs/getting-started-data-clients#sign-up-for-ngrok) ### Sign up for Ngrok Sign up for a free [Ngrok account](https://ngrok.com/) [2](/v2.0.0/data/docs/getting-started-data-clients#install-ngrok) ### Install Ngrok Install Ngrok via Homebrew by typing the following command in your terminal ` | | | | --- | --- | | $ | brew install Ngrok | ` [3](/v2.0.0/data/docs/getting-started-data-clients#authenticate-ngrok) ### Authenticate Ngrok Authenticate Ngrok with [your auth token](https://dashboard.ngrok.com/get-started/your-authtoken) by typing the following code in your terminal ` | | | | --- | --- | | $ | ngrok config add-authtoken | ` [4](/v2.0.0/data/docs/getting-started-data-clients#start-a-tunnel-to-the-port-of-your-choosing) ### Start a tunnel to the port of your choosing Start a tunnel to the port of your choosing by typing the following code in your terminal. This should be the same port you set in your `.env` file. ` | | | | --- | --- | | $ | ngrok http 3000 | ` [5](/v2.0.0/data/docs/getting-started-data-clients#update-app-redirect-uri) ### Update App redirect URI Copy the forwarding URI from the Ngrok session detail window. ![Ngrok setup](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/9039705-a2cd33a-Ngrok_Setup.png) * Navigate to your App’s details in the App Development section of your Workspace Settings. * Click the “Edit App” button and navigate to the “Building Blocks” tab. * In the Data Client section, update the redirect URI to the Ngrok forwarding URL with `/auth` added to the end. For example: `https://939c-136-33-253-184.Ngrok.io/auth` ![redirect uri](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/pages/v2.0.0/Apps/data-clients/getting-started-data-clients/redirect-uri.png) [5](/v2.0.0/data/docs/getting-started-data-clients#visit-your-app) ### Visit your App Visit `http://localhost:3000` (or the port of your choice)and click “Connect with Webflow” to see your Webflow sites! ![Webflow App Example](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/pages/v2.0.0/Apps/data-clients/getting-started-data-clients/new-user.png) Understanding the example ------------------------- [This example](https://github.com/Webflow-Examples/webflow-app-starter-v2) is a simple Node.js app that handles authorization and makes a single request to the Webflow API. Let’s review the code in `server.js`to understand how the App works. ###### Installation and configuration The App uses [Fastify](https://www.fastify.io/) to create a lightweight server, [Level](https://github.com/Level/level) as a database to store data, and the [Webflow JavaScript SDK](https://www.npmjs.com/package/webflow-api) to authenticate with Webflow and make requests to the API. To keep things simple, the frontend of the App is built with vanilla JavaScript and CSS, with a simple HTML file served from the `public` directory. In the beginning of `server.js`, we’re importing the necessary dependencies, loading our environment variables, and initializing the Fastify server. Here, we’ve also added security headers to the server to protect against common web vulnerabilities, as well as initializing the database for storing access tokens. server.js ` | | | | --- | --- | | 1 | import { WebflowClient } from "webflow-api"; | | 2 | import Fastify from "fastify"; | | 3 | import fastifyStatic from "@fastify/static"; | | 4 | import path from "path"; | | 5 | import url from "url"; | | 6 | import { Level } from "level"; | | 7 | import fs from "fs/promises"; | | 8 | | | 9 | // Load environment variables from .env file | | 10 | const { | | 11 | WEBFLOW_CLIENT_ID, | | 12 | WEBFLOW_SECRET, | | 13 | PORT | | 14 | NODE_ENV = "development", | | 15 | } = process.env; | | 16 | | | 17 | // Validate required environment variables | | 18 | if (!WEBFLOW_CLIENT_ID \| !WEBFLOW_SECRET) { | | 19 | console.error( | | 20 | "Missing required environment variables. Please check your .env file:" | | 21 | ); | | 22 | console.error("WEBFLOW_CLIENT_ID and WEBFLOW_SECRET are required"); | | 23 | process.exit(1); | | 24 | } | | 25 | | | 26 | // Initialize our server with basic security headers | | 27 | const server = Fastify({ | | 28 | logger: true, | | 29 | trustProxy: true, // Required for secure cookies behind a proxy | | 30 | }); | | 31 | | | 32 | // Add security headers | | 33 | server.addHook("onSend", async (request, reply) => { | | 34 | reply.headers({ | | 35 | "X-Content-Type-Options": "nosniff", // Prevent MIME type sniffing | | 36 | "X-Frame-Options": "DENY", // Prevent clickjacking | | 37 | "Strict-Transport-Security": "max-age=31536000; includeSubDomains", // Enforce HTTPS | | 38 | }); | | 39 | }); | | 40 | | | 41 | // Initialize the database (Note: Use a proper database in production) | | 42 | const db = new Level("data", { valueEncoding: "json" }); | | 43 | await db.open(); | ` ###### OAuth Authentication The App implements OAuth 2.0 authentication through a dedicated `/auth` route that handles both initiating the authorization flow and processing Webflow’s callback response. When a user clicks “Connect with Webflow”, this route first redirects them to Webflow’s authorization page. After the user grants permission, Webflow redirects back to this route with an authorization code that the App exchanges for an access token. For a comprehensive walkthrough of implementing OAuth 2.0 authentication in your App, refer to our detailed [OAuth 2.0 guide](/v2.0.0/data/reference/oauth-app) . #### Start the OAuth 2.0 authorization flow This route will check for a `code` query parameter. If the code is not present, we’ll redirect the user to the Webflow OAuth 2.0 authorization page using the `authorizeURL` method of the Webflow JavaScript SDK. server.js ` | | | | --- | --- | | 1 | // OAuth 2.0 authentication endpoint | | 2 | server.get("/auth", async (req, reply) => { | | 3 | const { code, error, error_description } = req.query; | | 4 | | | 5 | // If no code is provided, redirect to the authorization URL | | 6 | if (!code) { | | 7 | const installUrl = WebflowClient.authorizeURL({ | | 8 | scope: scopes, | | 9 | clientId: WEBFLOW_CLIENT_ID, | | 10 | // Optional: Add state parameter for CSRF protection | | 11 | state: Math.random().toString(36).substring(7), | | 12 | }); | | 13 | return reply.redirect(installUrl); | | 14 | } | | 15 | }); | ` #### Request an access token If the `code` query parameter is present, we’ll use it to request an access token from Webflow using the `getAccessToken` method of the Webflow JavaScript SDK. We’ll also store the access token in the database and redirect the user to the root URL of the App. server.js ` | | | | --- | --- | | 1 | // OAuth 2.0 authentication endpoint | | 2 | server.get("/auth", async (req, reply) => { | | 3 | | | 4 | // Previous Code // | | 5 | | | 6 | try { | | 7 | // Exchange the code for an access token | | 8 | const token = await WebflowClient.getAccessToken({ | | 9 | clientId: WEBFLOW_CLIENT_ID, | | 10 | clientSecret: WEBFLOW_SECRET, | | 11 | code: code, | | 12 | }); | | 13 | | | 14 | // Store the token in the database | | 15 | await db.put("token", token); | | 16 | | | 17 | if (NODE_ENV === "development") { | | 18 | console.log("\nAccess Token Received:", token, "\n"); | | 19 | } | | 20 | | | 21 | return reply.redirect("/?authorized=true"); | | 22 | } catch (error) { | | 23 | console.error("Auth Error:", error); | | 24 | return reply.code(500).send({ | | 25 | error: "Authentication failed", | | 26 | message: error.message, | | 27 | }); | | 28 | } | | 29 | }); | ` The example App stores and retrieves a single access token directly in the Level database. In a production app, you’ll want to implement proper user management and token storage, including: * Storing tokens securely per user/workspace * Encrypting sensitive data * Using secure session management Consider using dedicated auth services or implementing these security measures using libraries like Passport.js, JWT tokens, and proper database encryption. ###### Making requests to the REST API After the user has authorized the App, it can make requests to the REST API using the `WebflowClient` object. Here, the `/sites` route makes a request to the “[List Sites](https://developers.webflow.com/data/reference/sites/list) ” endpoint. Before calling the API, the App retrieves the access token from the database and creates a new, authenticated `WebflowClient` object. server.js ` | | | | --- | --- | | 1 | // Example API endpoint | | 2 | server.get("/sites", async (req, reply) => { | | 3 | try { | | 4 | const accessToken = await db.get("token"); | | 5 | | | 6 | const webflow = new WebflowClient({ accessToken }); | | 7 | | | 8 | const sites = await webflow.sites.list(); | | 9 | return sites; | | 10 | | | 11 | } catch (error) { | | 12 | console.error("API Error:", error); | | 13 | | | 14 | // Handle different types of errors | | 15 | if (error.response?.status === 401) { | | 16 | return reply.code(401).send({ | | 17 | error: "Invalid token", | | 18 | message: "Please authenticate again", | | 19 | }); | | 20 | } | | 21 | | | 22 | return reply.code(500).send({ | | 23 | error: "Server error", | | 24 | message: "Failed to fetch sites", | | 25 | }); | | 26 | } | | 27 | }); | ` Next Steps ---------- Now that you have a working app, you can: 1. **Add More API Endpoints**: Explore the [API Reference](/v2.0.0/data/reference) and our [Data Client Guides](/v2.0.0/data/docs/data-clients) to add functionality 2. **Add Designer Extension capabilities**: Learn how to [add Designer Extension capabilities](/v2.0.0/designer/docs/getting-started-designer-extensions) to your App. 3. **Authenticate a Hybrid App**: [Learn how to implement authentication](/v2.0.0/data/docs/authenticating-users-with-id-tokens) for Apps using Data Client and Designer Extension capabilities. 4. **Prepare your Marketplace App**: Learn how to [prepare your App for submission to the Webflow Marketplace](/v2.0.0/data/docs/submitting-your-app) [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Design Guidelines — Webflow API Documentation ![Developer UI kit](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/debecc2-developer-ui-kit.jpg) In this guide, we’ll explore essential principles and practical tips to ensure your extensions engage users and seamlessly integrate with the Webflow ecosystem. By focusing on user-centered design, thoughtful layout strategies, and effective color and typography choices, you’ll create extensions that not only enhance functionality but also delight users. Let’s dive in and discover how to make your extensions feel like a natural part of the Webflow experience. If you’re looking to publish your App on the Marketplace, please review our [Design and Usability section of our Marketplace App Guidelines.](/v2.0.0/data/docs/marketplace-guidelines) ##### Looking to build a native looking Webflow App? We’ve provided a simplified version of our design system with colors, typography, components, patterns, and App examples to help kickstart the design and build of your App. [Access the Webflow Apps Figma UI kit here](https://www.figma.com/community/file/1291823507081366246/webflow-app-ui-kit-2-0) . Crafting your user interface ---------------------------- Since Designer Extensions run within an iframe, you can use traditional HTML, CSS, and JavaScript to design and develop your user interface like you would any single-page application. You can use frameworks and libraries to help with this process. For instance, you might use [React](https://react.dev/) or [Vue.js](https://vuejs.org/) for creating your UI components, and [Tailwind CSS](https://tailwindcss.com/) or [Bootstrap](https://getbootstrap.com/) for styling. Webflow doesn’t require Designer Extensions to feel native to the Designer, but we do believe Apps that feel native will resonate with our customers and provide a higher-level experience. Design principles ----------------- Your UI should adhere to the following key principles: 1. **Customer-focused:** The App’s purpose and value should be defined around the needs of Webflow users. It should solve a unique problem for them. 2. **Simplicity & approachability:** Your App should be simple to use and not require extensive learning to get started. It should complement Webflow’s visual abstraction of code, not complicate it. 3. **Consistent design:** Use consistent design elements like color, typography, and button styles throughout your App. This improves the user experience and makes your App easier to navigate. 4. **Foster creative momentum:** Your App should not hinder the creative process. Avoid unnecessary steps or options that could break the user’s flow state. 5. **Clear Language:** Use clear and concise copy throughout your App. It should guide users and connect the dots between visuals, layouts, and usability. 6. **Inclusive & Accessible:** Strive to make your App accessible to all users. This means ensuring it adheres to accessibility standards and best practices. Layout guidelines ----------------- 1. **Vertical component arrangement:** For the narrow, default interface, components should be stacked vertically rather than horizontally. 2. **Full-width buttons & components:** Full-width elements enforce a vertical orientation and make your App easier to scan. 3. **Avoid horizontal scrolling:** Ensure your UI elements fit within the iframe’s width to prevent horizontal scrolling. 4. **Consistent spacing:** Use a consistent spacing rhythm (e.g., multiples of 4px) to create a visually pleasing App. Use white space effectively to create a balanced layout and highlight important information. 5. **Clear & concise copy:** Use sentence case for all text, including headings and buttons. Make error states helpful and actionable, and always strive for clarity over complexity. 6. **Consistent design language:** Use a consistent design language, including typography, color schemes, and button styles. This will create a more cohesive user experience and help users navigate your plugin more easily. 7. **Iconography**: Use recognizable and intuitive icons throughout your App. Icons can help users navigate your App more easily and quickly. Enhancing with colors & typography ---------------------------------- Choose a color scheme that aligns with the purpose and tone of your App. Webflow primarily uses the Inter font for its interface. You can consider adopting it for consistency. ### Fonts To use Webflow’s main font face, Inter, you will need to download the files into your App or access them via Google Font’s API. [Access Inter font family on Google Fonts](https://fonts.google.com/specimen/Inter) . ### CSS variables To design and build an App that feels native to Webflow’s Designer, you can use the following Webflow hosted CSS variables. These variables will automatically adjust based on a users [Appearance settings](https://webflow.com/feature/adjust-appearance-settings#:~:text=All%20display%20options%20are%20available,settings%20for%20the%20Webflow%20Designer.) . Implement these by calling them in your CSS selectors with the `var()` function: CSS ` | | | | --- | --- | | 1 | /* Webflow colors */ | | 2 | --background1: #1E1E1E; | | 3 | --background2: #2E2E2E; | | 4 | --background3: #383838; | | 5 | --background4: #373737; | | 6 | --background5: #444444; | | 7 | --backgroundInactive: #2E2E2E; | | 8 | --backgroundInverse: #EBEBEB; | | 9 | --backgroundInput: rgba(0, 0, 0, 0.15); | | 10 | | | 11 | --actionPrimaryBackground: #006ACC; | | 12 | --actionPrimaryBackgroundHover: #187CD9; | | 13 | --actionSecondaryBackground: linear-gradient(180deg, rgba(255, 255, 255, 0.12) 0%, rgba(255, 255, 255, 0.10) 100%); | | 14 | --actionSecondaryBackgroundHover: linear-gradient(180deg, rgba(255, 255, 255, 0.18) 0%, rgba(255, 255, 255, 0.16) 100%); | | 15 | --actionPrimaryText: #FFFFFF; | | 16 | --actionPrimaryTextHover: #FFFFFF; | | 17 | --actionSecondaryText: #E0E0E0; | | 18 | --actionSecondaryTextHover: #E0E0E0; | | 19 | | | 20 | --border1: rgba(255, 255, 255, 0.13); | | 21 | --border2: rgba(255, 255, 255, 0.14); | | 22 | --border3: rgba(255, 255, 255, 0.19); | | 23 | | | 24 | --text1: #F5F5F5; | | 25 | --text2: #BDBDBD; | | 26 | --text3: #A3A3A3; | | 27 | --textInactive: #757575; | | 28 | --textInverse: #1E1E1E; | | 29 | | | 30 | --blueText: #8AC2FF; | | 31 | --blueIcon: #8AC2FF; | | 32 | --blueBorder: #007DF0; | | 33 | | | 34 | --greenBackground: #007A41; | | 35 | --greenBackgroundHover: #0D8A4F; | | 36 | --greenText: #63D489; | | 37 | --greenIcon: #63D489; | | 38 | --greenBorder: #259D4D; | | 39 | --yellowBackground: #946B00; | | 40 | | | 41 | --yellowBackgroundHover: #AF7F00; | | 42 | --yellowText: #F3C831; | | 43 | --yellowIcon: #F3C831; | | 44 | --yellowBorder: #D7A220; | | 45 | | | 46 | --redBackground: #CF313B; | | 47 | --redBackgroundHover: #CB3535; | | 48 | --redText: #FF8A8A; | | 49 | --redIcon: #FF8A8A; | | 50 | --redBorder: #E42F3A; | | 51 | | | 52 | --orangeBackground: #BF4704; | | 53 | --orangeBackgroundHover: #DC95616; | | 54 | --orangeText: #EBA267; | | 55 | --orangeIcon: #EBA267; | | 56 | --orangeBorder: #DF640C; | | 57 | | | 58 | --purpleBackground: #734CE0; | | 59 | --purpleBackgroundHover: #815BEB; | | 60 | --purpleText: #B89EFF; | | 61 | --purpleIcon: #B89EFF; | | 62 | --purpleBorder: #875FFD; | | 63 | | | 64 | /* Box shadows for buttons and inputs */ | | 65 | --boxShadows-action-colored: 0px 0.5px 1px 0px rgba(0, 0, 0, 0.8),0px 0.5px 0.5px 0px rgba(255, 255, 255, 0.20) inset; | | 66 | --boxShadows-action-secondary: 0px 0.5px 1px rgba(0, 0, 0, 0.8),inset 0px 0.5px 0.5px rgba(255, 255, 255, 0.12); | | 67 | --boxShadows-input-inner: 0px 1px 1px -1px rgba(0, 0, 0, 0.13) inset,0px 3px 3px -3px rgba(0, 0, 0, 0.17) inset,0px 4px 4px -4px rgba(0, 0, 0, 0.17) inset,0px 8px 8px -8px rgba(0, 0, 0, 0.17) inset,0px 12px 12px -12px rgba(0, 0, 0, 0.13) inset,0px 16px 16px -16px rgba(0, 0, 0, 0.13) inset; | | 68 | | | 69 | --boxShadows-menu: 0px 0.5px 0.5px 0px rgba(255, 255, 255, 0.12) inset, 0px 12px 24px 8px rgba(0, 0, 0, 0.04), 0px 8px 16px 4px rgba(0, 0, 0, 0.04), 0px 4px 8px 2px rgba(0, 0, 0, 0.04), 0px 2px 6px 0px rgba(0, 0, 0, 0.04), 0px 0px 1px 0px rgba(0, 0, 0, 0.25); | | 70 | | | 71 | --input-inner-shadow: 0px 1px 1px -1px rgba(0, 0, 0, 0.13) inset, 0px 3px 3px -3px rgba(0, 0, 0, 0.17) inset, 0px 4px 4px -4px rgba(0, 0, 0, 0.17) inset, 0px 8px 8px -8px rgba(0, 0, 0, 0.17) inset, 0px 12px 12px -12px rgba(0, 0, 0, 0.13) inset, 0px 16px 16px -16px rgba(0, 0, 0, 0.13) inset; | | 72 | | | 73 | --menu-shadow: 0px 12px 24px 8px rgba(0, 0, 0, 0.08), 0px 8px 16px 4px rgba(0, 0, 0, 0.08), 0px 4px 8px 2px rgba(0, 0, 0, 0.08), 0px 2px 6px 0px rgba(0, 0, 0, 0.08), 0px -0.5px 0.5px 0px rgba(0, 0, 0, 0.12) inset, 0px 0.5px 0.5px 0px rgba(255, 255, 255, 0.12) inset; | | 74 | | | 75 | /* TYPOGRAPHY */ | | 76 | --font-stack: 'Inter', sans-serif; | | 77 | --font-size-small: 11.5px; | | 78 | --font-size-small-letter-spacing: -0.115px; | | 79 | --font-size-large: 12.5px; | | 80 | --font-weight-normal: 400; | | 81 | --font-weight-medium: 600; | | 82 | --border-radius: 4px; | ` [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Working with Assets — Webflow API Documentation Webflow’s asset APIs enable apps to upload and manage a site’s assets. Learn more about assets in Webflow in the [support documentation.](https://help.webflow.com/hc/en-us/articles/33961269934227-Assets-panel#supported-file-types) These APIs enable developers to create integrations that sync with external file management systems like [Digital Asset Managers (DAMs)](https://www.bynder.com/en/what-is-digital-asset-management/) . Keeping these systems in sync ensures that site designers and content managers have the assets they need when working in Webflow. ##### Important Files you upload to the assets panel aren’t restricted — that is, they’re publicly available and discoverable, but won’t necessarily be discovered or indexed by search engines if the file isn’t on a publicly viewable webpage or linked elsewhere. [Learn more about asset privacy in Webflow.](https://help.webflow.com/hc/en-us/articles/33961281837843) FAQs ---- ###### Which file types are supported? ###### Images ###### Documents ###### Lottie * PNG * JPEG and JPG * GIF * SVG * WebP * AVIF ###### Are there size limits for assets? Yes, uploaded assets must adhere to specific size limitations: * Images must not exceed 4MB * Documents are capped at 10MB ###### Why do I need to include a file hash for asset uploads? When uploading a file, Webflow requires an [MD5 hash](https://en.wikipedia.org/wiki/MD5) generated from the contents of the file to ensure data integrity and manage duplicate assets. ### What is a cryptographic hash? > A cryptographic hash, also often referred to as a “digest”, “fingerprint” or “signature”, is an almost perfectly unique string of characters that is generated from a separate piece of input text. —[boot.dev](https://blog.boot.dev/cryptography/how-sha-2-works-step-by-step-sha-256/) A cryptographic hash is the result of a hashing algorithm, which deterministically converts input data into an output of fixed length, regardless of input size. ### What are cryptographic hashes used for? Hashes serve a range of purposes, from verifying data integrity and enabling fast lookups in databases, to efficiently identifying duplicates. Let’s break down what that looks like when uploading a file to Webflow and including an [MD5 hash](https://www.okta.com/identity-101/md5/) : [1](/v2.0.0/data/docs/working-with-assets#generate-the-file-hash) ### Generate the file hash Before uploading, use the MD5 hashing algorithm to convert the binary contents of your file into a 128-bit hash. This hash will serve as the `fileHash` value. [2](/v2.0.0/data/docs/working-with-assets#provide-the-hash-on-upload) ### Provide the hash on upload When creating a new asset in Webflow, include this generated `fileHash` with a request to the [Create Asset Metadata](https://developers.webflow.com/data/reference/assets/assets/create) endpoint. [3](/v2.0.0/data/docs/working-with-assets#webflow-uses-the-hash-for-de-duplication) ### Webflow uses the hash for de-duplication Webflow uses the `fileHash` as a unique identifier to prevent duplicate uploads. If a hash matches an existing file’s hash, Webflow avoids redundant storage, optimizing resources. [4](/v2.0.0/data/docs/working-with-assets#lookup-and-verification) ### Lookup and verification Webflow may use the `fileHash` as a lookup key to retrieve or verify file data, ensuring consistency across operations. What you’ll build ----------------- In this tutorial, you’ll build an example script that: * Creates asset folders on a site * Uploads a new image to an Webflow with a [MD5 hash](/v2.0.0/data/docs/working-with-assets#cryptographic-hashing) * Organizes the image within a site’s asset folders Prerequisites ------------- * A Webflow site in your development Workspace * A Webflow App or site token with the following scopes: `assets:read`, `assets:write` * Some knowledge of Node.js or Python Conclusion ---------- Congratulations! You’ve just programmatically created asset folders and uploaded assets to a Webflow site. These assets can now be organized and used across the site by designers and editors of Webflow projects. Looking for more things to try with the API? Check out: * [Working with Custom Code](/v2.0.0/data/docs/custom-code) * [Working with the CMS](/v2.0.0/data/docs/working-with-the-cms) * [Working with Webhooks](/v2.0.0/data/docs/working-with-webhooks) [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Getting Started — Webflow API Documentation ![](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/b384af7-Large_GIF_1494x606.gif) This guide will walk you through the setup of a basic Designer Extension replaces the text of an element with “Lorem Ipsum”. By the end of this guide, you’ll have completed the following steps: 1. Install the Webflow CLI 2. Initialize a Designer Extension starter project 3. Run a Designer Extension in the Webflow Designer 4. Update Elements on a page 5. Modify Designer Extension with the Designer APIs ### Prerequisites To successfully follow along with this guide, please ensure your system meets the following requirements and you have the following resources: * Node.js 16.20 or later * A Webflow site for development and testing * A registered Webflow App that’s installed to your test site. If you haven’t set up an App yet, please follow our guide on [creating an App.](/v2.0.0/data/docs/register-an-app) * * * [1](/v2.0.0/designer/docs/getting-started-designer-extensions#install-the-webflow-cli) ### Install the Webflow CLI Webflow’s CLI is a command-line interface that allows you to create, manage, and deploy Designer Extensions. It provides a set of commands for initializing, building, and running your Designer Extension, as well as for interacting with the Designer APIs. To create a Designer Extension, you’ll need to install the Webflow CLI. ` | | | | --- | --- | | $ | npm i @webflow/webflow-cli -g | ` [2](/v2.0.0/designer/docs/getting-started-designer-extensions#create-a-designer-extension) ### Create a Designer Extension The [Webflow CLI](/designer/reference/webflow-cli) provides a command to create a new Designer Extension with a [basic structure](/designer/reference/app-structure) and [settings](/designer/reference/app-settings) . This command will create a new project folder with the necessary files and structure for your Designer Extension. Additionally, the CLI offers [templates](/designer/reference/webflow-cli#designer-extension-templates) to work with specific libraries and frameworks, including React and Typescript. ` | | | | --- | --- | | $ | webflow extension init my-extension-name react | ` ###### Designer Extension Project Structure The structure of your new project folder should resemble the example below. ` | | | --- | | my_example_extension/ | | ├── node_modules/ | | ├── public/ # Contains all the files to serve your designer extension | | │ ├── index.html # Required:This file serves as the initial point of entry for your single page app. | | │ ├── index.js # This file adds interactivity and dynamic behavior to your web app. | | │ └── styles.css # Defines the visual appearance of your App | | ├── src/ # Contains the source code for your designer extension | | │ └── index.ts | | ├── package-lock.json | | ├── package.json | | ├── webflow.json # Contains the settings for your designer extension | | ├── README.md | | └── tsconfig.json # Contains the TypeScript configuration for your designer extension | ` [3](/v2.0.0/designer/docs/getting-started-designer-extensions#run-your-designer-extension-locally) ### Run your Designer Extension locally Now that you’ve created your Designer Extension, let’s run it locally for development. The CLI provides a convenient development server that will automatically rebuild your extension whenever you make changes. Run the following command in your project directory: ` | | | | --- | --- | | $ | webflow extension serve | ` This will serve the Designer Extension on port 1337 using the CLI command `webflow extension serve` and run webpack in watch mode with `npm run watch-webpack` concurrently. Running these commands concurrently allows you to both serve your extension and automatically rebuild it whenever you make code changes, enabling a smooth development experience with live updates. Note that the Designer Extension will only be fully functional when loaded within the Webflow interface. [4](/v2.0.0/designer/docs/getting-started-designer-extensions#open-your-designer-extension-in-webflow) ### Open your Designer Extension in Webflow To see your Designer Extension running in Webflow, you’ll need to load it in the Webflow Designer. Ensure your App is [installed to your test site](/v2.0.0/data/docs/register-an-app#Install-an-app) and open your test site in the Webflow Designer. Click on the “Apps” icon in the left panel, and locate and click on your App to open its detail pane. Click on the “Launch development App” button to see your Designer Extension running in the Webflow Designer. ![Launch development App](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/c093a94-Screenshot_2024-01-31_at_11.38.58_AM.png) [5](/v2.0.0/designer/docs/getting-started-designer-extensions#modify-elements-with-the-designer-apis) ### Modify elements with the Designer APIs ![Update elements with the Designer APIs](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/b384af7-Large_GIF_1494x606.gif) The starter project demonstrates a simple example of using the Designer APIs. When you select a text element on the page and click the “Lorem Ipsum” button, the Designer Extension will [get the selected element](/designer/reference/get-selected-element) and [replace the text](/designer/reference/text-content#elementsettextcontentcontent) with “Lorem Ipsum” boilerplate text. This shows how Designer Extensions can programmatically modify content on the canvas. This code that modifies elements is located in `src/index.ts`. index.ts ` | | | | --- | --- | | 1 | document.getElementById("lorem").onsubmit = async (event) => { | | 2 | | | 3 | // Prevent the default form submission behavior, which would reload the page | | 4 | event.preventDefault() | | 5 | | | 6 | // Get the currently selected element in the Designer | | 7 | const el = await webflow.getSelectedElement() | | 8 | | | 9 | // Check if an element was returned, and the element can contain text content | | 10 | if (el && el.textContent) { | | 11 | | | 12 | // If we found the element and it has the ability to update the text content, | | 13 | // replace it with some placeholder text | | 14 | el.setTextContent( | | 15 | "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do " + | | 16 | "eiusmod tempor incididunt ut labore et dolore magna aliqua." | | 17 | ) | | 18 | } | | 19 | } | ` [6](/v2.0.0/designer/docs/getting-started-designer-extensions#update-code-in-the-designer-extension) ### Update code in the Designer Extension ![Notify user](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/scaffold-app-modified.gif) Let’s add some additional logic to our Designer Extension to handle a scenario where an element isn’t selected, or an element doesn’t have text content. To change this, add an `else` clause to the `if` statement in `index.ts` and use the [`webflow.notify()`](/designer/reference/notify-user) method to notify a user that they should choose an element. Save these changes to your `index.ts`, and try selecting a non-text element to see the notification. index.ts ` | | | | --- | --- | | 1 | document.getElementById("lorem").onsubmit = async (event) => { | | 2 | // Prevent the default form submission behavior, which would reload the page | | 3 | event.preventDefault() | | 4 | // Get the currently selected element in the Designer | | 5 | const el = await webflow.getSelectedElement() | | 6 | // Check if an element was returned, and the element can contain text content | | 7 | if (el && el.textContent) { | | 8 | // If we found the element and it has the ability to update the text content, | | 9 | // replace it with some placeholder text | | 10 | el.setTextContent( | | 11 | "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do " + | | 12 | "eiusmod tempor incididunt ut labore et dolore magna aliqua." | | 13 | ) | | 14 | } else { // If an element isn't selected, or an element doesn't have text content, notify the user | | 15 | await webflow.notify({ type: 'Error', message: "Please select an element that contains text." }) | | 16 | } | | 17 | } | ` [Explore more Designer APIs](/designer/reference/introduction) ### Next Steps Congratulations! You’ve build and run your first Designer Extension. To dive deeper into what you can do with Designer Extensions, check out our documentation on: * The [Designer API](/designer/reference/introduction) . * Building and deploying [Designer Extensions](/v2.0.0/designer/docs/publishing-your-app) . * [Submitting your App to the Webflow Marketplace](/v2.0.0/data/docs/submitting-your-app) . [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Hybrid Apps — Webflow API Documentation The most exciting thing about the new App model– with the Data Client capabilities, and the introduction of Designer Extensions–is the power that is available to developers by combining these two building blocks into a single App. This Hybrid App model allows your App to provide a comprehensive user experience by surfacing your App’s UI within the Designer and using the Data Client to manage site data, assets, and more. ![](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/42d5637-Hybrid_App.png) [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Working with Localization — Webflow API Documentation [Webflow Localization](https://webflow.com/localization) is end-to-end solution for customizing your website for visitors around the world – from design to translation to publishing. With these APIs, your Apps can make dynamic content updates and enable custom localization workflows, providing scalability for growing businesses that are looking to enhance global user engagement and optimize performance for international audiences. Let’s look at an example. AstralFund is an imaginary bank that serves two locales – the United States and France. To properly address each market’s needs, the bank needs to localize content throughout the site. In the images below, we’ve localized some content. In this tutorial, we’ll walk through how to localize the entire site. ###### Primary Locale ###### Secondary Locale ### United States 🇺🇸 The site’s primary locale is set to the United States with content in English. ![](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/d34fd40-AstralFund_Financial_-_English_-_Hero.png)![](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/ff584c7-AstralFund_Financial_-_English_-_Testimonial.png) What we’ll build ---------------- In this tutorial, we’ll walk through the process of localizing content for a French audience on a website. By the end of this tutorial, you’ll have a fully localized “Contact Us” page and a new testimonial that resonates with your French audience. You’ll learn how to: * Identify primary and secondary locales within Webflow. * Localize the DOM elements like text and images. * Optimize SEO data for different locales. * Manage CMS content across multiple locales. Prerequisites ------------- * **[Astral Fund Cloneable](https://webflow.com/made-in-webflow/website/astralfund-919afdc1091df68b8dc1347f952a?searchValue=astral) ** * **[Localization Example](https://github.com/Webflow-Examples/Localization-Demo) ** with code samples and localized data * **Webflow site plan** that supports CMS * **[Webflow App](/v2.0.0/data/docs/register-an-app) ** or a [Site Token](/v2.0.0/data/reference/site-token) with the following scopes: `sites:read`, `cms:read`, and `cms:write` * **Some knowledge of HTTP requests and JavaScript** ###### 1\. Clone AstralFund and Identify Localization Opportunities 1. [Clone the AstralFund](https://webflow.com/made-in-webflow/website/astralfund-919afdc1091df68b8dc1347f952a?searchValue=astral) site to your Webflow account, and add it to a Workspace used for testing. 2. [Publish the site](https://university.webflow.com/lesson/publish-your-site?topics=getting-started) to set it live. 3. Navigate to the French locale to see the localized French homepage. 4. Navigate to the Contact page in French. Note the content that is not yet localized. We’ll fix this by localizing the navigation bar, contact content, form, footer, and SEO data. ###### 2\. Set up the Development Environment 1. **Clone the Example Repository** Clone the [example repository](https://github.com/Webflow-Examples/Localization-Demo) and install dependencies. ` | | | | --- | --- | | $ | git clone https://github.com/Webflow-Examples/Localization-Demo.git | | > | cd localization-demo | | > | npm install | ` 2. **Authenticate with your Bearer Key** Make sure you have a valid Bearer Key that is authenticated for your new site. You can do this by authenticating through our API reference docs. Once you have your Bearer Key, store it in your `.env` file as `WEBFLOW_API_TOKEN`. ![Screenshot](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/68c9547-Screenshot_2023-11-06_at_11.15.47_AM.png) 3. **Create `localization.js`** There’s a full example of all the steps below in `index.js`. However, if you’d like to follow along with this guide, create a new file called `localization.js`, and include the following imports of the translated content, as well as the [Webflow Javascript SDK](https://www.npmjs.com/package/webflow-api) . localization.js ` | | | | --- | --- | | 1 | // Import the pre-prepared localized content | | 2 | import localizedDOM from "./helpers/Contact Us - French.json" assert {type: "json"}; // Localized "Contact Us" DOM | | 3 | import localizedMetadataBody from "./helpers/seoData.json" assert {type: "json"}; // Localized SEO Data | | 4 | import frenchTestimonials from "./helpers/Testimonials - French.json" assert {type: "json"}; // Localized Testimonials | | 5 | import newFrenchTestimonial from "./helpers/newTestimonial.json" assert {type: "json"}; // New French Testimonial | | 6 | | | 7 | // Import the Webflow Javascript SDK | | 8 | import { WebflowClient } from "webflow-api"; | | 9 | import dotenv from "dotenv"; | ` 4. **Initialize the API** Create an asynchronous function, and initialize the API using the Webflow JavaScript SDK: localization.js ` | | | | --- | --- | | 1 | async function localizePage() { | | 2 | try { | | 3 | | | 4 | // Initialize the API. | | 5 | dotenv.config(); | | 6 | const token = process.env.WEBFLOW_API_TOKEN; | | 7 | const webflow = new WebflowClient(\{ accessToken: token }); | | 8 | | | 9 | /* ADD CODE FROM GUIDE HERE */ | | 10 | | | 11 | } catch (error) { | | 12 | console.error("An error occurred:", error); | | 13 | } | | 14 | } | | 15 | localizePage(); | ` After each step, you can run the file by typing the command `node localization` to see your progress. ###### 3\. Retrieve Locale Identifiers In this step we’ll retrieve the site and locale identifiers, so that we can make locale-specific requests to our site. 1. **Call the List Sites endpoint to find your `siteId` and `locale` information.** Replace the `siteName` variable with the name of your cloned site. JavaScript ` | | | | --- | --- | | 1 | // List sites and get the Astral Fund site's details | | 2 | const siteName = "AstralFund" // Change the site name to the name of your cloned site | | 3 | const sites = await webflow.sites.list(); | | 4 | const astralFundSite = sites.sites.find((site) => | | 5 | site.displayName.includes(siteName) | | 6 | ); | | 7 | const siteId = astralFundSite.id; | | 8 | const siteDetails = await webflow.sites.get(siteId); // Get site details for locale information | ` 2. **Extract the `localeId` for both English and French from the Site object:** * Notice the `locales` parameter, which returns a `primary` locale, and an array of `secondary` locales. * Each locale has useful information like the language, location, and more. * In addition to a specific `localeId`, each locale also has a `cmsLocaleId`. localization.js ` | | | | --- | --- | | 1 | // Extract and store locale IDs | | 2 | const locales = siteDetails.locales; | | 3 | const secondaryLocaleId = locales.secondary[0].id; // French is the first secondary locale | | 4 | const secondaryCmsLocaleId = locales.secondary[0].cmsLocaleId; | | 5 | console.log([locales, secondaryLocaleId, secondaryCmsLocaleId]); | ` ###### 4\. Localize Page Content In this step, we’re getting the content from a static, primary page, and uploading a translated version to our locale-specific page. 1. **Get the `page_id` of the Contact Us page using the [List Pages](https://developers.webflow.com/data/reference/pages/list) endpoint.** JavaScript ` | | | | --- | --- | | 1 | // Get the page information for "Contact Us" | | 2 | const pages = await webflow.pages.list(siteId); | | 3 | const contactPage = pages.pages.find((page) => | | 4 | page.title.includes("Contact") | | 5 | ); | | 6 | const contactPageId = contactPage.id; | ` 2. **Get the content of the Primary Locale using the [Read DOM](https://developers.webflow.com/data/reference/pages/get-content) endpoint.** This will return all content that can be localized from a static page, which we can then translate for our locale-specific page. 📘 As of Sep 22, 2023, we only support writing to Text and Rich Text to the DOM. We do not support updating images via this API. 3. **Modify the content to include localized versions of the nav bar, contact content, form, and footer.** We’ve provided a localized DOM for you with `./helpers/Contact Us - French.json`. From this example, create a DOM write object, with an array of DOM Nodes and the `cmsLocaleId`. ./helpers/Contact Us - French.json ` | | | | --- | --- | | 1 | { | | 2 | "pageId": "65427cf400e02b306eaa0496", | | 3 | "nodes": [ | | 4 | { | | 5 | "nodeId": "8017772e-bc46-5c59-54c0-134cdfd4b03a", | | 6 | "text": "

Contactez-nous

" | | 7 | }, | | 8 | { | | 9 | "nodeId": "8017772e-bc46-5c59-54c0-134cdfd4b03c", | | 10 | "text": "

Notre équipe d'experts en finances n'est qu'à un appel téléphonique. Composez notre numéro sans frais, et discutons !

" | | 11 | }, | | 12 | { | | 13 | "nodeId": "aa9e4de0-011e-ac64-cbc2-3ec4fa3a8bb8", | | 14 | "text": "hello@astralfunds.com" | | 15 | }, | | 16 | { | | 17 | "nodeId": "aa9e4de0-011e-ac64-cbc2-3ec4fa3a8bbd", | | 18 | "text": "+1 (555) 000-0000" | | 19 | }, | | 20 | { | | 21 | "nodeId": "aa9e4de0-011e-ac64-cbc2-3ec4fa3a8bc2", | | 22 | "text": "398 11th Street, 2ème étage, San Francisco, CA 94103" | | 23 | }, | | 24 | { | | 25 | "nodeId": "8017772e-bc46-5c59-54c0-134cdfd4b0c4", | | 26 | "text": "

Merci ! Votre message a été reçu.

" | | 27 | }, | | 28 | { | | 29 | "nodeId": "8017772e-bc46-5c59-54c0-134cdfd4b0c6", | | 30 | "text": "

Notre équipe répondra à votre message dès que possible. Merci de votre patience.

" | | 31 | }, | | 32 | { | | 33 | "nodeId": "8017772e-bc46-5c59-54c0-134cdfd4b0c9", | | 34 | "text": "
Oups ! Quelque chose s'est mal passé lors de l'envoi de votre message.
" | | 35 | }, | | 36 | { | | 37 | "nodeId": "36c1f507-a281-83c4-8222-873b4179b955", | | 38 | "text": "

Commencez à banquer maintenant

" | | 39 | }, | | 40 | { | | 41 | "nodeId": "36c1f507-a281-83c4-8222-873b4179b957", | | 42 | "text": "
Adoptez une nouvelle ère de gestion financière
" | | 43 | }, | | 44 | { | | 45 | "nodeId": "36c1f507-a281-83c4-8222-873b4179b95b", | | 46 | "text": "
Commencez
" | | 47 | }, | | 48 | { | | 49 | "nodeId": "36c1f507-a281-83c4-8222-873b4179b95e", | | 50 | "text": "
En savoir plus
" | | 51 | } | | 52 | ], | | 53 | "pagination": { "limit": 100, "offset": 0, "total": 22 } | | 54 | } | ` 4. **Update the content of the French locale by making a `POST` request to the [Update DOM](https://developers.webflow.com/data/reference/pages/update-page-settings) endpoint.** Be sure to include the `localeId` in the `locale` query parameter. JavaScript ` | | | | --- | --- | | 1 | // Get the DOM for the Contact Us page in English and translate to French | | 2 | const primaryContactPageDom = await webflow.pages.getContent(contactPageId); | | 3 | | | 4 | // Create the domWrite object with the nodes and cmsLocaleId | | 5 | const domWrite = { | | 6 | nodes: localizedDOM.nodes, | | 7 | locale: secondaryLocaleId, | | 8 | }; | | 9 | | | 10 | // Update the Contact Us page DOM with French content | | 11 | await webflow.pages.updateStaticContent(contactPageId, domWrite); | ` ###### 5\. Update SEO Data In this step, we’ll update the SEO metadata for the French version of the page. 1. **Retrieve the primary page’s SEO data via a `GET` request to the [Get Page Metadata](https://developers.webflow.com/data/reference/pages/get-metadata) endpoint.** ###### Request ###### Response JavaScript ` | | | | --- | --- | | 1 | // Get page metadata | | 2 | const pageMetadata = await webflow.pages.getMetadata(contactPageId); | ` 2. **Translate the data so that it’s relevant for the French audience.** We’ve provided localized information for you with `./helpers/seoData.json`. ./helpers/seoData.json ` | | | | --- | --- | | 1 | { | | 2 | "title": "Contactez-nous", | | 3 | "slug": "contactez-nous", | | 4 | "seo": { | | 5 | "title": "Contactez-nous \| AstralFund Financier", | | 6 | "description": "Contactez AstralFund Financier pour des conseils financiers experts et un soutien. Notre équipe dédiée est là pour vous aider sur votre chemin vers le succès financier. Contactez-nous aujourd'hui." | | 7 | }, | | 8 | "openGraph": { | | 9 | "title": "AstralFund Financier - Votre partenaire pour la réussite financière", | | 10 | "titleCopied": true, | | 11 | "description": "Découvrez les services financiers personnalisés d'AstralFund et prenez le contrôle de votre avenir financier. Contactez-nous pour en savoir plus.", | | 12 | "descriptionCopied": true | | 13 | } | | 14 | } | ` 3. **Update the SEO Data for the French locale via a `POST` request to the [Update Page Metadata](https://developers.webflow.com/data/reference/pages/update-page-settings) endpoint.** Be sure to enter the `localeId` in the `locale` query parameter. JavaScript ` | | | | --- | --- | | 1 | // Get page metadata | | 2 | const pageMetadata = await webflow.pages.getMetadata(contactPageId); | | 3 | | | 4 | // Create Localized Page Setting Request | | 5 | const localizedMetadata = {}; | | 6 | localizedMetadata.locale = secondaryLocaleId; | | 7 | localizedMetadata.body = localizedMetadataBody; // Use the localized SEO data | | 8 | | | 9 | // Update SEO Data | | 10 | await webflow.pages.updatePageSettings(contactPageId, localizedMetadata); | ` ###### 6\. Manage Testimonials with the CMS To demonstrate AstralFund’s commitment to the French market, we’ll translate the existing testimonials, and create a French-specific testimonial from a French regulatory authority. 1. Get existing testimonials and translate them using our provided translation. Javascript ` | | | | --- | --- | | 1 | // Get Collections | | 2 | const collectionsData = await webflow.collections.list(siteId); | | 3 | const collections = collectionsData.collections; | | 4 | | | 5 | // Find Testimonials Collection | | 6 | const testimonialsCollectionId = collections.find( | | 7 | (collection) => collection.displayName === "Testimonials" | | 8 | ).id; | | 9 | | | 10 | const itemsData = await webflow.collections.items.listItems( | | 11 | testimonialsCollectionId | | 12 | ); | | 13 | const items = itemsData.items; // Get item data from testimonial collection | ` 2. For each translated testimonial, update the CMS item via the Update Collection Item endpoint. Be sure to include `cmsLocaleId` in the Item. JavaScript `` | | | | --- | --- | | 1 | try { | | 2 | // For each CMS item | | 3 | for (const [index, value] of items.entries()) { | | 4 | | | 5 | // Add the secondary `cmsLocaleId` to the item | | 6 | frenchTestimonials[index].cmsLocaleId = secondaryCmsLocaleId; | | 7 | | | 8 | // Update the CMS item | | 9 | const updatedItem = await webflow.collections.items.updateItemLive( | | 10 | testimonialsCollectionId, | | 11 | value.id, | | 12 | frenchTestimonials[index] | | 13 | ); | | 14 | console.log(`Item:`, updatedItem); | | 15 | } | | 16 | } catch (error) { | | 17 | console.error(`Error updating CMS items:`, error); | | 18 | throw error; | | 19 | } | `` 3. Create a French-only testimonial using our provided translation. `` | | | | --- | --- | | 1 | // Create new item | | 2 | try { | | 3 | // Set the `cmsLocaleId` of the new item | | 4 | newFrenchTestimonial.cmsLocaleId = secondaryCmsLocaleId; | | 5 | | | 6 | const newTestimonial = await webflow.collections.items.createItem( | | 7 | testimonialsCollectionId, | | 8 | newFrenchTestimonial | | 9 | ); | | 10 | console.log("Localization process completed successfully."); | | 11 | } catch (error) { | | 12 | console.error("Error Creating CMS Item:", error); | | 13 | } | `` ###### 7: Appreciate your beautifully localized site! 👏 Congratulations! You’ve localized your AstralFund site! Take a look around the site and see what other opportunities you have to localize content. ###### Primary Locale ###### Secondary Locale ### United States 🇺🇸 The site’s primary locale is set to the United States with content in English. ![](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/d34fd40-AstralFund_Financial_-_English_-_Hero.png)![](https://files.buildwithfern.com/https://webflow-prod.docs.buildwithfern.com/2025-03-19T19:52:09.981Z/assets/images/ff584c7-AstralFund_Financial_-_English_-_Testimonial.png) [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # User Authentication with ID Tokens — Webflow API Documentation [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Deep linking — Webflow API Documentation To streamline the hand-off between a 3rd party experience and the Webflow Designer Extension, use the following deep link format: ` | | | | --- | --- | | $ | https://.design.webflow.com?app= | ` * `site short name`: Use the [Get Site Information](/designer/reference/get-site-info) method to retrieve this. * `client id`: Available in your App’s settings in the Webflow Dashboard under Apps & Integrations. ### Why This Matters Deep linking allows you to bypass extra steps and provide a smooth user experience when moving from your Hybrid App to the Webflow Designer. If the App is already installed on the target site, the Designer launches directly with your Extension, reducing friction and context-switching for users. * **If the App is installed**: The Designer session starts with the Extension. * **If the App is not installed**: The Designer will launch as normal without the Extension, treating the deep link as a no-op. ### How It Works * **Fetch the Site Short Name:** The site short name is needed to construct the link. You can retrieve it using the [Get Site Information](/designer/reference/get-site-info) method or [Get Site endpoint](/v2.0.0/data/reference/sites/get) . * **Locate the Client ID:** Find the `client_id` in the Webflow Dashboard under Apps & Integrations in your App’s settings. By constructing a deep link with this format, you ensure that your Hybrid App and the Webflow Designer Extension work together seamlessly, reducing unnecessary user input and improving the overall flow between the two environments. [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) --- # Localizing Components (Beta) — Webflow API Documentation ##### Beta Feature This feature is currently in beta and may be subject to changes. During the beta phase, some functionality might be limited or unstable. Please use it with caution in production environments and provide feedback to help us improve. What are Components? -------------------- Components in Webflow empower you to create reusable and customizable blocks from various elements to help maintain a consistent, efficient, and scalable design workflow. Using the Localization APIs for components, teams can ensure the design of components remain consistent, while ensuring their translations are suited for a specific locale. Below, we’ll quickly cover the key concepts of components in Webflow. For a more detailed understanding, [visit Webflow University](https://university.webflow.com/lesson/components?topics=layout-design) . Component definitions, instances, and properties ------------------------------------------------ ### Component definition The component definition is the blueprint for a component. It establishes the foundational structure of the elements within the component, as well as properties that can be further defined in a component instance. Any modifications made to the component definition will propagate and automatically update all associated component instances. This ensures consistency across instances while allowing for centralized changes. ### Component instance A component instance is a single instantiation of the component definition. While it retains the core design and structure of the definition, each instance can be [customized through component properties](https://university.webflow.com/lesson/components?topics=layout-design#how-to-define-component-properties) . ### Component properties Component properties, or “props,” in Webflow define the customizable elements of a component, such as text, images, or links. While designers can provide default values for props, they can also be overridden in a component instance without changing the original component definition. These properties can be modified across locales, enabling seamless translation of your site into different languages. This flexibility allows you to create unique, localized variations of a component across different pages or sections, maintaining consistency while adapting to specific needs of a locale. Localizing Components in Webflow -------------------------------- When it comes to localizing components in Webflow, you have two approaches based on your preferences and specific needs: 1. **Localize a Component Definition** This approach is more suitable for commonly used components, like Navbars and Footers, that will appear throughout the localized version of your site. By localizing properties at the component definition level, you ensure consistency across all instances, making it easier to manage and update as needed. 2. **Localize a Component Instance** This method is ideal for components that are used in varied contexts, such as Hero Sections, Testimonials, and Call-to-Action Buttons. By localizing each instance individually, you can customize the content to meet specific needs and contexts, ensuring that it resonates with local audiences. ###### Localize Component Definition For frequently used components or those whose content remains consistent, localizing the component definition is the most effective approach. This method ensures that any changes made to the component’s properties will automatically propagate to all instances, maintaining uniformity across your site while streamlining localization efforts. ### Step 1: Identify Components to Localize Start by identifying the main components you want to localize. You can obtain a comprehensive list of all components available on your site by calling the [List Components endpoint](/v2.0.0-beta/reference/pages/components/list) . This endpoint provides details about each component, including its ID, name, group, and description. **Example Response** JSON ` | | | | --- | --- | | 1 | { | | 2 | "components": [ | | 3 | { | | 4 | "id": "6596da6045e56dee495bcbba", | | 5 | "name": "Primary Button", | | 6 | "group": "Buttons", | | 7 | "description": "A default button component that can be used across the site" | | 8 | }, | | 9 | { | | 10 | "id": "658205daa3e8206a523b5ad4", | | 11 | "name": "Secondary Button", | | 12 | "group": "Buttons", | | 13 | "description": "A secondary button component that can be used across the site" | | 14 | }, | | 15 | { | | 16 | "id": "6258612d1ee792848f805dcf", | | 17 | "name": "Card", | | 18 | "group": null, | | 19 | "description": null | | 20 | }, | | 21 | { | | 22 | "id": "68a2b1d1ee792848f805dcf", | | 23 | "name": "Nav", | | 24 | "group": null, | | 25 | "description": null, | | 26 | "readonly": true | | 27 | } | | 28 | ], | | 29 | "pagination": { | | 30 | "limit": 20, | | 31 | "offset": 0, | | 32 | "total": 4 | | 33 | } | | 34 | } | ` **Understanding the component object** Each component object contains the following properties: * `id`: A unique identifier for the component. * `name`: The name of the component. * `group`: The category to which the component belongs, which may be null. * `description`: A user-defined explanation of the component’s purpose, which may be null. * `readonly`: Indicates whether the component can be updated within the site. For example, components in Workspace Libraries are set to read-only. ### Step 2: Localizing Component Properties To localize a component definition, you’ll primarily work with its properties. With the ID of your selected component, use the [Get Component Properties endpoint](/v2.0.0-beta/reference/pages/components/get-properties) to get a list of the different properties that can be localized. **Example Response** ` | | | | --- | --- | | 1 | { | | 2 | "componentId": "658205daa3e8206a523b5ad4", | | 3 | "properties": [ | | 4 | { | | 5 | "id": "a245c12d-995b-55ee-5ec7-aa36a6cad623", | | 6 | "label": "Title", | | 7 | "type": "Plain Text", | | 8 | "text": { | | 9 | "html": null, | | 10 | "text": "The Hitchhiker's Guide to the Galaxy" | | 11 | } | | 12 | }, | | 13 | { | | 14 | "id": "a245c12d-995b-55ee-5ec7-aa36a6cad627", | | 15 | "label": "Content", | | 16 | "type": "Rich Text", | | 17 | "text": { | | 18 | "html": "

Don't Panic!

Always know where your towel is.

", | | 19 | "text": null | | 20 | } | | 21 | } | | 22 | ], | | 23 | "pagination": { | | 24 | "limit": 2, | | 25 | "offset": 0, | | 26 | "total": 2 | | 27 | } | | 28 | } | ` **Understanding the property object** Each property object consists of the following fields: * `id`: The unique identifier for the property. * `label`: The display name of the property. * `type`: The type of data. * `text`: An object containing the text values: * `html`: The HTML representation of the content. * `text`: Plain text representation. ##### Viewing Component DOM If you’d like to see the component’s DOM structure, you can use the [Get Component Content endpoint](/v2.0.0-beta/reference/pages/components/get-content) to fetch the static content of the component, that cannot be localized through properties. ### Step 3: Updating Component property values in a secondary locale Now that you have the properties of the component you wish to localize, you can translate the property values and use them as default values in your localized component definition. To localize component property values in a secondary locale, we’ll need to make a post request to the [Update Component Properties endpoint](/v2.0.0-beta/reference/pages/components/update-properties) . Our request should include the following: ###### cURL Request ###### Parameters CURL REQUEST ` | | | | --- | --- | | 1 | curl --request POST \ | | 2 | --url 'https://api.webflow.com/beta/sites/65427cf400e02b306eaa049c/components/1fa6f97b-84f7-2db3-29cb-1275161e432f/properties?locale_id=65427cf400e02b306eaa04a0' \ | | 3 | --header 'accept: application/json' \ | | 4 | --header 'content-type: application/json' \ | | 5 | --data ' | | 6 | { | | 7 | "properties": [ | | 8 | { | | 9 | "propertyId": "a245c12d-995b-55ee-5ec7-aa36a6cad623", | | 10 | "text": "La guía del autoestopista galáctico" | | 11 | }, | | 12 | { | | 13 | "propertyId": "a245c12d-995b-55ee-5ec7-aa36a6cad627", | | 14 | "text": "¡No entres en pánico!

Siempre sabe dónde está tu toalla.

" | | 15 | } | | 16 | ] | | 17 | } | | 18 | ' | ` ###### Localize Component Instances For components that are repurposed to fit the specific needs of a page—such as custom landing pages, campaigns, or time-sensitive promotions—localizing a component instance is the right approach. This method allows you to overwrite default text and tailor the content to resonate with local audiences. When localizing a component instance, you’ll make updates directly on the specific page where the instance appears, rather than modifying the component definition itself. **It’s important to note that while you’re managing the localized component properties, the default property values must have been overwritten in the primary locale to ensure consistency and relevance.** ### Step 1: Get Page Content of the Primary Locale To begin localizing a component instance, you need to retrieve the page content of the primary locale using the [Get Page Content endpoint](/v2.0.0-beta/reference/pages/get-content) . This endpoint returns details about every element that can be localized, now including component instances. ##### Overridden Properties A component instance will only appear in the [Get Page Content response](/v2.0.0-beta/reference/pages/get-content) if its property values have been overridden from the default settings in the primary locale. The API response will include only these overridden properties, and will not return [static content of a component](/v2.0.0-beta/reference/pages/components/get-content) . **Example Response** JSON ` | | | | --- | --- | | 1 | { | | 2 | "id": "34a7a7db-656d-7f88-167b-408785df039f", | | 3 | "type": "component-instance", | | 4 | "componentId": "1fa6f97b-84f7-2db3-29cb-1275161e432f", | | 5 | "properties": [ | | 6 | { | | 7 | "id": "ea72bc3f-05ad-603b-1c91-6c6d875d1379", | | 8 | "text": { | | 9 | "html": null, | | 10 | "text": "Features" | | 11 | } | | 12 | }, | | 13 | { | | 14 | "id": "c231a00f-3df8-ec07-15b7-86a4795541c4", | | 15 | "type": "Plain Text", | | 16 | "label": "Navbar link - Products", | | 17 | "text": { | | 18 | "html": null, | | 19 | "text": "Products" | | 20 | } | | 21 | }, | | 22 | { | | 23 | "id": "52be38f0-169b-8da1-63f8-951da106280a", | | 24 | "type": "Plain Text", | | 25 | "label": "Navbar link - Resources", | | 26 | "text": { | | 27 | "html": null, | | 28 | "text": "Resources" | | 29 | } | | 30 | }, | | 31 | { | | 32 | "id": "68924720-efbe-730d-eccf-47118e486009", | | 33 | "type": "Plain Text", | | 34 | "label": "Navbar link - Contact", | | 35 | "text": { | | 36 | "html": null, | | 37 | "text": "Contact" | | 38 | } | | 39 | }, | | 40 | { | | 41 | "id": "6644d791-c4b3-a065-35c5-053d194a759b", | | 42 | "type": "Plain Text", | | 43 | "label": "Button Text - Get Started", | | 44 | "text": { | | 45 | "html": null, | | 46 | "text": "Get Started" | | 47 | } | | 48 | } | | 49 | ] | | 50 | } | ` **Component Instance Structure** A component instance has a different structure compared to regular elements. Here are the main fields you’ll encounter: * `id`: The element ID. * `type`: The element type, which is component-instance. * `componentId`: The ID of the component definition. * `properties`: An array of all the overridden properties that can be localized. Each property object contains the following fields: * `id`: The property ID. * `type`: The property type (currently only text properties can be localized). * `label`: The property name as defined in the Component Definition. * `text`: An object containing the text and/or HTML of the property value. For now, the html value will always be null. ### Step 2: Update Page Content of the Secondary Locale With the IDs of the nodes and component properties you wish to update, you can create a payload for the [Update Page Content endpoint](/v2.0.0-beta/reference/pages/update-static-content) to localize your content. This payload should include the `nodeId` of the component instance and an array of `properties` that need to be updated. **Example Payload** JSON ` | | | | --- | --- | | 1 | { | | 2 | "nodes": [ | | 3 | { | | 4 | "nodeId": "1fa6f97b-84f7-2db3-29cb-1275161e432f", | | 5 | "properties": [ | | 6 | { | | 7 | "propertyId": "ea72bc3f-05ad-603b-1c91-6c6d875d1379", | | 8 | "text": "Fonctionnalités" | | 9 | }, | | 10 | { | | 11 | "propertyId": "c231a00f-3df8-ec07-15b7-86a4795541c4", | | 12 | "text": "Produits" | | 13 | }, | | 14 | { | | 15 | "propertyId": "52be38f0-169b-8da1-63f8-951da106280a", | | 16 | "text": "Ressources" | | 17 | }, | | 18 | { | | 19 | "propertyId": "68924720-efbe-730d-eccf-47118e486009", | | 20 | "text": "Contact" | | 21 | }, | | 22 | { | | 23 | "propertyId": "6644d791-c4b3-a065-35c5-053d194a759b", | | 24 | "text": "Commencer" | | 25 | } | | 26 | ] | | 27 | } | | 28 | ] | | 29 | } | ` In this example, we’ve only updated plain text properties. For other property types, ensure that the property value matches the expected type: * Plain Text and Alt Text: `text: Hello World!` * Rich Text: “text”: `

HelloWorld!

` ### Step 3: Get Page Content of the Secondary Locale Use the Get Page Content endpoint with the locale query parameter set to your secondary locale. This request will return the page content for that locale, including any localized changes to component instance properties. Conclusion ---------- By following these steps, you can effectively localize components on a Webflow site. Keep in mind the current limitations regarding what can be localized and ensure your payload matches the property type requirements to avoid issues during the localization process. [Built with](https://buildwithfern.com/?utm_campaign=buildWith&utm_medium=docs&utm_source=developers.webflow.com) ---