Claude-code-plugins-plus-skills webflow-hello-world
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/webflow-pack/skills/webflow-hello-world" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-skills-webflow-hello-world && rm -rf "$T"
manifest:
plugins/saas-packs/webflow-pack/skills/webflow-hello-world/SKILL.mdsource content
Webflow Hello World
Overview
Minimal working examples demonstrating the three core Webflow Data API v2 operations: listing sites, reading CMS collections/items, and creating a CMS item.
Prerequisites
- Completed
setupwebflow-install-auth
package installedwebflow-api- Valid API token with
andsites:read
scopescms:read
Instructions
Step 1: List Your Sites
Every Webflow API call starts with a
site_id. List your sites to find it:
// hello-webflow.ts import { WebflowClient } from "webflow-api"; const webflow = new WebflowClient({ accessToken: process.env.WEBFLOW_API_TOKEN!, }); async function listSites() { const { sites } = await webflow.sites.list(); for (const site of sites!) { console.log(`${site.displayName}`); console.log(` ID: ${site.id}`); console.log(` Short name: ${site.shortName}`); console.log(` Custom domains: ${site.customDomains?.map(d => d.url).join(", ")}`); console.log(` Last published: ${site.lastPublished}`); console.log(` Locales: ${site.locales?.map(l => l.displayName).join(", ")}`); } } listSites().catch(console.error);
Step 2: List CMS Collections
Collections define your content types (blog posts, team members, products, etc.):
async function listCollections(siteId: string) { const { collections } = await webflow.collections.list(siteId); for (const col of collections!) { console.log(`Collection: ${col.displayName}`); console.log(` ID: ${col.id}`); console.log(` Slug: ${col.slug}`); console.log(` Item count: ${col.itemCount}`); console.log(` Fields:`); for (const field of col.fields || []) { console.log(` - ${field.displayName} (${field.type}, required: ${field.isRequired})`); } } } // Usage: pass your site_id listCollections("your-site-id").catch(console.error);
Step 3: Read CMS Items
Fetch items from a collection — staged (draft) or live (published):
async function readItems(collectionId: string) { // Get staged (draft + published) items const { items } = await webflow.collections.items.listItems(collectionId, { limit: 10, offset: 0, }); for (const item of items!) { console.log(`Item: ${item.fieldData?.name || item.id}`); console.log(` ID: ${item.id}`); console.log(` Slug: ${item.fieldData?.slug}`); console.log(` Draft: ${item.isDraft}`); console.log(` Archived: ${item.isArchived}`); console.log(` Created: ${item.createdOn}`); } // Get live (published) items only const live = await webflow.collections.items.listItemsLive(collectionId, { limit: 10, }); console.log(`\nLive items: ${live.items?.length}`); }
Step 4: Create a CMS Item
async function createBlogPost(collectionId: string) { // Items are created as drafts by default (isDraft: true) const item = await webflow.collections.items.createItem(collectionId, { fieldData: { name: "Hello from the API", slug: "hello-from-api", // Field names must match your collection schema // Use the slug version of field names (lowercase, hyphens) "post-body": "<p>This post was created via the Webflow Data API v2.</p>", "author": "API Bot", "published-date": new Date().toISOString(), }, isDraft: false, // Set false to stage for publishing }); console.log(`Created item: ${item.id}`); console.log(` Draft: ${item.isDraft}`); console.log(` Slug: ${item.fieldData?.slug}`); return item; }
Step 5: Complete Hello World Script
import { WebflowClient } from "webflow-api"; const webflow = new WebflowClient({ accessToken: process.env.WEBFLOW_API_TOKEN!, }); async function main() { // 1. Get first site const { sites } = await webflow.sites.list(); const site = sites![0]; console.log(`Using site: ${site.displayName} (${site.id})\n`); // 2. List collections const { collections } = await webflow.collections.list(site.id!); console.log(`Found ${collections!.length} collections:`); for (const col of collections!) { console.log(` - ${col.displayName} (${col.itemCount} items)`); } // 3. Read items from first collection if (collections!.length > 0) { const firstCol = collections![0]; const { items } = await webflow.collections.items.listItems(firstCol.id!, { limit: 5, }); console.log(`\nFirst ${items!.length} items in "${firstCol.displayName}":`); for (const item of items!) { console.log(` - ${item.fieldData?.name} (${item.id})`); } } console.log("\nWebflow connection verified successfully."); } main().catch(console.error);
Run it:
npx tsx hello-webflow.ts
Output
- Console listing of all accessible sites with IDs
- Collection schemas with field types
- CMS item data (draft and live)
- Success confirmation:
Webflow connection verified successfully.
Error Handling
| Error | Cause | Solution |
|---|---|---|
| Bad token | Re-check token at developers.webflow.com |
| Missing scope | Add scope to token or app |
| Wrong or | List sites first to get valid IDs |
| Rate limited | Wait 60s (Retry-After header) |
Empty array | Token has no site access | Check workspace token permissions |
Key Concepts
- site_id: Every API call is scoped to a site. Get it from
.sites.list() - collection_id: CMS collections hold typed content. Get IDs from
.collections.list(siteId) - fieldData: Item fields use the slug form of field names (e.g.,
, notpost-body
).Post Body - isDraft: New items default to
. SetisDraft: true
to stage for publishing.false - Staged vs Live:
returns all items;listItems()
returns only published.listItemsLive()
Resources
Next Steps
Proceed to
webflow-local-dev-loop for development workflow setup.