From webflow-pack
Executes Webflow Data API v2 for sites management, pages metadata, forms submissions, ecommerce products/orders/inventory, and custom code.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin webflow-packThis skill is limited to using the following tools:
Beyond CMS content management, Webflow's Data API v2 covers site operations, page
Automates Webflow CMS collections, site publishing, page management, asset uploads, and ecommerce orders via Composio tools and Rube MCP. Use for managing live sites programmatically.
Automates Webflow CMS collections, site publishing, page management, asset uploads, and ecommerce orders via Rube MCP (Composio). Useful for programmatic site and content management.
Registers Webflow webhooks, verifies HMAC signatures, and handles events like form submissions, site publishes, ecommerce orders, and CMS changes for event-driven backends.
Share bugs, ideas, or general feedback.
Beyond CMS content management, Webflow's Data API v2 covers site operations, page metadata, form submissions, ecommerce (products, orders, inventory), and custom code injection. This skill covers all non-CMS API domains.
webflow-install-auth setupsites:read, sites:write, pages:read, forms:read,
ecommerce:read, ecommerce:write, custom_code:read, custom_code:writeimport { WebflowClient } from "webflow-api";
const webflow = new WebflowClient({
accessToken: process.env.WEBFLOW_API_TOKEN!,
});
// List all sites
async function listSites() {
const { sites } = await webflow.sites.list();
for (const site of sites!) {
console.log(`${site.displayName} (${site.id})`);
console.log(` Short name: ${site.shortName}`);
console.log(` Timezone: ${site.timeZone}`);
console.log(` Created: ${site.createdOn}`);
console.log(` Last published: ${site.lastPublished}`);
console.log(` Custom domains: ${site.customDomains?.map(d => d.url).join(", ")}`);
console.log(` Default locale: ${site.locales?.[0]?.displayName}`);
}
}
// Get single site details
async function getSite(siteId: string) {
const site = await webflow.sites.get(siteId);
return site;
}
// Publish site (rate limit: 1 per minute)
async function publishSite(siteId: string, domains?: string[]) {
await webflow.sites.publish(siteId, {
publishToWebflowSubdomain: true,
customDomains: domains, // Optional: publish to specific domains
});
console.log("Site published successfully");
}
// List all pages for a site
async function listPages(siteId: string) {
const { pages } = await webflow.pages.list(siteId);
for (const page of pages!) {
console.log(`${page.title} (${page.id})`);
console.log(` Slug: ${page.slug}`);
console.log(` SEO title: ${page.seo?.title}`);
console.log(` SEO description: ${page.seo?.description}`);
console.log(` Open Graph image: ${page.openGraph?.titleCopied}`);
console.log(` Created: ${page.createdOn}`);
console.log(` Published: ${page.publishedPath}`);
}
}
// Get page metadata
async function getPage(pageId: string) {
const page = await webflow.pages.getMetadata(pageId);
return page;
}
// Update page SEO metadata
async function updatePageSEO(pageId: string) {
await webflow.pages.updatePageSettings(pageId, {
seo: {
title: "New SEO Title — My Site",
description: "Updated meta description for search engines.",
},
openGraph: {
title: "New OG Title",
description: "Updated Open Graph description for social shares.",
},
});
}
// List forms on a site
async function listForms(siteId: string) {
const { forms } = await webflow.forms.list(siteId);
for (const form of forms!) {
console.log(`Form: ${form.displayName} (${form.id})`);
console.log(` Site ID: ${form.siteId}`);
console.log(` Page name: ${form.pageName}`);
console.log(` Submission count: ${form.submissionCount}`);
console.log(` Fields:`);
for (const field of form.fields || []) {
console.log(` ${field.displayName} (${field.type})`);
}
}
}
// Get form submissions (paginated)
async function getFormSubmissions(formId: string) {
const { formSubmissions } = await webflow.forms.listSubmissions(formId, {
limit: 100,
offset: 0,
});
for (const sub of formSubmissions!) {
console.log(`Submission ${sub.id}:`);
console.log(` Submitted: ${sub.submittedAt}`);
console.log(` Data: ${JSON.stringify(sub.formData)}`);
}
}
// Export all form submissions to CSV
async function exportFormData(formId: string) {
const allSubmissions = [];
let offset = 0;
const limit = 100;
while (true) {
const { formSubmissions, pagination } =
await webflow.forms.listSubmissions(formId, { limit, offset });
allSubmissions.push(...(formSubmissions || []));
if (allSubmissions.length >= (pagination?.total || 0)) break;
offset += limit;
}
return allSubmissions.map(sub => sub.formData);
}
// List all products
async function listProducts(siteId: string) {
const { items } = await webflow.products.list(siteId, {
limit: 100,
offset: 0,
});
for (const product of items!) {
console.log(`Product: ${product.product?.fieldData?.name}`);
console.log(` ID: ${product.product?.id}`);
console.log(` Slug: ${product.product?.fieldData?.slug}`);
console.log(` SKUs:`);
for (const sku of product.skus || []) {
console.log(` ${sku.fieldData?.name}: $${sku.fieldData?.price?.value}`);
console.log(` Inventory: ${sku.fieldData?.quantity}`);
}
}
}
// Get single product with all SKUs
async function getProduct(siteId: string, productId: string) {
const product = await webflow.products.get(siteId, productId);
return product;
}
// Create a product
async function createProduct(siteId: string) {
const product = await webflow.products.create(siteId, {
product: {
fieldData: {
name: "Premium Widget",
slug: "premium-widget",
description: "<p>Our best-selling widget</p>",
},
},
sku: {
fieldData: {
name: "Default",
slug: "default",
price: { value: 2999, unit: "USD" }, // Price in cents
quantity: 100,
"sku-properties": [],
},
},
});
console.log(`Created product: ${product.product?.id}`);
}
// Update inventory
async function updateInventory(
siteId: string,
collectionId: string,
itemId: string,
quantity: number
) {
await webflow.inventory.update(collectionId, itemId, {
inventoryType: "finite",
updateQuantity: quantity,
});
}
// List orders
async function listOrders(siteId: string) {
const { orders } = await webflow.orders.list(siteId, {
limit: 100,
});
for (const order of orders!) {
console.log(`Order #${order.orderId} (${order.status})`);
console.log(` Customer: ${order.customerInfo?.fullName}`);
console.log(` Email: ${order.customerInfo?.email}`);
console.log(` Total: $${(order.customerPaid?.value || 0) / 100}`);
console.log(` Items: ${order.purchasedItems?.length}`);
console.log(` Created: ${order.acceptedOn}`);
}
}
// Get order details
async function getOrder(siteId: string, orderId: string) {
const order = await webflow.orders.get(siteId, orderId);
return order;
}
// Update order status (fulfill, refund)
async function fulfillOrder(siteId: string, orderId: string) {
await webflow.orders.update(siteId, orderId, {
status: "fulfilled",
});
}
// Refund an order
async function refundOrder(siteId: string, orderId: string) {
await webflow.orders.refund(siteId, orderId);
console.log(`Refunded order: ${orderId}`);
}
// Register custom code to the site head/footer
async function addSiteCustomCode(siteId: string) {
// Register hosted script
await webflow.scripts.registerHosted(siteId, {
hostedLocation: "https://cdn.example.com/analytics.js",
integrityHash: "sha384-...",
canCopy: false,
version: "1.0.0",
displayName: "Analytics Script",
});
// Register inline script
await webflow.scripts.registerInline(siteId, {
sourceCode: "console.log('Hello from custom code');",
version: "1.0.0",
canCopy: true,
displayName: "Debug Script",
});
}
| Error | Cause | Solution |
|---|---|---|
403 Forbidden on ecommerce | Missing ecommerce:read scope | Add scope to token |
Site publish 429 | >1 publish/minute | Wait 60s between publishes |
| Empty products list | Ecommerce not enabled on site | Enable Ecommerce in Webflow dashboard |
Form 404 | Wrong form_id | List forms with forms.list(siteId) first |
| Order refund fails | Order already refunded | Check order status before refunding |
For common errors, see webflow-common-errors.