Webflow Core Workflow B — Sites, Pages, Forms & Ecommerce
Overview
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.
Prerequisites
- Completed
webflow-install-auth setup
- Scopes needed:
sites:read, sites:write, pages:read, forms:read,
ecommerce:read, ecommerce:write, custom_code:read, custom_code:write
Instructions
1. Sites Management
import { 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");
}
2. Pages API
// 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.",
},
});
}
3. Form Submissions
// 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);
}
4. Ecommerce — Products & SKUs
// 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,
});
}
5. Ecommerce — Orders
// 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}`);
}
6. Custom Code
// 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",
});
}
Output
- Sites: list, get details, publish with domain control
- Pages: list, read SEO metadata, update Open Graph settings
- Forms: list forms, read all submissions, export data
- Ecommerce: CRUD products/SKUs, manage orders, update inventory
- Custom Code: register hosted and inline scripts
Error Handling
| 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 |
Resources
Next Steps
For common errors, see webflow-common-errors.
Source: jeremylongshore/claude-code-plugins-plus-skills → plugins/saas-packs/webflow-pack/skills/webflow-core-workflow-b/SKILL.md
1---2name: webflow-core-workflow-b3description: "\"Execute Webflow secondary workflows \\u2014 Sites management, Pages API,\\ \\ Forms submissions,\\nEcommerce (products/orders/inventory), and Custom Code via\\ \\ the Data API v2.\\nUse when managing sites, reading pages, handling form data,\\ \\ or working with\\nWebflow Ecommerce products and orders.\\nTrigger with phrases\\ \\ like \\\"webflow sites\\\", \\\"webflow pages\\\", \\\"webflow forms\\\",\\n\\\"webflow ecommerce\\\"\\ , \\\"webflow products\\\", \\\"webflow orders\\\".\\n\""4allowed-tools: "Read, Write, Edit, Bash(npm:*), Bash(npx:*), Grep"5category: backend-and-data6source_repo: jeremylongshore/claude-code-plugins-plus-skills7source_path: "plugins/saas-packs/webflow-pack/skills/webflow-core-workflow-b/SKILL.md"8source_url: https://github.com/jeremylongshore/claude-code-plugins-plus-skills/blob/HEAD/plugins/saas-packs/webflow-pack/skills/webflow-core-workflow-b/SKILL.md9---1011# Webflow Core Workflow B — Sites, Pages, Forms & Ecommerce1213## Overview1415Beyond CMS content management, Webflow's Data API v2 covers site operations, page16metadata, form submissions, ecommerce (products, orders, inventory), and custom code17injection. This skill covers all non-CMS API domains.1819## Prerequisites2021- Completed `webflow-install-auth` setup22- Scopes needed: `sites:read`, `sites:write`, `pages:read`, `forms:read`,23 `ecommerce:read`, `ecommerce:write`, `custom_code:read`, `custom_code:write`2425## Instructions2627### 1. Sites Management2829```typescript30import { WebflowClient } from "webflow-api";3132const webflow = new WebflowClient({33 accessToken: process.env.WEBFLOW_API_TOKEN!,34});3536// List all sites37async function listSites() {38 const { sites } = await webflow.sites.list();39 for (const site of sites!) {40 console.log(`${site.displayName} (${site.id})`);41 console.log(` Short name: ${site.shortName}`);42 console.log(` Timezone: ${site.timeZone}`);43 console.log(` Created: ${site.createdOn}`);44 console.log(` Last published: ${site.lastPublished}`);45 console.log(` Custom domains: ${site.customDomains?.map(d => d.url).join(", ")}`);46 console.log(` Default locale: ${site.locales?.[0]?.displayName}`);47 }48}4950// Get single site details51async function getSite(siteId: string) {52 const site = await webflow.sites.get(siteId);53 return site;54}5556// Publish site (rate limit: 1 per minute)57async function publishSite(siteId: string, domains?: string[]) {58 await webflow.sites.publish(siteId, {59 publishToWebflowSubdomain: true,60 customDomains: domains, // Optional: publish to specific domains61 });62 console.log("Site published successfully");63}64```6566### 2. Pages API6768```typescript69// List all pages for a site70async function listPages(siteId: string) {71 const { pages } = await webflow.pages.list(siteId);7273 for (const page of pages!) {74 console.log(`${page.title} (${page.id})`);75 console.log(` Slug: ${page.slug}`);76 console.log(` SEO title: ${page.seo?.title}`);77 console.log(` SEO description: ${page.seo?.description}`);78 console.log(` Open Graph image: ${page.openGraph?.titleCopied}`);79 console.log(` Created: ${page.createdOn}`);80 console.log(` Published: ${page.publishedPath}`);81 }82}8384// Get page metadata85async function getPage(pageId: string) {86 const page = await webflow.pages.getMetadata(pageId);87 return page;88}8990// Update page SEO metadata91async function updatePageSEO(pageId: string) {92 await webflow.pages.updatePageSettings(pageId, {93 seo: {94 title: "New SEO Title — My Site",95 description: "Updated meta description for search engines.",96 },97 openGraph: {98 title: "New OG Title",99 description: "Updated Open Graph description for social shares.",100 },101 });102}103```104105### 3. Form Submissions106107```typescript108// List forms on a site109async function listForms(siteId: string) {110 const { forms } = await webflow.forms.list(siteId);111112 for (const form of forms!) {113 console.log(`Form: ${form.displayName} (${form.id})`);114 console.log(` Site ID: ${form.siteId}`);115 console.log(` Page name: ${form.pageName}`);116 console.log(` Submission count: ${form.submissionCount}`);117 console.log(` Fields:`);118 for (const field of form.fields || []) {119 console.log(` ${field.displayName} (${field.type})`);120 }121 }122}123124// Get form submissions (paginated)125async function getFormSubmissions(formId: string) {126 const { formSubmissions } = await webflow.forms.listSubmissions(formId, {127 limit: 100,128 offset: 0,129 });130131 for (const sub of formSubmissions!) {132 console.log(`Submission ${sub.id}:`);133 console.log(` Submitted: ${sub.submittedAt}`);134 console.log(` Data: ${JSON.stringify(sub.formData)}`);135 }136}137138// Export all form submissions to CSV139async function exportFormData(formId: string) {140 const allSubmissions = [];141 let offset = 0;142 const limit = 100;143144 while (true) {145 const { formSubmissions, pagination } =146 await webflow.forms.listSubmissions(formId, { limit, offset });147148 allSubmissions.push(...(formSubmissions || []));149 if (allSubmissions.length >= (pagination?.total || 0)) break;150 offset += limit;151 }152153 return allSubmissions.map(sub => sub.formData);154}155```156157### 4. Ecommerce — Products & SKUs158159```typescript160// List all products161async function listProducts(siteId: string) {162 const { items } = await webflow.products.list(siteId, {163 limit: 100,164 offset: 0,165 });166167 for (const product of items!) {168 console.log(`Product: ${product.product?.fieldData?.name}`);169 console.log(` ID: ${product.product?.id}`);170 console.log(` Slug: ${product.product?.fieldData?.slug}`);171 console.log(` SKUs:`);172 for (const sku of product.skus || []) {173 console.log(` ${sku.fieldData?.name}: $${sku.fieldData?.price?.value}`);174 console.log(` Inventory: ${sku.fieldData?.quantity}`);175 }176 }177}178179// Get single product with all SKUs180async function getProduct(siteId: string, productId: string) {181 const product = await webflow.products.get(siteId, productId);182 return product;183}184185// Create a product186async function createProduct(siteId: string) {187 const product = await webflow.products.create(siteId, {188 product: {189 fieldData: {190 name: "Premium Widget",191 slug: "premium-widget",192 description: "<p>Our best-selling widget</p>",193 },194 },195 sku: {196 fieldData: {197 name: "Default",198 slug: "default",199 price: { value: 2999, unit: "USD" }, // Price in cents200 quantity: 100,201 "sku-properties": [],202 },203 },204 });205206 console.log(`Created product: ${product.product?.id}`);207}208209// Update inventory210async function updateInventory(211 siteId: string,212 collectionId: string,213 itemId: string,214 quantity: number215) {216 await webflow.inventory.update(collectionId, itemId, {217 inventoryType: "finite",218 updateQuantity: quantity,219 });220}221```222223### 5. Ecommerce — Orders224225```typescript226// List orders227async function listOrders(siteId: string) {228 const { orders } = await webflow.orders.list(siteId, {229 limit: 100,230 });231232 for (const order of orders!) {233 console.log(`Order #${order.orderId} (${order.status})`);234 console.log(` Customer: ${order.customerInfo?.fullName}`);235 console.log(` Email: ${order.customerInfo?.email}`);236 console.log(` Total: $${(order.customerPaid?.value || 0) / 100}`);237 console.log(` Items: ${order.purchasedItems?.length}`);238 console.log(` Created: ${order.acceptedOn}`);239 }240}241242// Get order details243async function getOrder(siteId: string, orderId: string) {244 const order = await webflow.orders.get(siteId, orderId);245 return order;246}247248// Update order status (fulfill, refund)249async function fulfillOrder(siteId: string, orderId: string) {250 await webflow.orders.update(siteId, orderId, {251 status: "fulfilled",252 });253}254255// Refund an order256async function refundOrder(siteId: string, orderId: string) {257 await webflow.orders.refund(siteId, orderId);258 console.log(`Refunded order: ${orderId}`);259}260```261262### 6. Custom Code263264```typescript265// Register custom code to the site head/footer266async function addSiteCustomCode(siteId: string) {267 // Register hosted script268 await webflow.scripts.registerHosted(siteId, {269 hostedLocation: "https://cdn.example.com/analytics.js",270 integrityHash: "sha384-...",271 canCopy: false,272 version: "1.0.0",273 displayName: "Analytics Script",274 });275276 // Register inline script277 await webflow.scripts.registerInline(siteId, {278 sourceCode: "console.log('Hello from custom code');",279 version: "1.0.0",280 canCopy: true,281 displayName: "Debug Script",282 });283}284```285286## Output287288- Sites: list, get details, publish with domain control289- Pages: list, read SEO metadata, update Open Graph settings290- Forms: list forms, read all submissions, export data291- Ecommerce: CRUD products/SKUs, manage orders, update inventory292- Custom Code: register hosted and inline scripts293294## Error Handling295296| Error | Cause | Solution |297|-------|-------|----------|298| `403 Forbidden` on ecommerce | Missing `ecommerce:read` scope | Add scope to token |299| Site publish `429` | >1 publish/minute | Wait 60s between publishes |300| Empty products list | Ecommerce not enabled on site | Enable Ecommerce in Webflow dashboard |301| Form `404` | Wrong form_id | List forms with `forms.list(siteId)` first |302| Order refund fails | Order already refunded | Check order status before refunding |303304## Resources305306- [Sites API](https://developers.webflow.com/data/reference/sites)307- Pages API308- [Forms API](https://developers.webflow.com/data/reference/forms)309- [Ecommerce Products](https://developers.webflow.com/data/reference/ecommerce/products/list)310- [Custom Code API](https://developers.webflow.com/data/reference/custom-code)311312## Next Steps313314For common errors, see `webflow-common-errors`.315316---317318**Source:** [`jeremylongshore/claude-code-plugins-plus-skills`](https://github.com/jeremylongshore/claude-code-plugins-plus-skills) → `plugins/saas-packs/webflow-pack/skills/webflow-core-workflow-b/SKILL.md`