Webflow offers powerful form design flexibility, but connecting its forms to ActiveCampaign isn’t a built-in option. Don’t worry—we’ll walk you through three straightforward ways to connect them, whether you want a quick plug-and-play option or full creative control.
Here’s what we’ll cover:
Whether you need a quick setup, workflow automation, or full design flexibility, this guide has the right method for your needs. Let’s dive into each option in detail!
This method is super easy! Just embed your ActiveCampaign forms into Webflow using either a one-line JavaScript snippet (Simple Embed) or a combination of HTML/JavaScript (Full Embed).
You have two ways to embed your forms:
When you create your ActiveCampaign form, you’ll have these two embedding options to choose from. Don’t worry—we’ll guide you step by step to help you set it up easily, no matter which option you pick!
This method is ideal if you want a fast setup with minimal effort. ActiveCampaign’s form editor includes styling tools for colors, fonts, and layouts, letting you design a polished form that blends seamlessly into your Webflow site—no advanced customization needed.
Want to take your form design even further? BRIX Templates can help you style your ActiveCampaign Full Embed with custom CSS to perfectly match your branding.
Zapier is a no-code automation tool that connects your Webflow forms to ActiveCampaign. This method preserves your custom Webflow form design while automating contact data transfers.
If you need more advanced integrations—like syncing multiple task between different apps, connecting with or more advanced No-Code workflows—Zapier is a powerful option to extend Webflow’s capabilities. Need complex automations? BRIX Templates can build custom Zapier workflows tailored to your business needs.
⚠️ Note: Zapier charges monthly based on task volume. For example, 2,000 tasks (e.g., form submissions) cost $48.19/month (as of this writing) on the Business Plan.
As we’ve seen above, the first two methods offer convenient solutions: Embedding ActiveCampaign’s form code directly into Webflow provides an easy setup with ActiveCampaign’s native forms, though it’s design-limited. Zapier integration to connect Webflow form submissions to ActiveCampaign allows for no-code workflows while keeping your Webflow form design intact, but its recurring costs can quickly add up—especially for high-volume sites, making it less ideal for businesses handling large amounts of data.
To overcome these challenges, we’ve developed a custom JavaScript code designed to run on a Cloudflare Worker. This method leverages the ActiveCampaign API to connect your Webflow forms seamlessly while preserving your current design. We’ll guide you through setting up your own Cloudflare Worker, which allows you to handle up to 100,000 requests daily for free and scale to 10 million requests a day for just $5.
Here’s why this custom integration is a great choice:
For businesses seeking a cost-effective and scalable solution without sacrificing design flexibility, this custom JavaScript code to connect Webflow forms with the ActiveCampaign API is the ideal option.
Cloudflare Worker is a serverless platform that runs code on Cloudflare’s global network without requiring a traditional server. For example, it can process tasks like form submissions quickly and reliably, minimizing both costs and complexity.
This custom script links your Webflow forms to ActiveCampaign, processing form submissions and automating tasks like subscriptions and tag management.
const CONFIG = {
ACTIVE_CAMPAIGN_URL: '',
ACTIVE_CAMPAIGN_API_URL: '',
ACTIVE_CAMPAIGN_API_KEY: '',
ALLOWED_ORIGIN: '*'
};
const corsHeaders = {
'Access-Control-Allow-Origin': CONFIG.ALLOWED_ORIGIN,
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Access-Control-Max-Age': '86400',
};
async function addContactToList(contact, formData) {
// First, submit to proc.php to handle the list subscription
const procResponse = await fetch(CONFIG.ACTIVE_CAMPAIGN_URL, {
method: 'POST',
body: formData
});
if (!procResponse.ok) {
throw new Error('Failed to add contact to list');
}
// If we have tags, handle them through the API
const tags = formData.get('tags');
if (tags) {
try {
// Get contact by email to get their ID
const contactResponse = await fetch(`${CONFIG.ACTIVE_CAMPAIGN_API_URL}/contacts?email=${encodeURIComponent(contact.email)}`, {
headers: {
'Api-Token': CONFIG.ACTIVE_CAMPAIGN_API_KEY,
'Content-Type': 'application/json'
}
});
const contactResult = await contactResponse.json();
if (contactResult.contacts && contactResult.contacts.length > 0) {
const contactId = contactResult.contacts[0].id;
// Improved tag splitting
const tagArray = tags.split(/\s*,\s*/).filter(tag => tag.trim());
console.log('Processing tags:', tagArray);
// Add each tag
for (const tagName of tagArray) {
try {
// First try to find existing tag
const searchResponse = await fetch(`${CONFIG.ACTIVE_CAMPAIGN_API_URL}/tags?search=${encodeURIComponent(tagName)}`, {
headers: {
'Api-Token': CONFIG.ACTIVE_CAMPAIGN_API_KEY,
'Content-Type': 'application/json'
}
});
const searchResult = await searchResponse.json();
let tagId = null;
// Check if tag exists
if (searchResult.tags) {
const existingTag = searchResult.tags.find(t =>
t.tag.toLowerCase() === tagName.toLowerCase()
);
if (existingTag) {
tagId = existingTag.id;
}
}
// If tag doesn't exist, create it
if (!tagId) {
const createResponse = await fetch(`${CONFIG.ACTIVE_CAMPAIGN_API_URL}/tags`, {
method: 'POST',
headers: {
'Api-Token': CONFIG.ACTIVE_CAMPAIGN_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
tag: {
tag: tagName,
tagType: 'contact',
description: `Tag created for ${contact.email}`
}
})
});
const createResult = await createResponse.json();
tagId = createResult.tag?.id;
}
if (tagId) {
// Add tag to contact
await fetch(`${CONFIG.ACTIVE_CAMPAIGN_API_URL}/contactTags`, {
method: 'POST',
headers: {
'Api-Token': CONFIG.ACTIVE_CAMPAIGN_API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
contactTag: {
contact: contactId,
tag: tagId
}
})
});
console.log(`Successfully added tag: ${tagName}`);
}
} catch (tagError) {
console.error(`Error processing tag ${tagName}:`, tagError);
}
}
}
} catch (tagError) {
console.error('Error handling tags:', tagError);
// Don't throw error here - we still want to count the submission as successful
}
}
return true;
}
function handleOptions(request) {
return new Response(null, { headers: corsHeaders });
}
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
if (request.method === 'OPTIONS') {
return handleOptions(request);
}
if (request.method !== 'POST') {
return new Response('Method not allowed', { status: 405 });
}
try {
const formData = await request.formData();
const contact = {
email: formData.get('email'),
firstname: formData.get('firstname') || '',
lastname: formData.get('lastname') || ''
};
const result = await addContactToList(contact, formData);
return new Response(JSON.stringify({
success: true,
data: result
}), {
headers: {
...corsHeaders,
'Content-Type': 'application/json'
}
});
} catch (error) {
return new Response(JSON.stringify({
success: false,
error: error.message
}), {
status: 500,
headers: {
...corsHeaders,
'Content-Type': 'application/json'
}
});
}
}
This custom JavaScript script connects your Webflow form to the Cloudflare Worker and ActiveCampaign, handling form submissions, validation, and feedback messages.
<script>
//===========================================
// CONFIGURATION - Minimal
//===========================================
const CONFIG = {
// Replace with YOUR Cloudflare worker URL
workerUrl: '',
// Webflow Form Selectors
selectors: {
formSelector: 'form[data-ac-form-id]',
// Classes for success/error messages
messageClasses: {
success: '',
error: ''
},
// IDs for form elements
elementIds: {
submitButton: ''
}
}
};
//===========================================
// Form Handler
//===========================================
document.addEventListener('DOMContentLoaded', function() {
// Find the form by data-ac-form-id
const forms = document.querySelectorAll(CONFIG.selectors.formSelector);
forms.forEach(form => {
// Grab the submit button
const submitButton = form.querySelector(`#${CONFIG.selectors.elementIds.submitButton}`);
// Grab success and error message divs
const successMessage = document.querySelector(`.${CONFIG.selectors.messageClasses.success}`);
const errorMessage = document.querySelector(`.${CONFIG.selectors.messageClasses.error}`);
form.addEventListener('submit', async function(e) {
e.preventDefault();
// Hide any existing messages
if (successMessage) successMessage.style.display = 'none';
if (errorMessage) errorMessage.style.display = 'none';
try {
// Gather form data
const formData = new FormData(form);
// ActiveCampaign required fields
formData.append('u', form.getAttribute('data-ac-form-id'));
formData.append('f', form.getAttribute('data-ac-form-id'));
formData.append('s', '');
formData.append('c', '0');
formData.append('m', '0');
formData.append('act', 'sub');
formData.append('v', '2');
formData.append('or', form.getAttribute('data-ac-org-id'));
// Send data to your Cloudflare Worker
const response = await fetch(CONFIG.workerUrl, {
method: 'POST',
body: formData
});
const result = await response.json();
console.log('Server response:', result);
if (result.success) {
// Success: Hide form, show success
form.style.display = 'none';
if (successMessage) successMessage.style.display = 'block';
} else {
// Error response from server
if (errorMessage) errorMessage.style.display = 'block';
}
} catch (err) {
console.error('Form submission error:', err);
// Network or unexpected error
if (errorMessage) errorMessage.style.display = 'block';
}
});
});
});
</script>
Configurethe CONFIG object in the script with the following details:
Save your changes and publish the page in Webflow to activate the integration.
Get your ActiveCampaign form identifiers
Update your Webflow form
Key requirements
Choosing the right integration method depends on your specific needs and resources. Here's a quick overview to help you decide:
By evaluating your priorities—whether it's speed, automation complexity, or design flexibility—you can select the integration method that best aligns with your goals.
All three methods can successfully link your Webflow forms with ActiveCampaign. However, Method 3 (Custom JavaScript) stands out for flexibility, scalability, and cost efficiency, making it ideal for most users.
Need Assistance? Our team specializes in Webflow integrations and is ready to help you implement any of these methods. We can also develop custom solutions tailored to your unique needs. Contact us today to get started!
Learn how to add animated number counters to your Webflow site. This step-by-step guide explains how to do it in 5 minutes or less.
Learn how to add a copy URL button to your Webflow site. Step-by-step guide for implementing easy page sharing without plugins or code.
Learn how to add copy-to-clipboard button to your Webflow site in 5 minutes or less.