> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://developers.webflow.com/data/v2.0.0/docs/working-with-custom-code/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developers.webflow.com/_mcp/server. # Working with Custom Code 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. > **Building a Marketplace App?** > > Scripts you register and apply to customer sites are part of your reviewed App experience. Script versions are immutable by design — you cannot overwrite a registered script — so approved code can't change after review. To ship changes to code running on customer sites, register a new script version and submit an App update for review. See [App-delivered code and injected scripts](/apps/docs/marketplace-guidelines) in the Marketplace Guidelines. > **Managing scripts across your App's lifecycle** > > * **Changes require a publish.** Applying, updating, or removing a script through the API changes a site's custom code, but the change only takes effect when the site is published. Publishing pushes *all* staged site changes live, so prompt users to publish when they're ready rather than publishing automatically on their behalf. > * **Prefer the API over manual installation.** Deliver code through the Custom Code API rather than asking users to paste scripts into their site manually. Manually pasted code sits outside your App's lifecycle — your App can't version, update, or remove it — and it can run twice when your App also applies the same script through the API. > * **Retain the scopes needed for a clean uninstall.** To remove the code your App applied when a user uninstalls, your App must keep the scopes that let it do so — `custom_code:write`, plus `sites:write` or `pages:write` for scripts applied at the site or page level — and publish the affected site so the removal takes effect. Remove applied scripts at both the site and page level. See [App-delivered code and injected scripts](/apps/docs/marketplace-guidelines). ## Prerequisites * A clone of the [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) with the following scopes: `sites:read`, `sites:write`, `pages:read`, `pages:write`, `custom_code:read`, and `custom_code:write`. Only Webflow Apps with OAuth tokens can call the custom code API endpoints, not clients with site or Workspace tokens. * An [Ngrok account and authentication token](http://ngrok.com/). This guide uses Ngrok to set up a secure tunnel for the 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 ![Without Custom Code](/_fern-files/webflow.docs.buildwithfern.com/883b8c617cdfbb25c4db118cc8e9827ef89b2fc0d0ea63f5ee407800f5b4264e/assets/images/6d4b083-Large_GIF_1230x624.gif) #### With Custom Code ![With Custom Code](/_fern-files/webflow.docs.buildwithfern.com/11612b6401a78443be52441d5fe6083bbb8ead9a81029acc6731d1d2cf77504e/assets/images/0fbf9c8-Large_GIF_1238x662.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`** ```bash 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`** ```env .env WEBFLOW_CLIENT_ID=YOUR_CLIENT_ID WEBFLOW_CLIENT_SECRET=YOUR_CLIENT_SECRET NGROK_AUTH_TOKEN=YOUR_NGROK_AUTH_TOKEN PORT=8080 ``` #### 3. Start and Authorize Your App 1. **Start the Project** Run the following command in your IDE to start the project: **`Bash`** ```bash 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 ![Terminal Output](/_fern-img/b5a2cec6e0eb22c2d167d1d11c423825cbe3f099608f79d941f16d8d771544bb.webp) #### Update App Redirect URI ![Update App Redirect URI](/_fern-files/webflow.docs.buildwithfern.com/42e1699df2021d780a22362b803636c2ff30b663a41ea3df18fa87e54aec05bf/assets/images/cf5b0e1-Large_GIF_1320x708.gif) 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 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`** ```javascript backend/controllers/scriptController.js export const registerHostedScript = async (req, res) => { try { const siteId = req.params.siteId; async function generateSRI(url) { const response = await fetch(url); const data = await response.text(); const integrity = Sri(data, ["sha256"]); return integrity; } const hostedLocation = req.body.hostedLocation; const integrityHash = await generateSRI(hostedLocation); const script = { hostedLocation: hostedLocation, integrityHash: integrityHash, canCopy: true, version: req.body.version, displayName: req.body.displayName }; const data = await req.webflow.scripts.registerHosted(siteId, script); res.json(data); } catch (error) { console.error("Error registering hosted script:", error); res.status(500).send("Failed to register hosted script"); } }; ``` #### Inline Scripts Inline scripts require the actual JavaScript `sourceCode` to be provided. Each inline script has a limit of 10,000 characters. When providing the source code, do not include \