From webflow-pack
Manages Webflow CMS collections and items via Data API v2: list, CRUD (single/bulk), publish. For dynamic content like blog posts or team members.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin webflow-packThis skill is limited to using the following tools:
The primary money-path workflow for Webflow: managing CMS collections and items
Bulk creates or updates Webflow CMS collection items with schema validation, diff previews, granular approvals, and rollback. Use for multiple blog posts, products, or field updates.
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.
Generates TypeScript examples for Webflow Data API v2: list sites, read CMS collections/items, create items. For new integrations, testing setups, or learning basics.
Share bugs, ideas, or general feedback.
The primary money-path workflow for Webflow: managing CMS collections and items through the Data API v2. Covers the full CRUD lifecycle — create, read, update, delete, and publish CMS content programmatically.
webflow-install-auth setupcms:read and cms:write scopes| Operation | Method | Endpoint |
|---|---|---|
| List collections | GET | /v2/sites/{site_id}/collections |
| Get collection | GET | /v2/collections/{collection_id} |
| List items (staged) | GET | /v2/collections/{collection_id}/items |
| List items (live) | GET | /v2/collections/{collection_id}/items/live |
| Get item | GET | /v2/collections/{collection_id}/items/{item_id} |
| Create item | POST | /v2/collections/{collection_id}/items |
| Create items (bulk) | POST | /v2/collections/{collection_id}/items/bulk |
| Update item | PATCH | /v2/collections/{collection_id}/items/{item_id} |
| Update items (bulk) | PATCH | /v2/collections/{collection_id}/items/bulk |
| Delete item | DELETE | /v2/collections/{collection_id}/items/{item_id} |
| Delete items (bulk) | DELETE | /v2/collections/{collection_id}/items/bulk |
| Publish item | POST | /v2/collections/{collection_id}/items/publish |
import { WebflowClient } from "webflow-api";
const webflow = new WebflowClient({
accessToken: process.env.WEBFLOW_API_TOKEN!,
});
async function inspectCollections(siteId: string) {
const { collections } = await webflow.collections.list(siteId);
for (const col of collections!) {
console.log(`\n=== ${col.displayName} (${col.slug}) ===`);
console.log(`ID: ${col.id}`);
console.log(`Items: ${col.itemCount}`);
console.log(`Fields:`);
for (const field of col.fields || []) {
const req = field.isRequired ? " [REQUIRED]" : "";
console.log(` ${field.slug} (${field.type})${req}`);
// Types: PlainText, RichText, Image, MultiImage, Video,
// Link, Email, Phone, Number, DateTime, Switch,
// Color, Option, File, Reference, MultiReference,
// MembershipPlan
}
}
}
Items are created as drafts by default (isDraft: true). Field names use slug format.
async function createItem(collectionId: string) {
const item = await webflow.collections.items.createItem(collectionId, {
isDraft: false, // false = staged for publishing
fieldData: {
// "name" and "slug" are required system fields
name: "My New Blog Post",
slug: "my-new-blog-post",
// Custom fields use slug versions of field names
"post-body": "<h2>Hello World</h2><p>Content here.</p>",
"author-name": "Jeremy Longshore",
"publish-date": new Date().toISOString(),
"featured": true,
// Reference fields use the referenced item's ID
"category": "ref-item-id-here",
// Image fields use the Webflow asset URL
"hero-image": {
url: "https://uploads-ssl.webflow.com/...",
alt: "Hero image description",
},
},
});
console.log(`Created: ${item.id} (draft: ${item.isDraft})`);
return item;
}
async function bulkCreate(collectionId: string) {
const items = Array.from({ length: 50 }, (_, i) => ({
fieldData: {
name: `Product ${i + 1}`,
slug: `product-${i + 1}`,
price: (i + 1) * 9.99,
description: `Description for product ${i + 1}`,
},
isDraft: false,
}));
const result = await webflow.collections.items.createItemsBulk(
collectionId,
{ items }
);
console.log(`Bulk created: ${result.items?.length} items`);
return result;
}
async function readItems(collectionId: string) {
// Staged items (drafts + published, working copy)
const staged = await webflow.collections.items.listItems(collectionId, {
limit: 100, // Max 100 per request
offset: 0,
// Optional filters:
// sortBy: "fieldData.name",
// sortOrder: "asc",
});
console.log(`Staged items: ${staged.pagination?.total}`);
// Live items (published only, what visitors see)
const live = await webflow.collections.items.listItemsLive(collectionId, {
limit: 100,
});
console.log(`Live items: ${live.pagination?.total}`);
// Get single item by ID
const item = await webflow.collections.items.getItem(
collectionId,
staged.items![0].id!
);
console.log(`Item: ${item.fieldData?.name}`);
}
async function updateItem(collectionId: string, itemId: string) {
// PATCH — only send fields you want to change
const updated = await webflow.collections.items.updateItem(
collectionId,
itemId,
{
fieldData: {
name: "Updated Title",
"post-body": "<p>Updated content</p>",
},
}
);
console.log(`Updated: ${updated.id} at ${updated.lastUpdated}`);
}
// Bulk update (up to 100 items)
async function bulkUpdate(collectionId: string, updates: Array<{ id: string; fields: Record<string, any> }>) {
const items = updates.map(u => ({
id: u.id,
fieldData: u.fields,
}));
await webflow.collections.items.updateItemsBulk(collectionId, { items });
}
Publishing makes staged changes visible on the live site.
async function publishItems(collectionId: string, itemIds: string[]) {
// Publish specific items (not the whole site)
await webflow.collections.items.publishItem(collectionId, {
itemIds,
});
console.log(`Published ${itemIds.length} items`);
}
// Or publish the entire site (requires sites:write scope)
async function publishSite(siteId: string) {
// Rate limit: max 1 publish per minute
await webflow.sites.publish(siteId, {
publishToWebflowSubdomain: true,
// customDomains: ["example.com"], // Specify domains to publish to
});
console.log("Site published");
}
async function deleteItem(collectionId: string, itemId: string) {
await webflow.collections.items.deleteItem(collectionId, itemId);
console.log(`Deleted: ${itemId}`);
}
// Bulk delete (up to 100 items)
async function bulkDelete(collectionId: string, itemIds: string[]) {
await webflow.collections.items.deleteItemsBulk(collectionId, {
itemIds,
});
console.log(`Deleted ${itemIds.length} items`);
}
async function syncContentFromExternalCMS(
siteId: string,
collectionSlug: string,
externalPosts: Array<{ title: string; body: string; publishedAt: string }>
) {
// 1. Find the target collection
const { collections } = await webflow.collections.list(siteId);
const collection = collections!.find(c => c.slug === collectionSlug);
if (!collection) throw new Error(`Collection "${collectionSlug}" not found`);
// 2. Get existing items to avoid duplicates
const { items: existing } = await webflow.collections.items.listItems(collection.id!);
const existingSlugs = new Set(existing!.map(i => i.fieldData?.slug));
// 3. Create new items (skip duplicates)
const newPosts = externalPosts.filter(
p => !existingSlugs.has(slugify(p.title))
);
if (newPosts.length === 0) {
console.log("No new posts to sync");
return;
}
// 4. Bulk create (batches of 100)
const items = newPosts.map(p => ({
isDraft: false,
fieldData: {
name: p.title,
slug: slugify(p.title),
"post-body": p.body,
"publish-date": p.publishedAt,
},
}));
const created = await webflow.collections.items.createItemsBulk(
collection.id!,
{ items: items.slice(0, 100) }
);
// 5. Publish the new items
const newIds = created.items!.map(i => i.id!);
await webflow.collections.items.publishItem(collection.id!, {
itemIds: newIds,
});
console.log(`Synced and published ${newIds.length} new posts`);
}
function slugify(text: string): string {
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
}
| Error | Cause | Solution |
|---|---|---|
400 Bad Request | Invalid field data or missing required fields | Check collection schema for required fields |
404 Not Found | Wrong collection_id or item_id | List collections first with collections.list() |
409 Conflict | Duplicate slug in collection | Use unique slugs or add suffix |
429 Too Many Requests | Rate limit exceeded | SDK auto-retries; for bulk, add delays between batches |
| Site publish 429 | >1 publish/minute | Wait 60s between site publishes |
For site, page, and ecommerce management, see webflow-core-workflow-b.