# All Products

Created with 💙 by Reform Digital®

***

Welcome to the official docs for Reform Digital's suite of tools. Select a product to get started.

* [**DevKit**](/devkit)**™** – Repository template for Webflow.
* [**CookieFlow**](/cookie-flow)**™** – GDPR-compliant cookie consent for Webflow.
* [**ScriptEmbed**](/script-embed)**™** – Dynamic component script loader for Webflow.
* [**TooltipX**](/tooltip-x)**™** – Accessible tooltips for Webflow.
* [**ContactCloak**](/contact-cloak)**™** – Protect contact information from scrapers and bots.
* **CopyKit™** – One-click copy-paste functionality for Webflow components. *(Coming soon)*
* **FlowAudio™** – CMS Audio player for Webflow. *(Coming soon)*


# DevKit™

Repository template for Webflow. Includes support for private repositories, NPM publishing, and CDN deployment.

<a href="https://github.com/reform-digital/webflow-devkit" class="button primary">Clone the GitHub template</a>  <a href="/pages/XjyqhlXXS1Z8aTIqgBPX" class="button secondary">View condensed version</a>

![](https://uploads-ssl.webflow.com/61700604b1b79e1cd9ef9412/6618f3d81b4b7e5a7b89c264_DevKit.png)

Webflow DevKit™ serves as a powerful template, employed by the development team at [Reform Digital®](https://reform.digital) - an award-winning Webflow agency and partner. Designed with a keen emphasis on upholding best practices and optimizing workflows, it aims to revolutionize web development processes. Specifically sculpted to complement Webflow development, this kit harmoniously integrates simplicity and efficiency, seeking to seamlessly embed them into your project lifecycle.

Before diving into development, please read through this documentation to familiarize yourself with the working structure of the template.

## Introduction

The Webflow DevKit™ by Reform Digital® is more than just a tool—it represents a holistic approach to web development, offering a structured framework that aligns with the modern dynamics of the Webflow platform. Whether you're starting from scratch or integrating into an existing project, this template encapsulates a workflow optimized for efficiency, clarity, and scalability.

#### Workflow Overview

1. **Local Development in Sync with GitHub:** Write and revise your code locally while maintaining version control through a synchronized GitHub repository. This enables collaborative work, easy version tracking, and a centralized source of truth for your project.
2. **Testing via Local Server:** Before deploying any changes, test your code in real-time through a local server environment. This allows for rigorous debugging, performance analysis, and ensures the integrity of your code.
3. **Deploy to NPM:** Once you're satisfied with your local iterations, deploy your code to NPM. NPM serves as a reliable package manager, allowing you to manage and distribute your code efficiently.
4. **Serve to Webflow via JsDelivr CDN:** By utilizing the JsDelivr CDN, your deployed code can be seamlessly integrated into your Webflow projects. This ensures fast delivery, high uptime, and optimal performance for your web applications.
5. **Iterate, Version, and Scale:** The Webflow DevKit encourages iterative development. As your project grows, easily roll out new versions of your code. This modular approach ensures future maintenance, continuous scaling, and flexibility.

By leveraging the capabilities of this DevKit™, developers can focus on what truly matters—the development process, while being assured that the underlying mechanics and workflows are robust, streamlined, and in tune with best practices.

### Included Tools

* [**pnpm**](https://pnpm.io/)**:** A fast, disk space-efficient package manager for installing code libraries.
* [**esbuild**](https://esbuild.github.io/)**:** An extremely fast JavaScript bundler and minifier, known for drastically reducing build times.
* [**Prettier**](https://prettier.io/)**:** An opinionated code formatter that enforces a consistent style across your codebase by re-formatting code.
* [**ESLint**](https://eslint.org/)**:** A tool for identifying and fixing problems in your JavaScript code with additional configurations for seamless integration with Prettier:
  * [**eslint-config-prettier**](https://github.com/prettier/eslint-config-prettier)**:** Disables ESLint rules that might conflict with Prettier.
  * [**eslint-plugin-prettier**](https://github.com/prettier/eslint-plugin-prettier)**:** Runs Prettier as an ESLint rule.
* [**javascript-obfuscator**](https://github.com/javascript-obfuscator/javascript-obfuscator)**:** A tool for obfuscating JavaScript code, making it more difficult to understand and reverse engineer production code.
* [**chalk**](https://github.com/chalk/chalk)**:** A tool that adds color and style to text in the command line, making it easier and more pleasant to read.
* [**Express**](https://expressjs.com/)**:** A tool for creating web servers through local host for real-time code testing.
* [**Inquirer**](https://github.com/SBoudrias/Inquirer.js/)**:** A user interface library designed to streamline the deployment process. By presenting users with interactive checklists and guided questions, it negates the need for manual editing of scripts and JSON files, ensuring a smoother and more intuitive package setup.
* [**jQuery**](https://jquery.com/)**:** A fast, small, and feature-rich JavaScript library designed to simplify tasks like HTML document traversal and manipulation, event handling, and animation. Webflow projects automatically include the jQuery library, enabling developers to utilize its functionalities without any additional setup. Recognizing this, Webflow DevKit™ seamlessly integrates support for jQuery syntax, without the need to import the library.
* [**Husky**](https://typicode.github.io/husky/)**:** A tool for managing Git hooks, ensuring that code quality checks run automatically before commits. This prevents poorly formatted or linted code from being committed to the repository.
* [**lint-staged**](https://github.com/okonet/lint-staged)**:** A tool that runs linters on staged Git files, ensuring that only the files you're committing are checked and formatted. This provides fast, efficient code quality enforcement during the commit process.

### Prerequisites

Before utilizing this template, ensure the following software and environments are installed on your local machine:

* [**Visual Studio Code**](https://code.visualstudio.com/)**:** A source-code editor that you'll use for writing and managing your code.
* [**Node.js**](https://nodejs.org/)**:** A JavaScript runtime to build and run your applications.
* [**GitHub Desktop**](https://desktop.github.com/)**:** (Optional, but recommended) A graphical interface that enables you to interact with GitHub without using the command line.
* [**Google Chrome**](https://www.google.com/chrome/)**:** A Chromium-based browser such as Google Chrome or Arc is required. Please note that this template is not compatible with Safari or some other browsers and may not function as intended if used with them.

***

## Installation

If you are an existing DevKit™ user, you can skip this detailed guide and view the Condensed Guide instead.

{% stepper %}
{% step %}

### Setup Template

1. **Create GitHub account**:
   * If you haven’t done so, [create a GitHub account](https://github.com/join).
2. **Clone this template**:
   * Navigate to the [main page](https://github.com/reform-digital/webflow-devkit) of the template repository.
   * Click on `Use this template` at the top of the repository and choose `Create a new repository`.
   * Ensure the "Owner" is your GitHub username, and give your repository a unique name relevant to the project (e.g., `client-project-name`).
   * Choose `Private` as the repository visibility.
   * Click on `Create repository` to generate your new repository.
3. **Download the Repository Locally Using GitHub Desktop**:
   * Navigate to your newly created GitHub repository (if not redirected there already upon creation).
   * Click on the `Code` button, and then choose `Open with GitHub Desktop`.
   * Follow the steps in GitHub Desktop to choose a folder on your local machine where the repository files will be downloaded and synchronized, and press `clone`.
4. **Launch Your Development Environment**:
   * In GitHub Desktop, check that your new repository is now listed under `Current Repository` and if not make sure to select it.
   * Click on the `Repository` tab in the top menu, and choose `Open in Visual Studio Code` or use the quick button link.
   * Visual Studio Code should launch, opening your project repository locally, ready for development.
     {% endstep %}

{% step %}

### Setup NPM

* **Create a Free NPM Account:**
  * If not done so already, create a free [NPM account](https://www.npmjs.com/).
* **(Optional) Create an NPM Organization:**
  * If you intend to manage your package under your own account/organization, you may **skip this step**.
  * If multiple owners or specific permissions for a project are required (e.g., for a client project), create a new NPM organization under your account.
  * Name it according to your client's company or project name.
  * Grant your client permission to this organization whenever needed.
* **Create an NPM Access Token:**
  * Click on your profile icon in NPM and select `Access Tokens`.
  * Click `Generate New Token` and select `Granular Access Token`.
  * Name it descriptively, such as "Your-Project-Name NPM Token".
  * **Configure Permissions:**
    * Select `Read and write` access (required for publishing packages)
    * Choose the appropriate scope (your package scope or organization)
  * **Set Expiration:** Choose between 7-90 days (recommended: 30 days for regular rotation)
  * Click `Generate Token` to finish.
* **Copy Your NPM Token:**
  * Ensure that the generated token is copied as it cannot be viewed again.
* **Add the NPM Token to GitHub Secrets:**

  **For Solo Developers:**

  * Navigate to your project repository on GitHub
  * Go to the project `Settings` → `Secrets and variables` → `Actions`
  * Click `New repository secret`
  * Name: `NPM_TOKEN`
  * Value: Paste your NPM token
  * Click `Add secret`

  **For Organization Teams:**

  **Option A: For Each New Repository (Free)**

  * Go to each project repository → `Settings` → `Secrets and variables` → `Actions`
  * Click `New repository secret`
  * Name: `NPM_TOKEN`
  * Value: Paste your NPM token
  * Click `Add secret`
  * **Note:** Repeat this process for each new repository

  **Option B: Only Once for Whole Organization (Paid)**

  * **⚠️ Prerequisite:** Ensure your GitHub organization has a **paid plan** (required for organization secrets with private repositories)
  * Go to organization settings → `Secrets and variables` → `Actions`
  * Click `New organization secret`
  * Name: `NPM_TOKEN`
  * Value: Paste your NPM token
  * Repository access: Select "All repositories"
  * Click `Add secret`
  * **Note:** This automatically works for all repositories in the organization
    {% endstep %}

{% step %}

### Setup Access Token

* **Create GitHub Personal Access Token:**
  * Go to GitHub Settings → `Developer settings` → `Personal access tokens` → `Tokens (classic)`
  * Click `Generate new token (classic)`
  * **Token Configuration:**
    * **Note:** "DevKit Template - \[Project Name]"
    * **Expiration:** 90 days (recommended)
    * **Scopes:** Select the following:
      * ✅ **`repo`** (Full control of private repositories)
      * ✅ **`workflow`** (Update GitHub Action workflows)
      * ✅ **`write:packages`** (Upload packages to GitHub Package Registry)
      * ✅ **`read:packages`** (Download packages from GitHub Package Registry)
  * Click `Generate token`
  * **Copy the token immediately** (you won't see it again!)
* **Add PAT to GitHub Secrets:**

  **For Solo Developers:**

  * Go to your project repository → `Settings` → `Secrets and variables` → `Actions`
  * Click `New repository secret`
  * Name: `PERSONAL_ACCESS_TOKEN`
  * Value: Paste your PAT
  * Click `Add secret`

  **For Organization Teams:**

  **Option A: For Each New Repository (Free)**

  * Go to each project repository → `Settings` → `Secrets and variables` → `Actions`
  * Click `New repository secret`
  * Name: `PERSONAL_ACCESS_TOKEN`
  * Value: Paste your PAT
  * Click `Add secret`
  * **Note:** Repeat this process for each new repository

  **Option B: Only Once for Whole Organization (Paid)**

  * **⚠️ Prerequisite:** Ensure your GitHub organization has a **paid plan** (required for organization secrets with private repositories)
  * Go to organization settings → `Secrets and variables` → `Actions`
  * Click `New organization secret`
  * Name: `PERSONAL_ACCESS_TOKEN`
  * Value: Paste your PAT
  * Repository access: Select "All repositories"
  * Click `Add secret`
  * **Note:** This automatically works for all repositories in the organization
    {% endstep %}

{% step %}

### Setup VS Code

This section guides you through setting up your project package in Visual Studio Code or Cursor, which involves installing a package manager, managing dependencies, and initial setup. Make sure you have the correct project and directory loaded in Visual Studio Code – you can always use GitHub desktop to load the correct repository (as you did in Step 1.4).

1. **Install pnpm (First-Time Only):**
   * pnpm is a fast, disk space efficient package manager. If it's your first time using pnpm, install it globally with the following command:

     ```sh
     npm install -g pnpm
     ```
2. **Install VS Code Extensions (First-Time Only):**
   * Install and activate [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) and [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) extensions in Visual Studio Code.
3. **Install Dependencies:**
   * Execute the following command to install the project dependencies:

     ```sh
     pnpm install
     ```

#### ✅ Installation Complete!

{% endstep %}
{% endstepper %}

***

## How to use DevKit™

Understanding the structure of the Webflow DevKit™ template is crucial for a seamless development experience.

### Project Folders

Here’s a guide to help you navigate through the key directories and utilize them effectively:

#### Source Directory

The `src` folder serves as the primary workspace for your project, housing all the JavaScript files, CSS files, and modules necessary for your Webflow site.

#### Files Folder

Located within the src directory, the `files` folder is your primary working area designated for housing all your main JavaScript and CSS files for the project. For example `home.js`, `home.css`, `about.js`, `contact.js`, and so forth.

Additionally, you can create any global files such as `global.js`, `global.css`, `analytics.js`, etc. in the same Files folder, if you wish to execute certain scripts or invoke specific modules across all pages of your website. The actual scope of each file (i.e. page-specific versus global) will depend on where it is imported in Webflow (see Importing Scripts in Webflow).

#### Modules Folder

Adjacent to the files folder, the `modules` directory is intended for smaller, reusable script segments. Examples of files you might store here include:

* `greet.js`: A simple module to greet users.
* `mirror-click.js`: A helper function to mirror click events in Webflow, useful across various sections and pages.
* `animations.js`: A collection of animation functions to enhance your site's interactivity.

These modular script files can be effortlessly imported into any of your page-specific script files. This practice not only keeps your codebase tidy but also fosters a modular development approach, making your code more maintainable and scalable.

By adhering to this structure, you ensure a well-organized and efficient development environment, paving the way for a smoother integration of JavaScript functionalities and CSS styles into your Webflow projects.

### Development

As you embark on the journey of developing JavaScript and CSS functionality within the "files" and "modules" directories, integrating testing into your workflow is paramount. Conducting tests in a development setting is imperative and should proceed hand-in-hand with the coding phase. To facilitate this, run a local development server and integrate your scripts into your Webflow staging domain. Stay alert for any anomalies or errors, utilizing the available debugging tools to rectify issues as they arise. This continuous loop of coding, testing, and debugging is crucial for cultivating a stable and trustworthy codebase.

#### Running the Development Server

To build and initiate the development server, execute:

```sh
pnpm dev
```

The development server facilitates **live reloading** on save, providing real-time feedback on your changes and significantly expediting the development and debugging processes.

Furthermore, the development server is enhanced with **sourcemaps**, which are invaluable for debugging. Sourcemaps preserve the visibility of your initial code structure, even when inspecting your Webflow project. This feature is instrumental in tracing back to the origins of imported modules by referencing individual files, rather than navigating through bundled or minified code.

If your project incorporates **multiple DevKit**™ **templates** and you intend to run several local servers simultaneously, it’s necessary to assign unique port numbers to each. To configure this:

* Open the `server.js` file located in the `bin` folder.
* Locate the line `const PORT = 3000;`.
* Modify the port number (3000) to an alternative number (e.g., 3001) to distinguish each template’s local server.

By doing this, you enable the concurrent running of distinct local servers, each serving project files from a different template, all while avoiding port conflicts.

### Pre-commit Hooks

Webflow DevKit includes automatic code quality enforcement through pre-commit hooks powered by Husky and lint-staged. This ensures consistent code formatting and catches linting errors before they reach your repository.

#### How It Works

When you commit code, the following happens automatically:

1. **Prettier** formats your JavaScript and CSS files in the `src/` directory
2. **ESLint** checks for and auto-fixes common issues
3. **Commit is blocked** if any ESLint errors are found
4. **Auto-fixed files** are automatically staged and included in the commit

#### What Gets Checked

* **Files**: Only files in `src/**/*.{js,css}` are processed
* **Formatting**: Prettier ensures consistent code style
* **Linting**: ESLint catches errors and auto-fixes when possible
* **Performance**: Only staged files are checked (fast commits)

#### Benefits

* **Automatic formatting**: No need to manually run Prettier
* **Error prevention**: Catches issues before they reach CI/CD
* **Team consistency**: Everyone gets the same code style
* **Editor agnostic**: Works regardless of your editor or extensions
* **Fast**: Only processes files you're actually committing

#### Troubleshooting

If a commit is blocked due to linting errors:

1. **Check the error message** in your terminal
2. **Fix the issues** manually in your editor
3. **Stage the fixes** with `git add`
4. **Commit again** - the hooks will re-run

The pre-commit hooks are automatically set up when you run `pnpm install` thanks to the `prepare` script in package.json.

### Importing Scripts

DevKit™ offers **two methods** to import your JavaScript and CSS files into your Webflow project:

#### 1️⃣ Traditional Method

During the operation of a local server (via `pnpm dev` or `pnpm prod` mentioned later), DevKit™ conveniently logs the script tags for all JavaScript and CSS files situated in the src folder. These scripts, along with their imported modules and source maps, are subsequently exported to the dev folder and served directly from this location.

**Logged script tags example:**

```
=== JS Scripts: === (Before </body> tag)

 <script src="http://localhost:3000/about.js" defer></script>

 <script src="http://localhost:3000/global.js" defer></script>

 <script src="http://localhost:3000/home.js" defer></script>

=== CSS Scripts: === (Inside <head> tag)

 <link rel="stylesheet" href="http://localhost:3000/home.css">
```

Integration steps:

1. **Page Styles:** Manually copy the required `<link>` tag/s and paste them into the designated Webflow page, inside the `<head>` tag.
2. **Page Scripts:** Manually copy the required `<script>` tag/s and paste them into the designated Webflow page, either before the closing `</body>` tag or inside the `<head>` tag (thanks to the defer attribute, both options work seamlessly).
3. **Global Styles:** For styles intended to be global, add the respective `<link>` tag/s in the Webflow site’s global settings, insice the `<head>` tag.
4. **Global Scripts:** For scripts intended to be global, add the respective `<script>` tag/s in the Webflow site’s global settings, either in the closing `</body` tag or the `head` tag (thanks to defer).

⚠️ **Inefficiency of Traditional Method:** Transitioning from development to production necessitates manually replacing these script tags with their production counterparts, and reverting back for subsequent changes — a process that can become cumbersome over time. To address this shortfall, DevKit™ offers an improved automated method which handles the swtiching of the tags for you:

#### 2️⃣ Automated Method (Recommended)

* Jump to condensed version (experienced DevKit™ users)

DevKit™ offers a custom script import mechanism designed to streamline and automate the process of integrating JavaScript and CSS into your Webflow project. This approach eliminates the need for manual switching between script tags when moving from a development to a production environment, providing a smoother and more efficient workflow.

#### Setup

**`Step 1` Main Settings:**

Add this script to your site’s **global** settings in the **`<head>`** tag. The script is designed to configure essential variables for your project: the path to your npm package, the development mode toggle, and the local port number. These variables are crucial for script loader functions and other development processes across your site.

```
<!-- RD® Webflow DevKit / Main Settings -->
<script>
window.npmPath = "@reform-digital/sample-project@1.0.0"; // Update this once you have shipped to npm.
window.devMode = true; // Change to false in production
window.localPort = 3000; // Also change in bin/localport.js in VS Code
</script>
```

***Main Settings Configurations:***

* **NPM Path:** The Main Settings script includes a default `npmPath` that serves as a placeholder during the development phase. Initially, the template is configured to bypass this sample project path, so there's no immediate need to alter it during development. Once your project is ready for deployment and you've published your package to npm, you should update the `npmPath` variable to your own npm package path "@your-npm-username/your-package-name\@version" to auto-direct the script and style loaders to your live production files via jsDelivr.
* **Dev Mode:** The `devMode` variable is a boolean that controls whether the development mode is active (**true**) or inactive (**false**). When `devMode` is `true` (development mode), the integrated script-loader and style-loader will first check for a local server instance initiated by either `pnpm dev` or `pnpm prod` within VS Code. If a local server is found, it serves the site files directly from there, allowing for real-time testing and development—this local version is only visible to you, while other visitors continue to access the production files. In the absence of a local server, the loaders will fall back to the production version, fetching files via jsDelivr. Furthermore, devMode enables detailed console logging for both local and npm file requests, aiding in the debugging process and clarifying which file sources are being rendered in your local browser. Conversely, when `devMode` is set to `false`, it signifies that the site is in its production phase. The loaders will then bypass the local server check and directly load files from npm to optimize performance. Console logs related to devMode activities are also disabled in production mode to maintain a clean and performance-focused environment.
* **Local Port:** The `localPort` setting specifies the port number on which your local server is running. The default port is **3000** but can be altered to suit your needs, such as when running multiple local servers simultaneously. Adjust the `localPort` value in the main settings to your preferred port to direct the script-loader and style-loader to the correct local server. Ensure this change is also mirrored in the Webflow DevKit™ template within VS Code by modifying the file at `/bin/localport.js` to match otherwise the template will not connect accordingly.

**`Step 2` Style Loader:**

Add this script to your site’s **global** settings in the **`<head>`** tag. It enables the dynamic loading of styles based on the development server’s status.

```
<!-- RD® Webflow DevKit™ / Style Loader -->
<script src="https://cdn.jsdelivr.net/npm/@reform-digital/webflow-devkit-utils@1.2.1/prod/style-loader.js"></script>
```

**`Step 3` Script Loader:**

Add this script to your site’s **global** settings before the **`</body>`** closing tag. It enables the dynamic loading of scripts based on the development server’s status.

```
<!-- RD® Webflow DevKit™ / Script Loader -->
<script src="https://cdn.jsdelivr.net/npm/@reform-digital/webflow-devkit-utils@1.2.1/prod/script-loader.js"></script>
```

#### Import Files

**`Global` Styles:**

If you have any global CSS files that should be loaded across all pages, import them by adding the following script to your site’s **global** settings in the **`<head>`** tag, under the Style Loader script. Add and remove file names as required (the globalStyles variable is a comma-separated array).

```
<!-- RD® Webflow DevKit / Global Styles -->
<script>
const globalStyles = ["global.css", "animation.css"];
loadWebflowStylesheets(globalStyles, npmPath);
</script>
```

**`Global` Scripts:**

If you have any global JavaScript files that should be loaded across all pages, import them by adding the following script to your site’s **global** settings before the **`</body>`** closing tag, under the Script Loader script. Add and remove file names as required (the globalScripts variable is a comma-separated array).

```
<!-- RD® Webflow DevKit / Global Scripts -->
<script>
const globalScripts = ["global.js", "analytics.js"];
loadWebflowScripts(globalScripts, npmPath);
</script>
```

**`Page` Styles:**

If you have any page-specific CSS files that should be loaded on a specific page, import them by adding the following script to your **page** settings in the **`<head>`** tag.

```
<!-- RD® Webflow DevKit / Page Styles -->
<script>
const pageStyles = ["home.css"];
loadWebflowStylesheets(pageStyles, npmPath);
</script>
```

For the About page for example, if you have created an `about.css` in your src folder, you would replace `const pageStyles = ["home.css"];` with `const pageStyles = ["about.css"];`

**`Page` Scripts:**

If you have any page-specific JavaScript files that should be loaded on a specific page, import them by adding the following script to your **page** settings before the **`</body>`** closing tag.

```
<!-- RD® Webflow DevKit / Page Scripts -->
<script>
const pageScripts = ["home.js"];
loadWebflowScripts(pageScripts, npmPath);
</script>
```

For the About page for example, if you have created an `about.js` in your src folder, you would replace `const pageScripts = ["home.js"];` with `const pageScripts = ["about.js"];`

#### How It Works

Once you have shipped your production files to npm (see Shipping to NPM) and updated the `npmPath` in the global script, the script loader automatically loads your production files located in npm via jsDelivr.

When you're ready to test new changes, running a local development server using `pnpm dev` (or a production testing server using `pnpm prod` as oulined in next section) triggers the script loader to temporarily deactivate the live production scripts from npm on your local browser. This enables you to seamlessly work and test in a local environment without affecting what the public sees on your live website.

This transition is seamless and requires no manual intervention, allowing you to focus on development and testing without worrying about the underlying script management. Once you're done and shut down your local server, your browser automatically reverts to serving the live production files, ensuring a consistent and error-free user experience.

By adopting the Automated Method with DevKit’s custom script import mechanism, you are choosing a workflow that is not only more efficient but also less prone to human error, ensuring a smoother development experience and a more reliable live website.

### Production

When your files and modules have been extensively tested and are stable in the development environment, it’s time to shift your focus to the production environment for further testing and validation.

#### Running the Production Server

To assess your code’s performance and security in a production-like setting, execute:

```sh
pnpm prod
```

Executing this command will bundle, minify, and obfuscate your code, aiming to boost performance and security. It’s crucial to note that the production server does not support live reloading. This is a deliberate design choice, as the production environment is not intended for real-time code adjustments. Instead, its primary purpose is to confirm that the production files are correctly bundled and to validate that they function as expected before being deployed to NPM for live production use.

#### Building Without Running a Server

For scenarios where you wish to build the production files without launching the production server, utilize:

```sh
pnpm build
```

Ensuring the built files function properly in a production-like setting is essential. This step verifies their performance and readiness for deployment, confirming that they are fully prepared for live production use.

### Shipping to NPM

After thorough development and testing of your code in both the development and production environments, the next pivotal step is to ship your code to NPM. This is a crucial phase as it involves packaging your code and making it accessible for live production use. We've built a seamless mechanism for shipping your code to NPM.

#### Update the README.md File

Before running the ship command, ensure you have updated the README.md file. If this is not done, then the current DevKit™ README, which you are reading now, will be added to NPM. This could create confusion as it does not provide information specific to your package or project. Instead, your README should clearly outline the purpose, installation, usage, and any other important details related to your package or project.

#### Run the Ship Command

To build and initiate the development server, execute:

```
pnpm ship
```

Note: If you are using the GitHub extension for VS Code, you might receive the message "GitHub for VS Code is requesting additional permissions”. If so, review the permissions requested by the app and grant the necessary permissions.

#### Pre-shipment Checklist

Executing the `pnpm ship` command starts a 9-step pre-shipment checklist. It ensures that the NPM destination, package description, change type (major, minor, patch), and other package details are correctly set.

The script will interactively guide you through the following:

* Confirming the destination package name. You can edit it if necessary.
* Confirming the package description. Again, you can edit this if required.
* Confirming the author. Similarly, you can edit this if required.
* Confirming the package keywords. Again, you can edit or omit this if required.
* Confirming the license type. Similarly, you can edit this if required.
* Choosing the type of version update (patch, minor, major). For initial shipments, the version will be set to 1.0.0.
* Describing the changes in this version, which will be appended to the CHANGELOG.md file.
* Confirming that the README.md file has been updated.
* Final confirmation before proceeding.

After you confirm, the script will:

* Update the package.json with the new version, name, description, and authors.
* Check if the version tag exists locally or remotely and handle it.
* Commit the changes and tag the commit with the new version.
* Trigger the CI/CD Pipeline.

#### CI/CD Pipeline

* **Bundling and Optimization:** The CI/CD pipeline automates the process of bundling your code. It applies necessary optimizations and minifications.
* **GitHub Push:** The code, along with its shipment settings and the updated version number, is then pushed to your GitHub repository.
* **GitHub Action - Ship to NPM:** After the push to GitHub, a predefined GitHub Action is triggered. This action ensures your package is correctly published under your NPM account. It handles tasks like authentication with NPM and publishing.

#### Post-Shipment Steps

After successful shipment to NPM, depending on the script tag import method you've set up in your Webflow project (see Importing Scripts in Webflow), follow the steps below:

**Automated Method (Recommended):**

Update npmPath: In your Webflow project, locate the DevKit™ "Main Settings" script in global `<head>` section. Update the npmPath variable with your shipped NPM package path:

```
const npmPath = "@your-npm-username/your-package-name@version";
```

This directs the script loader to fetch the production files directly from your NPM package when DevMode is off (set to "false") during production. When DevMode is on (set to "true") during development, the script loader tries to load the scripts from your local development server when active and auto-switches to your NPM files when the local server is off. Replace `@your-npm-username/your-package-name@version` with the appropriate values. While you can omit @version to always fetch the latest version of the script, doing so may lead to caching issues if the CDN or browsers cache an older version of the script. Specifying the exact version helps to ensure that users always receive the correct version of your script. Refer to Addressing Version Caching for ways to mitigate these issues.

**Traditional Method:**

If you're using the traditional method for script tags in Webflow, update your script tags to the following format:

```
<script src="https://cdn.jsdelivr.net/npm/@your-npm-username/your-package-name@version/your-filename.js"></script>
```

And your CSS files to:

```
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@your-npm-username/your-package-name@version/your-filename.css">
```

Replace `@your-npm-username/your-package-name@version/your-filename.js` or `.css` with the appropriate values. While you can omit @version to always fetch the latest version of the script, doing so may lead to caching issues if the CDN or browsers cache an older version of the script. Specifying the exact version helps to ensure that users always receive the correct version of your script. Refer to Addressing Version Caching for ways to mitigate these issues.

#### Verification

To ensure everything is in order:

* Visit your live website.
* Open your browser's developer tools and inspect the network requests.
* Confirm that the JavaScript and CSS files are being sourced from jsDelivr.

### Addressing Caching

When deploying updates to your scripts via NPM and serving them through jsDelivr for your Webflow project, understanding how versioning and caching work together is crucial to ensure that your users always receive the latest version of your scripts.

#### Using @latest for Versioning

If you choose to use the @latest tag (or omit the version number altogether), you are instructing jsDelivr to serve the latest version of your script. This is perfectly fine for your initial release, however, for subsequent version releases, this approach can lead to caching challenges:

* **CDN Caching:** jsDelivr, like other CDNs, caches content across its global network of servers to reduce latency and improve performance. When a new version of your script is published, it might take some time for the CDN to update the cached content across all of its servers.
* **Browser Caching:** Browsers also cache content locally to improve page load times. If a user has recently visited your site, their browser might have cached the old version of your script, and it could take some time before the browser checks for an updated version.

#### Manually Purging CDN Cache

To expedite the process of updating cached content on jsDelivr, you can manually purge the cache for your script files. Visit [jsDelivr’s Purge Tool](https://www.jsdelivr.com/tools/purge) and enter the URLs of your script files to clear the cache. However, this process can be time-consuming, especially if you have multiple script files, and it only addresses CDN caching—not browser caching.

#### Manually Clearing Browser Cache

While you can clear your own browser's cache or perform a hard reset (Shift + Refresh) to fetch the latest version of your scripts (provided that the CDN cache has already been resolved or purged), there is no simple way to force this action on your visitors' browsers. If they have visited your site recently and have a cached version of your scripts, they might not see the updates until their browser's cache expires and fetches the new version.

#### Using Specific Versions to Avoid Caching Issues

To circumvent both CDN and browser caching issues, the recommended approach is to use specific version numbers in your imported script tags:

* In the Automated script import method (recommended), under `npmPath` you would add `"@your-npm-username/your-package-name@version"`
* In the Traditional script import method, for each script tag `src` you would add `"https://cdn.jsdelivr.net/npm/@your-npm-username/your-package-name@version/your-filename.js"`
* Similarly, for each style tag `href` you would add `"https://cdn.jsdelivr.net/npm/@your-npm-username/your-package-name@version/your-filename.css"`.

By explicitly specifying the version number, you ensure that both the CDN and browsers treat the updated script as a completely new file, bypassing the cache and delivering the latest version to your users. This approach is crucial when immediate updates are required, and you cannot afford to wait for caches to expire.

#### Conclusion

Understanding how CDN and browser caching work can help you make informed decisions about how to version your scripts and ensure that your users always have access to the latest features and fixes. While using specific versions requires more management, it provides the reliability needed for critical updates. For less critical updates, using @latest might be a convenient option, but be prepared to manually purge the CDN cache and educate your users on clearing their browser's cache if necessary.

### Branches & Contributing

Developing a project with a structured approach to version control can significantly improve the efficiency and clarity of the development process. Below, we outline two common scenarios: working solo and collaborating with multiple developers.

#### Single Developer Workflow

**Initial Development:**

All development work can be done directly in the main branch until the first version is ready to be released.

**Creating a Dev Branch:**

After the initial release, create a `dev` branch from main for ongoing development using GitHub Desktop:

* Open GitHub Desktop and navigate to your repository.
* Click on the current branch at the top of the application to view all available branches.
* Choose “New branch”, name it "dev", and click “Create Branch”.
* Push the new branch to the remote repository by clicking on “Publish branch”.

**Routine Development:**

Ensure you are working in the `dev` branch. You can switch branches in GitHub Desktop by clicking on the current branch’s name and selecting the one you wish to switch to. Your local files will now reflect the state of the `dev` branch. Note that this state is preserved even if you close and reopen GitHub Desktop. Develop, commit your changes, and push your commits to the `dev` branch.

**Stashing Changes:**

If you need to switch branches but have uncommitted changes, GitHub Desktop will offer to stash your changes. Stashing temporarily sets aside your changes, allowing you to switch branches and work on something else. When you’re ready, you can come back and apply your stashed changes.

**Merging and Releasing:**

Once you are ready to release a new version:

* Merge `dev` into `main` via a pull request on GitHub.
* Switch to the `main` branch in GitHub Desktop, pull the latest changes, and run `npm ship` to publish the new version to npm.

By following these steps, a single developer can maintain a streamlined development workflow while keeping the `main` branch stable. The `dev` branch serves as a space for ongoing development, with the ability to create and apply stashes as needed to manage concurrent tasks.

#### Multi-Developer Collaboration Workflow

Collaborating with multiple developers requires a more structured approach to manage concurrent development activities and minimize conflicts.

**1. Setting Up Main and Dev Branches:**

Ensure that both `main` and `dev` branches are set up in the repository, and if not, make sure to add a `dev` branch for the whole team to access. All developers should clone the repository to their local machines using GitHub Desktop:

* Open GitHub Desktop.
* Go to “File” > “Clone Repository” and select the repository from the list.
* Choose the local path for the repository and click “Clone”.
* Run `pnpm install` to install project dependencies.

**2. Creating Feature Branches:**

Each developer works on their specific feature or bug fix by creating a new branch from 'dev', also known as a **feature branch**. In GitHub Desktop:

* Ensure you are on the `dev` branch.
* Click on the current branch at the top, select “New Branch”, name it according to the feature or fix you are working on, and click “Create Branch”.
* Publish the branch to the remote repository by clicking “Publish branch”.

**3. Development, Commit, Push:**

Develop on your feature branch. Commit your changes in GitHub Desktop:

* Enter a summary and description for your changes.
* Click “Commit to \[your-branch-name]”.
* Push your commits to the remote repository by clicking “Push origin”.

**4. Collaboration and Code Review:**

When a feature is complete:

* Open a pull request on GitHub to merge your branch back into `dev`.
* Team members review the code, suggest changes, and discuss implementations.
* After approval, **merge** the branch into `dev`.

**5. Syncing Changes:**

To maintain consistency and minimize merge conflicts, all developers should regularly synchronize their local working branches with the remote repository, ensuring they have the latest changes from the dev branch. Here's how to do it using GitHub Desktop:

Fetch Changes from the Remote Repository:

* Open GitHub Desktop and navigate to your repository.
* Click “Fetch origin” to retrieve the latest changes from the remote repository. If there are new commits on the remote `dev` branch, GitHub Desktop will show an option to “Pull origin”. Click this button to update your local `dev` branch.

Merge Changes from `dev` to Your Feature Branch:

* Ensure you are on your feature branch. You can switch branches using the branch dropdown at the top of GitHub Desktop.
* Go to the “Branch” menu at the top and select “Merge into current branch…”.
* A list of branches will appear. Select `dev` from this list and click “Merge dev into \[your-feature-branch]”.
* If there are any merge conflicts, resolve them in your preferred code editor.

Push Your Changes:

* Once the merge is complete and any conflicts are resolved, commit your changes.
* Push your changes to the remote repository to ensure that your feature branch on GitHub is up-to-date.

By following these steps, you ensure that your feature branch stays synchronized with the latest changes from `dev`, reducing potential issues when it's time to merge your feature back into the development branch.

**6. Adding Collaborators:**

Project maintainers can add collaborators:

* Go to the repository on GitHub.
* Click “Settings” > “Manage access” > “Invite a collaborator”.

**7. Preparing for Release:**

Once `dev` is stable and ready for release:

* Create a pull request to merge `dev` into main.
* Conduct a final review and merge the changes.

**8. Shipping to npm:**

Switch to the `main` branch in GitHub Desktop:

* Fetch the latest changes by clicking “Fetch origin”.
* Pull the changes by clicking “Pull origin” (if there are new commits to pull).
* Run `npm ship` to publish the new version to npm.

#### Conclusion

These workflows are designed to cater to different scales of development, ensuring code integrity and facilitating collaboration. The single developer workflow is straightforward and suited for smaller projects or the initial development phases. The multi-developer collaboration workflow, on the other hand, is robust and accommodates concurrent development activities, making it suitable for larger teams and more complex projects. This structure ensures that every developer's changes are isolated in their own feature branches, allowing for independent development, easy code review, and reduced merge conflicts.


# DevKit™ (Condensed)

Repository template for Webflow. Includes support for private repositories, NPM publishing, and CDN deployment.

<a href="https://github.com/reform-digital/webflow-devkit" class="button primary">Clone the GitHub template</a>  <a href="/pages/mFbvmDctzOWym3tRUu5O" class="button secondary">View full version</a>

![](https://uploads-ssl.webflow.com/61700604b1b79e1cd9ef9412/6618f3d81b4b7e5a7b89c264_DevKit.png)

## Installation

{% stepper %}
{% step %}

### Setup Template

* Click on "Use this template" in GitHub and clone as private repository.
* Open locally with GitHub Desktop and open project in Visual Studio Code.
  {% endstep %}

{% step %}

### Setup NPM

* Create NPM account
* Generate NPM Granular Access Token with read/write permissions
* Set Token Expiration: 30-90 days (recommended: 30 days)
* Copy NPM Token (not retrievable later)

**Add NPM Token to GitHub Secrets:**

**For Solo Developers:**

* Go to project repository → Settings → Secrets and variables → Actions
* New repository secret: Name `NPM_TOKEN`, paste token

**For Organization Teams:**

* **Option A (Free):** Add to each repository's secrets
* **Option B (Paid):** Add to organization secrets (requires paid plan)
  {% endstep %}

{% step %}

### Setup Access Token

* Go to GitHub Settings → Developer settings → Personal access tokens → Tokens (classic)
* Generate new token (classic)
* Configure scopes: repo, workflow, write:packages, read:packages
* Copy token immediately (not retrievable later)

**Add PAT to GitHub Secrets:**

**For Solo Developers:**

* Go to project repository → Settings → Secrets and variables → Actions
* New repository secret: Name `PERSONAL_ACCESS_TOKEN`, paste PAT

**For Organization Teams:**

* **Option A (Free):** Add to each repository's secrets
* **Option B (Paid):** Add to organization secrets (requires paid plan)
  {% endstep %}

{% step %}

### Setup VS Code

**Install pnpm: (Skip if already installed)**

```
npm install -g pnpm
```

**Install dependencies:**

```
pnpm install
```

{% endstep %}
{% endstepper %}

## How to Use DevKit™

### Building & Testing

#### Run a Local Development Server:

```
pnpm dev
```

#### Run a Local Production Server:

```
pnpm prod
```

### Pre-commit Hooks

#### Automatic Code Quality

Pre-commit hooks automatically format and lint your code before commits:

* **Prettier** formats JavaScript and CSS files in `src/`
* **ESLint** catches and auto-fixes errors
* **Commit blocked** if ESLint errors are found
* **Auto-setup** when running `pnpm install`

#### Troubleshooting

If commit is blocked:

1. Fix the linting errors shown in terminal
2. Stage fixes with `git add`
3. Commit again

### Importing Scripts

#### 1️⃣ Traditional Method:

* Operation: Run your local server using pnpm dev or pnpm prod.
* Script Logging: DevKit™ logs script tags for JavaScript and CSS files from the src folder.
* Integration: Manually copy and paste script tags to your Webflow pages or global settings, being mindful to switch between development and production tags as needed.

#### 2️⃣ Automated Method (Recommended):

#### Core DevKit™ Scripts (Global):

**`Main Settings`: Add in global `<head>` tag**

```
<!-- RD® Webflow DevKit™ / Main Settings -->
<script>
window.npmPath = "@reform-digital/sample-project@1.0.0"; // Update this once you have shipped to npm.
window.devMode = true; // Change to false in production
window.localPort = 3000; // Also change in bin/localport.js in VS Code
</script>
```

**`Style-Loader`: Add in global `<head>` tag**

```
<!-- RD® Webflow DevKit™ / Style Loader -->
<script src="https://cdn.jsdelivr.net/npm/@reform-digital/webflow-devkit-utils@1.2.1/prod/style-loader.js"></script>
```

**`Script-Loader`: Add before global `</body>` closing tag**

```
<!-- RD® Webflow DevKit™ / Script Loader -->
<script src="https://cdn.jsdelivr.net/npm/@reform-digital/webflow-devkit-utils@1.2.1/prod/script-loader.js"></script>
```

#### Project Code (Page level):

**Page `Scripts`: Add before page `</body>` closing tag**

```
<!-- RD® Webflow DevKit / Page Scripts -->
<script>
const pageScripts = ["home.js"];
loadWebflowScripts(pageScripts, npmPath);
</script>
```

**Page `Styles`: Add in page `<head>` tag**

```
<!-- RD® Webflow DevKit / Page Styles -->
<script>
const pageStyles = ["home.css"];
loadWebflowStylesheets(pageStyles, npmPath);
</script>
```

#### Project Code (Global):

**Global `Scripts`: Add before global `</body>` closing tag, under Script Loader.**

```
<!-- RD® Webflow DevKit / Global Scripts -->
<script>
const globalScripts = ["global.js", "analytics.js"];
loadWebflowScripts(globalScripts, npmPath);
</script>
```

**Global `Styles`: Add in global `<head>` tag, under Style Loader.**

```
<!-- RD® Webflow DevKit / Global Styles -->
<script>
const globalStyles = ["global.css", "animation.css"];
loadWebflowStylesheets(globalStyles, npmPath);
</script>
```

### Shipping to NPM

```
pnpm ship
```

If you are using the GitHub extension for VS Code, grant the necessary permissions if prompted.

#### Post-Shipment Steps:

**Automated:**

Update `npmPath` with your own path in the global `<head>`.

**Traditional:**

Replace local script tags located in global and page-specific `</body>` to:

```
<script src="https://cdn.jsdelivr.net/npm/@your-npm-username/your-package-name@version/your-filename.js"></script>
```

Replace local style tags in global and page-specific `<head>` to:

```
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@your-npm-username/your-package-name@version/your-filename.css">
```

### Addressing Caching

#### @latest Versioning

* Initial Release: @latest (or omitting @version) is ok for initial release.
* Subsequent Releases: @latest might lead to outdated content due to CDN and browser caching.

#### Cache Management

* CDN Cache: Manually purge via [jsDelivr’s Purge Tool](https://www.jsdelivr.com/tools/purge).
* Browser Cache: Educate users; no direct control, can only hard refresh or clear own browser cache.

#### Use Specific Versions to Prevent Caching Issues

* Automated Import: npm path `"@your-npm-username/your-package-name@version"`
* Traditional Import: src path `"https://cdn.jsdelivr.net/npm/@your-npm-username/your-package-name@version/your-filename.js"`

### Branches & Collab

#### Single Developer Workflow

* **Initial Development:** Work directly in main branch.
* **Creating a Dev Branch:** After initial release, create a dev branch.
* **Routine Development:** Work in dev, commit changes, push commits.
* **Merging and Releasing:** Merge dev into main, publish to npm.

#### Multi-Developer Collaboration Workflow

* **Setting Up Main and Dev Branches:** Ensure main and dev branches are set up.
* **Creating Feature Branches:** Developers create feature branches from dev.
* **Development, Commit, Push:** Work on feature, commit, and push.
* **Collaboration and Code Review:** Open pull requests, review code, merge into dev.
* **Syncing Changes:** Regularly fetch and merge changes from dev to avoid conflicts.
* **Adding Collaborators:** Project maintainers can add collaborators through GitHub settings.
* **Preparing for Release:** Merge dev into main, prepare for npm release.
* **Shipping to npm:** Switch to main, fetch latest, pull changes, publish to npm.

#### Conclusion

* Single developer workflow for smaller projects or initial phases.
* Multi-developer collaboration workflow for larger teams and complex projects.


# CookieFlow™

GDPR-compliant cookie consent, CMP & privacy solution for Webflow.

***

<a href="https://www.reform.digital/tools/cookieflow" class="button primary" data-icon="webflow">Copy to Webflow</a> <a href="https://www.reform.digital/tools/cookieflow" class="button secondary" data-icon="figma">Copy to Figma</a> <a href="https://www.reform.digital/tools/cookieflow" class="button secondary" data-icon="bolt">Copy to Supabase</a>

<figure><img src="https://3948747524-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FyWDd0BQVjmRUYm47Xnrj%2Fuploads%2F3h17Hj5ZAxhUMFE6oHmg%2FThumb.png?alt=media&#x26;token=a7d697e2-d4cc-4310-a224-5f49fa4f3654" alt=""><figcaption></figcaption></figure>

***

## Overview

CookieFlow™ is a comprehensive cookie consent management solution developed by [Reform Digital®](https://reform.digital) specifically for Webflow websites. It provides a compliant, customizable framework for handling user consent preferences across different geographical regions, automatically adapting to privacy regulations like GDPR, CCPA, and others.

**What CookieFlow™ Does**

* **Automatically detects user location** and displays the appropriate consent banner
* **Manages cookie consent** across multiple categories (marketing, analytics, personalization)
* **Complies with regional regulations** (GDPR, CCPA, etc.)
* **Stores consent records** in your Supabase database for audit trails
* **Integrates seamlessly** with Google Tag Manager and Webflow Analyze
* **Respects privacy signals** like Do Not Track (DNT) and Global Privacy Control (GPC)

***

### Features

#### 🔍 Automatic Geolocation

CookieFlow™ automatically detects your visitors' location using IP-based geolocation and displays the appropriate consent banner based on their region. If geolocation fails or returns invalid data, we default to ZONE\_3 (GDPR/strictest) to stay compliant.

**How It Works:**

1. CookieFlow™ checks the visitor's IP address
2. Determines their country code
3. Matches the country to the appropriate zone (ZONE\_1, ZONE\_2, or ZONE\_3)
4. Shows the correct banner for that region
5. Hides banners for other regions

**Privacy-Conscious:**

* IP addresses are anonymized before storage (last octet set to 0)
* Geolocation data is used only to determine compliance zone
* No personally identifiable information is collected during detection

**Cloudflare Worker response**

* The worker returns JSON (`{ country, ip }`) so the client can parse it reliably.
* IPs are masked in the worker itself (last octet zero) before the JSON payload is delivered.
* `supabaseClient.js` still runs an additional anonymization pass as a safety net.

#### 📍 Regional Compliance (3 Zones)

* **ZONE\_1 (Basic Notice)**: Simple notice-only approach for 130 countries with minimal compliance requirements
* **ZONE\_2 (Opt-Out/CCPA)**: For 6 CCPA-affected regions (US, PR, GU, AS, MP, VI) with "Do Not Sell" option
* **ZONE\_3 (Opt-In/GDPR)**: For 50 GDPR-affected regions (EU, UK, Canada, Brazil, Japan, etc.) with detailed consent options
* **Customizable**: Override defaults with script attributes if privacy regulations change

#### ⏰ Configurable Cookie Expiry

Set how long consent cookies should last (default is 6 months). Users can be prompted to renew their consent when it expires.

#### 📊 Consent Record Storage

GDPR and other privacy regulations require consent records to be stored and maintained for audit trails. CookieFlow™ is built to work seamlessly with Supabase due to its ease of setup and free tier availability. Once configured, all consent records are automatically stored in your Supabase database, providing a complete compliance audit trail without additional maintenance.

#### 🔒 Privacy Signal Respect

CookieFlow™ automatically respects and responds to:

* Do Not Track (DNT) browser signals
* Global Privacy Control (GPC) signals
* Automatically opts users out if these signals are detected

#### 🤖 Bot Detection

Crawlers and bots won't see consent banners, keeping your site's SEO intact.

#### 🔄 Consent ID Tracking

Tracks and displays a unique consent ID to users (GDPR requirement for EU visitors).

#### 🎨 Fully Customizable

Complete control over styling and layout using Webflow's native design tools.

***

### Compliance

✔ **Equal Prominence**: "Accept" and "Reject" buttons are identical in design.\
✔ **No Pre-Checked Boxes**: Users must actively opt in to non-essential cookies.\
✔ **Plain Language**: Simple, clear wording without legal jargon.\
✔ **No Implied Consent**: Actions like scrolling or navigating do not count as consent.\
✔ **No Cookie Walls**: Full access to the website is provided, even if cookies are rejected.\
✔ **Granular Control**: Users can opt in to different cookie categories.\
✔ **Close Button**: Clearly explains that no cookies will be set if closed.\
✔ **Privacy & Cookie Policy Link**: Easily accessible for transparency.\
✔ **Publisher Identification**: The website publisher's name is explicitly stated.\
✔ **Stored Consent Choices**: Users' selections are remembered for a minimum of 6 months (per France & Italy).\
✔ **Consent Expiry**: Re-consent required every 6–24 months, per country regulations.\
✔ **Easy Consent Review**: Users can modify settings anytime via a widget or link.\
✔ **Third-Party Cookies Disclosure**: Third-party providers are listed in the policy.\
✔ **Cross-Site Tracking Compliance**: Explicit opt-in required for tracking across sites.\
✔ **No Nudging**: Rejecting cookies is just as easy as accepting them.\
✔ **Dismissal Transparency (Italy)**: Users are informed that rejecting cookies will not affect access to content.

CookieFlow™ has been built with these regulations in mind, for full compliance implement it according to the documentation, do not change its functionality and only edit and style it considering the above rules.

### Considerations

While CookieFlow™ provides comprehensive cookie consent management, there are several Webflow-specific features that require additional attention to ensure full GDPR compliance:

#### Webflow E-Commerce is not GDPR compliant

Webflow's native e-commerce solution is not fully GDPR compliant by default, as it uses cookies that may track users without explicit consent. Since these cookies are managed directly by Webflow, our cookie consent solution, CookieFlow, cannot control or block them. If you are using Webflow e-commerce, we recommend consulting a legal expert and exploring additional compliance measures to ensure your store meets GDPR requirements.

#### Webflow's native video element for YouTube

YouTube videos do not comply with GDPR regulations by default. To ensure users have control over their data, it's best to use embedded iFrames. If you add YouTube videos to your Webflow site using the native video element, personal data is automatically shared with YouTube and its parent company, Google, as soon as the page loads. To avoid this, consider using a custom code embed instead.

#### Webflow's map is not GDPR compliant

Webflow's native map element does not comply with GDPR regulations, as it automatically shares personal data with third parties like Google without user consent. To prioritize user privacy and provide better control over data sharing, it's advisable to use an embedded Google Map instead.

#### Webflow's reCaptcha is not GDPR compliant

Webflow's built-in reCaptcha does not fully comply with GDPR, as it collects user data (such as IP addresses and behavior) without explicit consent. To maintain compliance and safeguard user privacy, it's best to integrate reCaptcha manually into your forms.

#### Remove `<noscript>` tags for compliance

`<noscript>` tags are not compliant with cookie consent regulations and should be removed. These tags execute even when JavaScript is disabled, which can bypass cookie consent mechanisms and potentially collect user data without proper authorization. To ensure GDPR compliance, it is essential to eliminate all `<noscript>` tags from your website.

***

### Support

#### Getting Help

Need assistance with CookieFlow™? Try these steps:

1. **Review the documentation** - Most common issues are covered in this guide
2. **Check the browser console** - Look for error messages that may indicate configuration issues
3. **Verify your configuration** - Ensure all attributes are spelled correctly and properly formatted
4. **Validate Supabase credentials** - Confirm your Supabase URL and API key are correct and have proper permissions
5. **Still stuck?** - Join our [Slack community](https://join.slack.com/t/rdcommunity/shared_invite/zt-2zser6sir-3CnFYB6gP4lvQsV2rY3wGw) for direct support from our team

#### Feature Requests & Bugs

CookieFlow™ is actively maintained and continuously improved. We welcome your feedback:

* **Feature requests** - Share ideas to make CookieFlow™ even better
* **Bug reports** - Help us identify and fix issues
* **General feedback** - Tell us about your experience

Join our [Slack community](https://join.slack.com/t/rdcommunity/shared_invite/zt-2zser6sir-3CnFYB6gP4lvQsV2rY3wGw) to contribute!

***

## Recommended Setup

### Quick Start

We provide a ready-to-use Webflow component that includes all necessary elements, attributes, and scripts out of the box. Simply copy the component from our website and paste it into your Webflow project. You can also copy the original Figma design so you can style CookieFlow as needed.

<a href="https://www.reform.digital/tools/cookieflow" class="button primary" data-icon="webflow">Copy to Webflow</a> <a href="https://www.reform.digital/tools/cookieflow" class="button secondary" data-icon="figma">Copy to Figma</a>

#### What's Included

The prebuilt component comes with:

* **All required HTML elements** with proper attributes
* **The CookieFlow™ script** already integrated
* **Three banner variations** (for different compliance zones)
* **Settings/preferences modal** with consent toggles
* **Manager button** for reopening the consent interface
* **GDPR consent info banner**

#### Important: Script Configuration

The prebuilt component includes the CookieFlow™ script already. You just need to:

1. Copy the component from our demo site
2. Paste it into your Webflow project
3. Update the script attributes in the component with your Supabase credentials (see the Supabase Setup section below)
4. Customize the styling to match your brand

***

### Supabase Setup

CookieFlow™ requires a Supabase database to store consent records for compliance and audit purposes. If you don't already have a Supabase account and database set up:

1. **Sign up at** [**https://supabase.com**](https://supabase.com)
2. **Create a new project** (wait for provisioning to complete)
3. **Open the SQL Editor** in your Supabase dashboard
4. **Paste & run the following SQL code** to create the necessary tables and security policies:

```sql
/* ============================================================
   1️⃣  CREATE TABLES
   ============================================================ */

-- Create the main consents table (idempotent)
create table if not exists public.consents (
  id              serial primary key,
  consent_id      text       not null,
  anonymized_ip   text,
  action_date     timestamptz default now(),
  page_url        text       not null,
  user_agent      text,
  consent_method  text,
  modal_text      text,
  button_clicked  text,
  consents        jsonb      not null,
  geo_region      text
);

/* ============================================================
   2️⃣  ROW-LEVEL SECURITY (RLS)
   ============================================================ */

-- Enable RLS on the consents table
alter table public.consents enable row level security;

-- Allow anonymous INSERTs only (no SELECT/UPDATE/DELETE)
do
$$
begin
  if not exists (
    select 1
    from pg_policies
    where schemaname = 'public'
      and tablename  = 'consents'
      and policyname = 'Allow public inserts'
  ) then
    create policy "Allow public inserts"
      on public.consents
      for insert
      with check (true);
  end if;
end
$$;

/* ============================================================
   3️⃣  QUERY HELPER FUNCTION
   ============================================================ */

-- Use a wrapper so clients can only read whitelisted columns
create or replace function public.get_consent_by_id (p_consent_id text)
returns table (
  consent_id  text,
  action_date timestamptz,
  consents    jsonb
)
language sql
stable
security definer
set search_path = public
as
$$
  select consent_id, action_date, consents
  from   public.consents
  where  consent_id = p_consent_id
  order  by action_date desc
  limit  1;
$$;

-- Revoke direct table SELECT, grant function EXECUTE
revoke select on public.consents from public;
grant  execute on function public.get_consent_by_id(text) to public;

/* ============================================================
   4️⃣  HEARTBEAT FUNCTION (keep-alive for Supabase Free plan)
   ============================================================ */

create or replace function public.heartbeat ()
returns void
language sql
stable
set search_path = public
as
$$
  select 1;
$$;

-- Grant execution to the anonymous role so an external cron
-- can ping /rest/v1/rpc/heartbeat using only the anon key
grant execute on function public.heartbeat() to anon;

/* Optional: Lock down visibility of heartbeat to everyone else */
revoke all on function public.heartbeat() from public;
```

5. **Copy your Supabase URL and API Key** from your Supabase dashboard:
   * **Project URL**: Found in **Settings → Data API** tab (e.g., `https://xxxxxxxxxxxxx.supabase.co`)
   * **anon key**: Found in **Settings → API Keys** tab (copy the `anon` `public` key)

***

### Script Configuration

The prebuilt component includes an embed element called "Component Scripts" with the required CookieFlow™ script already configured. To get started with the default configuration, simply update the script's attributes with your Supabase credentials (see Supabase Setup above).

#### Basic Configuration

The script requires these two essential attributes to function:

```html
<script 
  src="https://cdn.jsdelivr.net/npm/@reform-digital/cookie-flow@2.3.1/prod/index.js"
  rd-consent-storage-url="https://your-project.supabase.co"
  rd-consent-storage-api="your-api-key-here"
></script>
```

#### Advanced Configuration (Optional)

Beyond the basic setup, CookieFlow™ supports additional customizations to meet your specific compliance needs and preferences.

**Cookie Expiration Configuration**

**Default Behavior**: By default, the consent cookie expires after **6 months**. This setting works well for most countries and aligns with common GDPR requirements.

**How It Works**: CookieFlow™ stores a consent cookie called `rd-cf-consent` that remembers the user's choices. The expiration of this cookie is controlled by the `rd-consent-expiry` attribute in your script tag.

**Setting a Custom Expiration**: If you need to set a different expiration period based on your specific country's GDPR regulations, you can override the default by adding the `rd-consent-expiry` attribute to your script tag along with a value in **months**. For example, if your country states that consents should expire after 3 months instead of six, then you would update the attribute as follows:

```html
<script 
  src="https://cdn.jsdelivr.net/npm/@reform-digital/cookie-flow@2.3.1/prod/index.js"
  rd-consent-storage-url="https://your-project.supabase.co"
  rd-consent-storage-api="your-api-key-here"
  rd-consent-expiry="3"
></script>
```

**What Happens on Expiry**: When the consent cookie expires:

1. User returns to your site
2. CookieFlow™ detects the expired cookie
3. The appropriate consent banner is shown again
4. User can reconfirm or change their preferences

**Displaying Expiry Date to Users (Optional)**: To inform users when their consent expires, add the `rd-consent-expiry` attribute to any text element (except script tags):

```html
<!-- Will display "6" (based on your configuration) -->
<p><span rd-consent-expiry></span> months</p>
```

CookieFlow™ will automatically set the text content of the element to the expiry period number from your script configuration.

**Regional Compliance Overview**

CookieFlow™ automatically adapts to your visitors' location, showing the appropriate compliance interface. The system uses three compliance zones:

**ZONE\_1: Basic Notice (Default)**

**Countries**: Most countries worldwide\
**Behavior**: Simple notice informing users about cookie usage\
**User Actions**: Accept or dismiss the notice\
**Use Case**: Minimal compliance requirements

**Default Country Assignment** (130 countries): AF, AX, AL, DZ, AD, AO, AI, AQ, AG, AM, AW, AU, AZ, BS, BD, BB, BY, BZ, BJ, BM, BT, BO, BQ, BA, BW, BV, IO, BN, BF, BI, CV, KH, CM, KY, CF, TD, CL, CN, CX, CC, CO, KM, CG, CD, CK, CR, CI, CU, CW, DJ, DM, DO, EC, EG, SV, GQ, ER, SZ, ET, FK, FO, FJ, GF, PF, TF, GA, GM, GE, GH, GI, GL, GD, GP, GT, GG, GN, GW, GY, HT, HM, VA, HN, HK, IN, ID, IR, IQ, IM, JM, JE, JO, KZ, KI, KP, KW, KG, LA, LB, LS, LR, LY, MO, MG, MW, MY, MV, ML, MH, MQ, MR, YT, MX, FM, MD, MC, MN, ME, MS, MA, MZ, MM, NA, NR, NP, NC, NI, NE, NU, NF, MK, OM, PK, PW, PS, PA, PG, PY, PE, PH, PN, RE, RU, RW, BL, SH, KN, LC, MF, PM, VC, WS, SM, ST, SA, SN, RS, SC, SL, SG, SX, SB, SO, GS, SS, LK, SD, SR, SJ, SY, TW, TJ, TZ, TH, TL, TG, TK, TO, TT, TN, TM, TC, TV, UZ, UA, AE, VU, VE, VN, VG, WF, UM, EH, YE, ZM, ZW

**ZONE\_2: Opt-Out (CCPA)**

**Countries**: United States and other CCPA-affected regions\
**Behavior**: Users must opt-out if they don't want their data sold\
**User Actions**:

* Accept All
* Reject All (opt-out)
* Manage Preferences (opens settings) **Use Case**: California Consumer Privacy Act (CCPA) compliance

**Default Country Assignment** (6 countries): AS, GU, MP, PR, US, VI

**Special Features**:

* "Do Not Sell My Personal Information" option

**ZONE\_3: Opt-In (GDPR)**

**Countries**: European Union and other GDPR-affected regions\
**Behavior**: Granular consent required for each cookie category\
**User Actions**:

* Accept All
* Reject All
* Accept Selected (only enable desired categories)
* Open detailed preferences **Use Case**: General Data Protection Regulation (GDPR) compliance

**Default Country Assignment** (50 countries): AR, AT, BH, BE, BR, BG, CA, HR, CY, CZ, DK, EE, FI, FR, DE, GR, HU, IS, IE, IL, IT, JP, KE, KR, LV, LI, LT, LU, MT, MU, NL, NZ, NG, NO, PL, PT, QA, RO, SK, SI, ZA, ES, SE, CH, TR, UG, GB, UY

**Special Features**:

* Detailed cookie category descriptions
* Consent ID display for audit trails
* Granular consent management

**Automatic Detection**

CookieFlow™ uses IP-based geolocation via a Cloudflare Worker that leverages Cloudflare's built-in geolocation data. This approach is GDPR-compliant as no third-party services receive user IP addresses.

1. **Primary**: IP-based geolocation (via Cloudflare Worker using `request.cf.country`)
2. **Fallback**: Defaults to ZONE\_3 (GDPR/strictest) if geolocation fails

You can configure your Cloudflare Worker URL via the `rd-geo-worker-url` script attribute, or it will use the default worker URL.

**Regional Configuration Override**

By default, CookieFlow™ uses predefined country assignments based on current privacy regulations (see the Regional Compliance Overview above). However, you can override these defaults if:

1. A country's privacy regulations change
2. You need to customize the regional assignments for your specific use case
3. You want to test different compliance zones

To customize country assignments, add these attributes to your script tag:

```html
<script 
  src="https://cdn.jsdelivr.net/npm/@reform-digital/cookie-flow@2.3.1/prod/index.js"
  rd-consent-storage-url="https://your-project.supabase.co"
  rd-consent-storage-api="your-api-key-here"
  rd-zone-1="US,CA,MX"
  rd-zone-2="UK,AU,BR"
  rd-zone-3="DE,FR,IT,ES"
></script>
```

**How to Override**: Simply provide a comma-separated list of 2-letter ISO country codes to reassign any country to a different zone.

**Example**: If Canada moves from ZONE\_3 to ZONE\_2 due to a regulation change:

```html
<script 
  ...
  rd-zone-2="CA"
></script>
```

**Configuration Attribute Reference**

**`rd-consent-storage-url` (Required)**

* Your Supabase project URL
* Format: `https://xxxxxxxxxxxxx.supabase.co`
* Found in: Settings → Data API

**`rd-consent-storage-api` (Required)**

* Your Supabase anonymous/public API key
* Format: Long string of characters
* Found in: Settings → API Keys (use the `anon` `public` key)

**`rd-consent-expiry` (Optional)**

* Cookie expiration duration in months
* Default: `6` (6 months)
* Can be any number (e.g., `3`, `12`, `24`)

**`rd-zone-1`, `rd-zone-2`, `rd-zone-3` (Optional)**

* Comma-separated list of country codes (2-letter ISO format)
* Used to override default regional assignments

**`rd-geo-worker-url` (Optional)**

* Your Cloudflare Worker URL for geolocation
* Format: `https://your-worker.your-subdomain.workers.dev`
* Default: Uses a default worker URL if not specified
* The worker should return a 2-letter country code and accept the `x-cookieflow: 1` header
* Format: `"US,CA,MX"`

***

### Store Consents

CookieFlow™ automatically stores comprehensive consent records in your Supabase database for compliance and audit purposes. Each time a user interacts with the consent banner, a detailed record is created that includes both technical metadata and the user's specific consent choices.

#### What Information is Stored

Every consent record contains the following information:

**Consent Identification**

* **`consent_id`**: Unique identifier generated from timestamp and anonymized IP (28-character base36 string)
* **`action_date`**: Precise timestamp when consent was given (automatically set by database)

**User Consent Choices**

* **`consents`**: JSON object containing the user's specific consent decisions:

  ```json
  {
    "marketing": true/false,
    "analytics": true/false, 
    "personalization": true/false,
    "essential": true
  }
  ```

**Technical Metadata**

* **`anonymized_ip`**: User's IP address with the last octet set to "0" for privacy
* **`user_agent`**: Browser and device information for technical support
* **`page_url`**: The website domain where consent was given
* **`geo_region`**: User's compliance zone (ZONE\_1, ZONE\_2, or ZONE\_3)

**User Interaction Details**

* **`consent_method`**: How consent was given ("accept\_all", "reject\_all", "accept\_selected")
* **`button_clicked`**: Text content of the specific button the user clicked
* **`modal_text`**: The full text content of the consent banner/modal

#### Consent Record Examples

**Example 1: Accept All (GDPR Region)**

```json
{
  "consent_id": "A1B2C3D4E5F6G7H8I9J0K1L2M3N4",
  "action_date": "2024-01-15T14:30:25.123Z",
  "anonymized_ip": "192.168.1.0",
  "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
  "page_url": "https://example.com",
  "consent_method": "accept_all",
  "button_clicked": "Accept All",
  "modal_text": "We use cookies to enhance your experience...",
  "geo_region": "ZONE_3",
  "consents": {
    "marketing": true,
    "analytics": true,
    "personalization": true,
    "essential": true
  }
}
```

**Example 2: Selective Consent (GDPR Region)**

```json
{
  "consent_id": "B2C3D4E5F6G7H8I9J0K1L2M3N4O5",
  "action_date": "2024-01-15T14:35:10.456Z",
  "anonymized_ip": "203.45.67.0",
  "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
  "page_url": "https://example.com",
  "consent_method": "accept_selected",
  "button_clicked": "Save Preferences",
  "modal_text": "We use cookies to enhance your experience...",
  "geo_region": "ZONE_3",
  "consents": {
    "marketing": false,
    "analytics": true,
    "personalization": false,
    "essential": true
  }
}
```

**Example 3: Reject All (CCPA Region)**

```json
{
  "consent_id": "C3D4E5F6G7H8I9J0K1L2M3N4O5P6",
  "action_date": "2024-01-15T14:40:15.789Z",
  "anonymized_ip": "198.51.100.0",
  "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15",
  "page_url": "https://example.com",
  "consent_method": "reject_all",
  "button_clicked": "Reject All",
  "modal_text": "We use cookies to enhance your experience...",
  "geo_region": "ZONE_2",
  "consents": {
    "marketing": false,
    "analytics": false,
    "personalization": false,
    "essential": true
  }
}
```

#### Privacy & Security Features

**IP Anonymization**

* All IP addresses are automatically anonymized by setting the last octet to "0"
* Example: `192.168.1.123` becomes `192.168.1.0`
* This provides location data while protecting user privacy

**Unique Consent IDs**

* Each consent record gets a unique 28-character identifier
* Generated using SHA-256 hash of timestamp + anonymized IP
* Enables tracking consent changes over time while maintaining privacy

**Database Security**

* Row-level security (RLS) enabled on all tables
* Anonymous users can only INSERT records (no SELECT/UPDATE/DELETE)
* Consent retrieval requires specific function calls with proper permissions

#### Compliance Benefits

**Audit Trail**

* Complete record of all consent decisions
* Timestamped entries for regulatory compliance
* Detailed interaction metadata for transparency

**Data Subject Rights**

* Users can request their consent records using their consent ID
* Records can be exported for data portability requests
* Clear consent withdrawal tracking

**Regulatory Reporting**

* Structured data format for compliance reporting
* Geographic region tracking for multi-jurisdictional compliance
* Detailed consent method tracking for audit purposes

#### Accessing Consent Records

**For Users (ZONE\_3/GDPR)**

Users in GDPR regions can view their consent ID and timestamp directly in the consent banner after making a choice.

**For Administrators**

Use the Supabase dashboard to query consent records. You can run any of these queries as needed:

```sql
-- Get all consent records for a specific date range
SELECT * FROM consents 
WHERE action_date >= '2024-01-01' 
AND action_date < '2024-02-01';
```

```sql
-- Get consent records by region
SELECT * FROM consents 
WHERE geo_region = 'ZONE_3';
```

```sql
-- Get specific user's consent history
SELECT * FROM consents 
WHERE consent_id = 'USER_CONSENT_ID';
```

```sql
-- Get latest consent for a specific user
SELECT * FROM get_consent_by_id('USER_CONSENT_ID');
```

***

### Consent Categories

CookieFlow™ manages consent across four main categories:

#### 1. Marketing Cookies

**Purpose**: Used for advertising and tracking across websites\
**Includes**: Social media pixels, retargeting pixels, advertising cookies\
**Control**: Users can enable or disable this category

#### 2. Analytics Cookies

**Purpose**: Used to understand how visitors interact with your site\
**Includes**: Google Analytics, Webflow Analyze, heatmap tools\
**Control**: Users can enable or disable this category

#### 3. Personalization Cookies

**Purpose**: Used to remember user preferences and personalize experience\
**Includes**: Language preferences, theme preferences, saved settings\
**Control**: Users can enable or disable this category

#### 4. Essential Cookies (Always On)

**Purpose**: Necessary for website functionality\
**Includes**: Authentication, security, site functionality\
**Control**: Cannot be disabled—required for site to function

***

### Adding Project Scripts

Once CookieFlow™ is set up, you need to configure your existing scripts to respect user consent preferences. CookieFlow™ provides two methods for script integration:

#### Method 1: Adding Scripts Directly in Webflow

This method is ideal if you manage scripts directly within your Webflow project using embed elements or custom code.

**How It Works**

CookieFlow™ uses HTML attributes to control when scripts load based on user consent. Add the appropriate attributes to all your project scripts:

**Important: Remove `<noscript>` Tags for Compliance**

**Remove `<noscript>` tags for compliance**: When adding any tracking scripts directly in Webflow, ensure that no `<noscript>` tags are included. If any of your existing scripts contain `<noscript>` tags, remove them as they will bypass consent management and violate compliance requirements.

**Example of what NOT to add** (Google Tag Manager `<noscript>` tag):

```html
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->
```

This `<noscript>` tag loads tracking scripts even when JavaScript is disabled, completely bypassing consent management and violating privacy regulations.

**Essential Scripts**

**Attribute**: `type="disabled" rd-cookieflow="essential"`\
**Use for**: Authentication, security, payment processing, accessibility scripts, form validation, load balancing, privacy & consent management

```html
<!-- Stripe JS Library -->
<script type="disabled" rd-cookieflow="essential" src="https://js.stripe.com/v3/"></script>

<!-- Authentication Script -->
<script type="disabled" rd-cookieflow="essential">
  // Your authentication code here
</script>
```

**Analytics Scripts**

**Attribute**: `type="disabled" rd-cookieflow="analytics"`\
**Use for**: Google Analytics, Hotjar, tracking and recording scripts, heatmaps, Microsoft Clarity, Adobe Analytics

```html
<!-- Google Analytics 4 -->
<script type="disabled" rd-cookieflow="analytics" async src="https://www.googletagmanager.com/gtag/js?id=YOURGA4ID"></script>
<script type="disabled" rd-cookieflow="analytics">
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'YOURGA4ID');
</script>

<!-- Hotjar -->
<script type="disabled" rd-cookieflow="analytics">
  (function(h,o,t,j,a,r){
    h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
    h._hjSettings={hjid:YOUR_HOTJAR_ID,hjsv:6};
    a=o.getElementsByTagName('head')[0];
    r=o.createElement('script');r.async=1;
    r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
    a.appendChild(r);
  })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');
</script>
```

**Marketing Scripts**

**Attribute**: `type="disabled" rd-cookieflow="marketing"`\
**Use for**: Tracking pixels, advertising tags, social media integration scripts, retargeting cookies, affiliate tracking, marketing automation

```html
<!-- Meta Pixel Code -->
<script type="disabled" rd-cookieflow="marketing">
!function(f,b,e,v,n,t,s)
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t,s)}(window, document,'script',
'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', 'YOUR_PIXEL_ID');
fbq('track', 'PageView');
</script>

<!-- Google Ads Conversion Tracking -->
<script type="disabled" rd-cookieflow="marketing">
  gtag('event', 'conversion', {
    'send_to': 'AW-CONVERSION_ID/CONVERSION_LABEL',
    'value': 1.0,
    'currency': 'USD'
  });
</script>
```

**Personalization Scripts**

**Attribute**: `type="disabled" rd-cookieflow="personalization"`\
**Use for**: Language preferences, theme or appearance, recommendations, user profile customization, behavioral segmentation, geo-targeting

```html
<!-- Language Preference Script -->
<script type="disabled" rd-cookieflow="personalization">
  function setLanguagePreference(lang) {
    localStorage.setItem('preferred-language', lang);
    document.documentElement.lang = lang;
  }
</script>

<!-- Theme Customization Script -->
<script type="disabled" rd-cookieflow="personalization">
  function applyUserTheme(theme) {
    document.body.className = theme;
    localStorage.setItem('user-theme', theme);
  }
</script>
```

**Important Notes for Webflow Integration**

1. **Add attributes to embed elements**: In Webflow, when adding scripts via embed elements, include the attributes in the opening `<script>` tag
2. **Scripts load automatically**: Once users give consent, CookieFlow™ automatically enables the appropriate scripts
3. **Essential scripts always load**: Scripts with `rd-cookieflow="essential"` load immediately without requiring consent

***

#### Method 2: Adding Scripts via Google Tag Manager

This method is recommended if you use Google Tag Manager to manage your website scripts and tracking.

**Prerequisites**

**Remove `<noscript>` tags for compliance**: When installing Google Tag Manager, do not add the `<noscript>` tag after the opening `<body>` tag. If you already have Google Tag Manager installed, remove that part from Webflow.

**Step 1: Set Up Triggers in Google Tag Manager**

Go to **Workspace → Triggers** and click **New** to create triggers for each consent category:

**Essential Cookie Trigger**

* **Name**: `Essential Cookie Activated`
* **Type**: Other → Custom Event
* **Event Name**: `essential-activated`
* **Fires On**: Some Custom Events
* **Condition**: Event equals `essential-activated`

**Analytics Cookie Trigger**

* **Name**: `Analytics Cookie Activated`
* **Type**: Other → Custom Event
* **Event Name**: `analytics-activated`
* **Fires On**: Some Custom Events
* **Condition**: Event equals `analytics-activated`

**Marketing Cookie Trigger**

* **Name**: `Marketing Cookie Activated`
* **Type**: Other → Custom Event
* **Event Name**: `marketing-activated`
* **Fires On**: Some Custom Events
* **Condition**: Event equals `marketing-activated`

**Personalization Cookie Trigger**

* **Name**: `Personalization Cookie Activated`
* **Type**: Other → Custom Event
* **Event Name**: `personalization-activated`
* **Fires On**: Some Custom Events
* **Condition**: Event equals `personalization-activated`

**Step 2: Configure Your Tags**

For each existing or new tag in Google Tag Manager:

**Essential Scripts**

* **Trigger**: Essential Cookie Activated
* **Use for**: Authentication, security, payment processing, accessibility scripts, form validation, load balancing, privacy & consent management

**Analytics Scripts**

* **Trigger**: Analytics Cookie Activated
* **Use for**: Google Analytics, Hotjar, tracking and recording scripts, heatmaps, Microsoft Clarity, Adobe Analytics

**Marketing Scripts**

* **Trigger**: Marketing Cookie Activated
* **Use for**: Tracking pixels, advertising tags, social media integration scripts, retargeting cookies, affiliate tracking, marketing automation

**Personalization Scripts**

* **Trigger**: Personalization Cookie Activated
* **Use for**: Language preferences, theme or appearance, recommendations, user profile customization, behavioral segmentation, geo-targeting

**Step 3: Add Advanced Consent Settings**

For each tag, go to **Tag Configuration → Advanced Settings → Consent Settings** and select **Require additional consent for tag to fire**:

**Essential Scripts**

* **Required Consent**: `security_storage`

**Analytics Scripts**

* **Required Consent**: `analytics_storage`

**Marketing Scripts**

* **Required Consent**: `ad_storage`

**Personalization Scripts**

* **Required Consent**: `personalization_storage` and `functionality_storage`

**Step 4: Publish & Test**

1. **Publish**: Click **Submit**, name your version, and hit **Publish**
2. **Test**: Click **Preview**, enter your website URL to initiate test mode
3. **Verify**: By default, you should only see essential tags firing without further consent
4. **Test Consent**: Toggle different cookie types on your previewed website to verify their respective tags fire correctly

**Troubleshooting GTM Integration**

* **Tags not firing**: Check that triggers are properly configured and attached to tags
* **Consent not working**: Verify that advanced consent settings are properly configured
* **Essential scripts not loading**: Ensure essential tags have the correct trigger and consent settings

***

## Manual Setup

### Setup Guide

If you prefer to build your own UI or need to customize the implementation beyond the prebuilt component, you can manually set up CookieFlow™ by adding the required HTML elements and attributes to your Webflow project.

#### Quick Start

1. Add the CookieFlow™ script to your Webflow project
2. Create the required HTML elements in your Webflow project
3. Add the necessary attributes to each element
4. Customize the styling to match your brand

***

### Adding the Script

Add the following script to your Webflow project's **global settings**, inside the `<head>` tag:

```html
<script defer
  src="https://cdn.jsdelivr.net/npm/@reform-digital/cookie-flow@2.3.1/prod/index.js"
  rd-consent-storage-url="YOUR_SUPABASE_URL"
  rd-consent-storage-api="YOUR_SUPABASE_API_KEY"
></script>
```

#### What's Next?

* **Configure your Supabase database**: Follow the Supabase Setup guide in Option 1
* **Learn about script attributes**: See the Script Configuration section for all available attributes and customization options
* **Understand regional compliance**: Check the Regional Compliance Overview section to learn how CookieFlow™ adapts to different regions

***

### Elements & Attributes

CookieFlow™ uses **HTML data attributes** to identify and control UI elements. These attributes start with `rd-cookieflow` (Reform Digital CookieFlow).

#### Core Components

**1. Wrapper Element**

**Purpose**: Contains all CookieFlow™ components\
**Attribute**: `rd-cookieflow="wrapper"`

```html
<div rd-cookieflow="wrapper">
  <!-- All other components go inside here -->
</div>
```

**2. Manager Component**

**Purpose**: Small button/floating element that allows users to reopen the consent interface\
**Attribute**: `rd-cookieflow="manager"`\
**Additional**: Add `rd-cookieflow="manager-interaction"` to control show/hide state

**Position**: Typically positioned as a floating button, often in the bottom-right corner

**Privacy Settings Link (Alternative to Manager)**

If you prefer to use a text link instead of the floating manager button (e.g., a "Privacy Settings" link in your footer), you can add this attribute to any element:

**Attribute**: `rd-cookieflow="manager-link"`

```html
<!-- Example: Footer privacy link -->
<a href="#" rd-cookieflow="manager-link">Privacy Settings</a>
```

**How It Works:**

* Clicking this element opens the CookieFlow™ settings modal, just like the floating manager button
* You can place this link anywhere on your page (footer, navigation, etc.)
* If using this approach, the floating manager button (`rd-cookieflow="manager"`) can be removed without affecting functionality

**3. Banner Components**

**Purpose**: Display consent options to users when they first visit

There are **three banner types**, one for each compliance zone:

* **Banner Zone 1** (Basic Notice): `rd-cookieflow="banner-zone-one"`
* **Banner Zone 2** (Opt-Out/CCPA): `rd-cookieflow="banner-zone-two"`
* **Banner Zone 3** (Opt-In/GDPR): `rd-cookieflow="banner-zone-three"`

**Important**: All three banners are hidden by default. CookieFlow™ will automatically remove the banners that don't apply to the user's location.

**Additional**: Add `rd-cookieflow="banner-interaction"` to control show/hide state

**4. Settings/Preferences Component**

**Purpose**: Detailed consent management modal where users can customize their preferences\
**Attribute**: `rd-cookieflow="settings"`\
**Additional**: Add `rd-cookieflow="preferences-interaction"` to control show/hide state

**Components Inside Settings**:

* Header text
* Consent category toggles
* Action buttons (Accept All, Reject All, Accept Selected)
* Close button

**5. Consent Info Banner (GDPR Only)**

**Purpose**: Displays consent ID and information about cookies for GDPR users\
**Attribute**: `rd-cookieflow="consent-banner"`\
**Additional**: Add `rd-cookieflow="consent-interaction"` to control show/hide state

#### Essential UI Elements Within Components

**Consent Buttons**

All consent-related buttons need these attributes:

* **Accept All**: `rd-cookieflow="accept"`
* **Reject All**: `rd-cookieflow="reject"`
* **Custom/Selected**: `rd-cookieflow="accept-selected"`
* **Open Settings**: `rd-cookieflow="open-settings"`
* **Close**: `rd-cookieflow="close"`

**Consent Checkboxes**

For the settings/preferences modal, add checkboxes for each consent category:

* **Marketing Cookies**:
  * Checkbox: `rd-cookieflow="marketing-checkbox"`
  * Toggle interaction: `rd-cookieflow="toggle-interaction"` (inside the checkbox container)
  * State display: `rd-cookieflow="marketing-state"` (to show On/Off text)
* **Analytics Cookies**:
  * Checkbox: `rd-cookieflow="analytics-checkbox"`
  * Toggle interaction: `rd-cookieflow="toggle-interaction"` (inside the checkbox container)
  * State display: `rd-cookieflow="analytics-state"` (to show On/Off text)
* **Personalization Cookies**:
  * Checkbox: `rd-cookieflow="personalization-checkbox"`
  * Toggle interaction: `rd-cookieflow="toggle-interaction"` (inside the checkbox container)
  * State display: `rd-cookieflow="personalization-state"` (to show On/Off text)

**Scroll Lock Attribute**

To prevent page scrolling when the settings modal is open, add this attribute to the settings component container:

```html
<div rd-cookieflow-scroll="disabled">
  <!-- Settings modal content -->
</div>
```

#### Example Structure

Here's an example of a complete CookieFlow™ structure:

```html
<div rd-cookieflow="wrapper" style="display: none;">
  
  <!-- Manager Button (always visible) -->
  <div rd-cookieflow="manager">
    <button rd-cookieflow="open-settings">Cookie Settings</button>
  </div>

  <!-- Zone 1 Banner (Basic Notice) -->
  <div rd-cookieflow="banner-zone-one">
    <p>We use cookies to enhance your experience...</p>
    <button rd-cookieflow="accept">Accept</button>
  </div>

  <!-- Zone 2 Banner (Opt-Out/CCPA) -->
  <div rd-cookieflow="banner-zone-two">
    <p>We use cookies to enhance your experience...</p>
    <button rd-cookieflow="accept">Accept All</button>
    <button rd-cookieflow="reject">Reject All</button>
    <button rd-cookieflow="open-settings">Manage Preferences</button>
  </div>

  <!-- Zone 3 Banner (Opt-In/GDPR) -->
  <div rd-cookieflow="banner-zone-three">
    <p>We use cookies to enhance your experience. Choose your preferences...</p>
    <button rd-cookieflow="accept">Accept All</button>
    <button rd-cookieflow="reject">Reject All</button>
    <button rd-cookieflow="accept-selected">Accept Selected</button>
    <button rd-cookieflow="open-settings">Customize</button>
  </div>

  <!-- Settings/Preferences Modal -->
  <div rd-cookieflow="settings" rd-cookieflow-scroll="disabled">
    <h2>Cookie Preferences</h2>
    
    <!-- Marketing Toggle -->
    <div>
      <input type="checkbox" rd-cookieflow="marketing-checkbox">
      <button rd-cookieflow="toggle-interaction"></button>
      <span rd-cookieflow="marketing-state">Off</span>
    </div>

    <!-- Analytics Toggle -->
    <div>
      <input type="checkbox" rd-cookieflow="analytics-checkbox">
      <button rd-cookieflow="toggle-interaction"></button>
      <span rd-cookieflow="analytics-state">Off</span>
    </div>

    <!-- Personalization Toggle -->
    <div>
      <input type="checkbox" rd-cookieflow="personalization-checkbox">
      <button rd-cookieflow="toggle-interaction"></button>
      <span rd-cookieflow="personalization-state">Off</span>
    </div>

    <button rd-cookieflow="accept">Accept All</button>
    <button rd-cookieflow="reject">Reject All</button>
    <button rd-cookieflow="accept-selected">Accept Selected</button>
    <button rd-cookieflow="close">Close</button>
  </div>

  <!-- GDPR Consent Info Banner -->
  <div rd-cookieflow="consent-banner">
    <p>Your Consent ID: [will be populated automatically]</p>
    <button rd-cookieflow="open-settings">Manage Cookies</button>
    <button rd-cookieflow="close">Close</button>
  </div>

</div>
```

***

## Product Tracking

CookieFlow™ includes an extremely lightweight telemetry module that helps us understand product adoption patterns. This information allows us to focus our support efforts and prioritize product enhancements where they matter most.

**What We Track:**

* **Product Identifier**: The name of the product (e.g., "COOKIE\_FLOW")
* **Domain**: The public hostname where the product is installed (e.g., "example.com")

**Privacy & Performance:**

* No cookies, fingerprinting, or personally identifiable information
* Only runs on live, public domains (never on localhost or development environments)
* Single lightweight request sent once per page load
* Data is aggregated for internal analytics only
* Not used for advertising, marketing, or tracking

This anonymous usage data helps us ensure CookieFlow™ evolves to meet real-world needs.

***


# ScriptEmbed™

Dynamic component script loader for Webflow.

***

## Overview

ScriptEmbed™ lets you load custom component scripts on your Webflow page by adding a single embed. It reads the component URL and name from the script tag's attributes, then adds the component script to the page — but only if it hasn't already been loaded. This helps avoid loading the same script multiple times when using the same component more than once.

### Features

* **Prevents duplicate loading** — Automatically checks if a component has already been loaded
* **Simple setup** — Add a single script embed to your Webflow project
* **Flexible loading** — Supports both external script URLs and inline template content
* **Zero dependencies** — Lightweight and fast-loading
* **Webflow-friendly** — Works seamlessly with Webflow's embed system

***

## Quick Start

### Option A: Self-Contained Embeds (Recommended for Webflow)

Each embed includes everything it needs — just copy/paste wherever you need a component:

```html
<script 
  src="https://cdn.jsdelivr.net/npm/@reform-digital/script-embed@1.1.0/prod/index.js"
  rd-component-name="my-component"
  rd-component-src="https://example.com/path/to/component.js"
  defer
></script>
```

This is ideal when:

* You don't have access to global settings
* You want portable, self-contained embeds
* You're embedding components in a CMS or page builder

> **Note:** It's safe to include this on multiple components — the loader only runs once.

***

### Option B: Global Script + Lightweight Embeds

Add the loader once in your **global settings** (`<head>` tag):

```html
<script 
  src="https://cdn.jsdelivr.net/npm/@reform-digital/script-embed@1.1.0/prod/index.js"
  defer
></script>
```

Then use simpler embeds for each component:

```html
<script 
  rd-component-name="my-component"
  rd-component-src="https://example.com/path/to/component.js"
  defer
></script>
```

This is ideal when:

* You have access to global settings
* You prefer cleaner, shorter embed code
* You're managing a larger site with many components

***

**Both options work identically** — choose whichever fits your workflow best.

## Loading Components

Add component scripts anywhere on your page using either method below.

***

### Usage

#### Method 1: External Script URL

Add a `<script>` tag with the required attributes:

```html
<script 
  rd-component-name="my-component"
  rd-component-src="https://example.com/path/to/component.js"
  defer
></script>
```

#### Method 2: Inline Template

Use a `<template>` element with the script content. **Recommended:** Wrap your JavaScript code in `<script>` tags inside the template to preserve proper formatting and syntax highlighting in Webflow:

```html
<script rd-component-name="my-component" defer></script>
<template rd-component-name="my-component">
  <script>
    // Your component script code here
    console.log('Component loaded!');
  </script>
</template>
```

You can also put JavaScript directly in the template (without script tags), though formatting may not be preserved in Webflow:

```html
<script rd-component-name="my-component" defer></script>
<template rd-component-name="my-component">
  // Your component script code here
  console.log('Component loaded!');
</template>
```

#### Attributes

* **`rd-component-name`** — Unique identifier for your component (required)
* **`rd-component-src`** — URL to the external component script (optional if using template)

**Note:** If you provide both `rd-component-src` and a matching `<template>`, the external URL will be used.

***

### How It Works

1. On page load, the embed script scans for all `<script>` tags with `rd-component-name`
2. For each component, it checks if it's already been loaded (prevents duplicates)
3. If not loaded, it either:
   * Loads the script from the `rd-component-src` URL, or
   * Extracts and executes the content from a matching `<template>` element
4. Tracks loaded components globally to prevent duplicate loading

#### Example

```html
<!-- First instance loads the script -->
<script 
  rd-component-name="tooltip"
  rd-component-src="https://cdn.example.com/tooltip.js"
  defer
></script>

<!-- Second instance won't load (already loaded) -->
<script 
  rd-component-name="tooltip"
  rd-component-src="https://cdn.example.com/tooltip.js"
  defer
></script>
```

This is especially useful when using the same component multiple times across different sections of your page.

***

## Support

Need help? Join our [Slack community](https://join.slack.com/t/rdcommunity/shared_invite/zt-2zser6sir-3CnFYB6gP4lvQsV2rY3wGw).

***

## Product Tracking

ScriptEmbed™ includes an extremely lightweight telemetry module that helps us understand product adoption patterns. This information allows us to focus our support efforts and prioritize product enhancements where they matter most.

**What We Track:**

* **Product Identifier**: The name of the product (e.g., "SCRIPT\_EMBED")
* **Domain**: The public hostname where the product is installed (e.g., "example.com")

**Privacy & Performance:**

* No cookies, fingerprinting, or personally identifiable information
* Only runs on live, public domains (never on localhost or development environments)
* Single lightweight request sent once per page load
* Data is aggregated for internal analytics only
* Not used for advertising, marketing, or tracking

***


# TooltipX™

Accessible tooltips for Webflow.

***

## Overview

TooltipX™ provides a simple framework for adding interactive tooltips to web elements. Developed by [Reform Digital®](https://reform.digital) specifically for Webflow websites.

### Features

* **Hybrid interaction support** — Works with hover, click, and keyboard focus
* **Accessible by default** — Automatic ARIA labels and keyboard navigation
* **Zero dependencies** — Lightweight and fast-loading
* **Webflow-friendly** — Uses HTML data attributes that work seamlessly with Webflow
* **Smart behavior** — Closes other tooltips when opening a new one, auto-closes on scroll
* **Fully customizable** — Complete control over styling using Webflow's native design tools

***

## Quick Start

#### 1. Add the Script

Add to your Webflow project's **global settings**, inside the `<head>` tag:

```html
<script 
  src="https://cdn.jsdelivr.net/npm/@reform-digital/tooltip-x@1.1.0/prod/index.js"
></script>
```

#### 2. Add HTML Structure

Wherever you want a tooltip, add this structure:

```html
<div rd-tooltipx="wrapper">
  <div rd-tooltipx="icon">ℹ️</div>
  <div rd-tooltipx="for">Your Label Text</div>
  <div rd-tooltipx="tooltip">Your tooltip content goes here</div>
</div>
```

**That's it!** TooltipX™ automatically initializes and makes your tooltip interactive.

***

### Required Attributes

TooltipX™ uses HTML data attributes to identify elements. You need four attributes:

* **`rd-tooltipx="wrapper"`** — Main container wrapping all tooltip components
* **`rd-tooltipx="icon"`** — Clickable/hoverable trigger element (typically an info icon)
* **`rd-tooltipx="for"`** — Label text that the tooltip is associated with
* **`rd-tooltipx="tooltip"`** — The tooltip content that appears

#### Complete Example

```html
<div rd-tooltipx="wrapper">
  <div rd-tooltipx="icon">ℹ️</div>
  <div rd-tooltipx="for">Shipping Information</div>
  <div rd-tooltipx="tooltip">
    Free shipping on orders over $50.
  </div>
</div>
```

***

### Behavior

* **Hover** — Shows on mouse enter, hides on mouse leave
* **Click** — Toggle open/closed with a click
* **Keyboard** — Shows on focus (Tab key), closes on Escape
* **Smart** — Only one tooltip open at a time, closes on scroll or click outside

TooltipX™ automatically adds ARIA labels and keyboard accessibility. Style everything using Webflow's native design tools.

***

### Advanced

#### Manual Re-initialization

If you're dynamically adding tooltips after page load:

```javascript
window.TooltipX.init();
```

***

### Support

Need help? Join our [Slack community](https://join.slack.com/t/rdcommunity/shared_invite/zt-2zser6sir-3CnFYB6gP4lvQsV2rY3wGw).

***

## Product Tracking

TooltipX™ includes an extremely lightweight telemetry module that helps us understand product adoption patterns. This information allows us to focus our support efforts and prioritize product enhancements where they matter most.

**What We Track:**

* **Product Identifier**: The name of the product (e.g., "TOOLTIP\_X")
* **Domain**: The public hostname where the product is installed (e.g., "example.com")

**Privacy & Performance:**

* No cookies, fingerprinting, or personally identifiable information
* Only runs on live, public domains (never on localhost or development environments)
* Single lightweight request sent once per page load
* Data is aggregated for internal analytics only
* Not used for advertising, marketing, or tracking

This anonymous usage data helps us ensure TooltipX™ evolves to meet real-world needs.

***


# ContactCloak™

Protect contact information on Webflow sites from scrapers and bots.

***

## Overview

ContactCloak™ encrypts your email addresses and phone numbers in your HTML, making them invisible to bots and scrapers while remaining fully functional for real users. When visitors load your page, ContactCloak™ automatically decrypts and displays your contact information, ensuring a seamless user experience without compromising security.

### Features

* **Email protection** — Encrypts email addresses in mailto links to prevent scraping
* **Phone number protection** — Encrypts phone numbers in tel links to prevent harvesting
* **Text encryption** — Encrypts any sensitive text content that you want to protect
* **Zero dependencies** — Lightweight and fast-loading
* **Webflow-friendly** — Works seamlessly with Webflow sites
* **Automatic decryption** — Contact information is automatically decrypted on page load for real users

***

### Quick Start

#### 1. Add the script

Add this script to your Webflow project's global `<head>` settings:

```html
<!-- ContactCloak™ by Reform Digital® -->
<script
  src="https://cdn.jsdelivr.net/npm/@reform-digital/contact-cloak@1.0.2/prod/contact-cloak.js"
  defer
></script>
```

#### 2. Encrypt your information

Generate encrypted values with the [Contact Cloak encryption tool](https://contact-cloak.webflow.io).

#### 3. Add the appropriate attribute

| Attribute     | Apply to    | Result                                          |
| ------------- | ----------- | ----------------------------------------------- |
| `rd-cc-email` | `<a>`       | Sets its `href` to the decrypted `mailto:` link |
| `rd-cc-phone` | `<a>`       | Sets its `href` to the decrypted `tel:` link    |
| `rd-cc-text`  | Any element | Displays the decrypted value as text            |

```html
<!-- Email -->
<a rd-cc-email="aW5mb0BleGFtcGxlLmNvbQ==">Email us</a>

<!-- Phone -->
<a rd-cc-phone="KzExMjIzMzQ0NTU2Ng==">Call us</a>

<!-- Protected text, such as an address -->
<span rd-cc-text="TmV3IFlvcmssIE5ZIDEwMDAx"></span>
```

Use generic link labels such as “Email us” and “Call us.” Writing the original contact details inside the HTML would expose them to scrapers.

### How It Works

On page load, ContactCloak™ finds the supported `rd-cc-*` attributes, decrypts values generated by the [Contact Cloak encryption tool](https://contact-cloak.webflow.io), and updates each element. Visitors receive functional links and readable text while the original contact information remains absent from the HTML source.

### Product Tracking

ContactCloak™ sends one lightweight, anonymous installation request per product and public domain in each browser. This helps Reform Digital® understand adoption and prioritize improvements.

The request contains only:

* The product identifier (`CONTACT_CLOAK`)
* The public hostname where it is installed (for example, `example.com`)

Tracking does not run on localhost, private networks, or numeric IP addresses. It uses no cookies, fingerprinting, or personally identifiable information, and the aggregated data is not used for advertising or marketing.

### Support

Need help? Join the [Reform Digital® Slack community](https://join.slack.com/t/rdcommunity/shared_invite/zt-2zser6sir-3CnFYB6gP4lvQsV2rY3wGw).


# CopyKit™

One-click copy-paste functionality for Webflow components.

***

## Overview

CopyKit™ lets you instantly copy and paste ready-to-use Webflow components with one click. It intelligently detects the content format (JSON, HTML, or plain text) and copies it to the clipboard in the appropriate format. Perfect for component libraries, design systems, and code showcases.

### Features

* **Smart format detection** — Automatically detects and copies content as JSON, HTML, or plain text
* **One-click copying** — Simple button click to copy any content
* **Success interactions** — Optional visual feedback when content is copied
* **Zero dependencies** — Lightweight and fast-loading
* **Webflow-friendly** — Works seamlessly with Webflow's interaction system

***

## Quick Start

#### 1. Add the Script

Add to your Webflow project's **global settings**, inside the `<head>` tag:

```html
<script 
  src="https://cdn.jsdelivr.net/npm/@reform-digital/copy-flow@1.1.0/prod/index.js"
  defer
></script>
```

**That's it!** CopyKit initializes automatically and is ready to use.

#### 2. Set Up Your Copy Component

Structure your component with the required data attributes:

```html
<div rd-copyflow="wrapper">
  <div rd-copyflow="copy-this">
    <!-- Content to be copied goes here -->
    <div class="my-component">
      <h2>Example Component</h2>
      <p>This will be copied to the clipboard</p>
    </div>
  </div>
  <button rd-copyflow="button">Copy Component</button>
  <div rd-copyflow="success-interaction">Copied!</div>
</div>
```

***

### Usage

#### Basic Structure

Every copy component needs three essential parts:

1. **Wrapper** (`rd-copyflow="wrapper"`) — Contains the entire copy component
2. **Content source** (`rd-copyflow="copy-this"`) — The element whose content will be copied
3. **Button** (`rd-copyflow="button"`) — The element that triggers the copy action

#### Optional: Success Interaction

Add a **success interaction** element (`rd-copyflow="success-interaction"`) to trigger a Webflow interaction when content is successfully copied. This is useful for showing "Copied!" messages or visual feedback.

The success interaction will be automatically clicked when content is copied, and clicked again after 2 seconds to reset (perfect for toggle-style interactions).

#### Data Attributes

* **`rd-copyflow="wrapper"`** — Required wrapper element that contains all copy-related elements
* **`rd-copyflow="copy-this"`** — Required element whose text content will be copied
* **`rd-copyflow="button"`** — Required element that triggers the copy action (clickable)
* **`rd-copyflow="success-interaction"`** — Optional element that triggers on successful copy (typically a Webflow interaction trigger)

***

### How It Works

1. On page load, CopyKit scans for all buttons with `rd-copyflow="button"`
2. When a button is clicked, it finds the nearest wrapper (`rd-copyflow="wrapper"`)
3. Inside the wrapper, it locates the content source (`rd-copyflow="copy-this"`)
4. It intelligently detects the content format:
   * **JSON** — If the content is valid JSON (object or array), it copies as formatted JSON
   * **HTML** — If the content contains HTML tags, it copies as HTML
   * **Plain text** — Otherwise, it copies as plain text
5. The content is added to the clipboard in the appropriate format
6. If a success interaction element exists, it's triggered to provide visual feedback

#### Example: Copying a Component

```html
<div rd-copyflow="wrapper">
  <!-- The component code to copy -->
  <div rd-copyflow="copy-this">
    <div class="card">
      <h3>Card Title</h3>
      <p>Card description goes here.</p>
      <button>Action</button>
    </div>
  </div>
  
  <!-- Copy button -->
  <button rd-copyflow="button">Copy Code</button>
  
  <!-- Success message (optional) -->
  <div rd-copyflow="success-interaction" class="success-message">
    Copied!
  </div>
</div>
```

When the "Copy Code" button is clicked, the HTML inside `rd-copyflow="copy-this"` will be copied to the clipboard as HTML format, and the success message will appear (if you've set up a Webflow interaction on that element).

#### Example: Copying JSON

```html
<div rd-copyflow="wrapper">
  <pre rd-copyflow="copy-this">
{
  "name": "Example",
  "value": 123
}
  </pre>
  <button rd-copyflow="button">Copy JSON</button>
</div>
```

The JSON will be copied in a properly formatted way, making it easy to paste into code editors or share with developers.

***

### Support

Need help? Join our [Slack community](https://join.slack.com/t/rdcommunity/shared_invite/zt-2zser6sir-3CnFYB6gP4lvQsV2rY3wGw).

***

## Product Tracking

CopyKit™ includes an extremely lightweight telemetry module that helps us understand product adoption patterns. This information allows us to focus our support efforts and prioritize product enhancements where they matter most.

**What We Track:**

* **Product Identifier**: The name of the product (e.g., "COPY\_KIT")
* **Domain**: The public hostname where the product is installed (e.g., "example.com")

**Privacy & Performance:**

* No cookies, fingerprinting, or personally identifiable information
* Only runs on live, public domains (never on localhost or development environments)
* Single lightweight request sent once per page load
* Data is aggregated for internal analytics only
* Not used for advertising, marketing, or tracking

***


# FlowAudio™

Native audio player for webflow. Free, fully customisable & CMS driven.


# Copy-Paste to Webflow


# Copy-Paste to Figma


