CMS Data
CMS Data action allows you to fetch and retrieve data from Webflow CMS collections within your workflows. This action is designed for reading CMS content and making it available to subsequent actions in your workflow.
Overview

The CMS Data action connects to your Webflow site's CMS collections and retrieves items based on your configuration. Unlike CMS Data Sync which writes data back to Webflow, this action is focused on reading and consuming CMS content.
Configuration
Site Selection
The action automatically uses your connected Webflow site. Ensure you have proper permissions to access the CMS collections you want to read from.
Collection Settings
Collection: Select the CMS collection you want to fetch data from. The dropdown will show all available collections in your connected Webflow site.
Live Publish:
Enabled - Fetches data from your live, published site
Disabled - Fetches data from your staging/draft site

Choose based on whether you need the most current published content or if you're working with draft content.
Data Expression
The Expression field allows you to write JavaScript code that processes the retrieved CMS data. Within this expression, you have access to:
items- Array of CMS collection itemsctx- Context object from previous actionsslug()- Utility function to create URL-safe slugs
Working with CMS Data
Accessing Collection Items
CMS collection items are available in the items variable within your expression:
// Access all items
items
// Get the first item
items[0]
// Filter items by a field
items.filter(item => item.fieldData.status === 'published')
// Sort items by date
items.sort((a, b) => new Date(b.fieldData.dateCreated) - new Date(a.fieldData.dateCreated))Data Structure
Each item in the items array has the following structure:
ctx.cmsItems = [
{
id: "collection_item_id",
fieldData: {
name: "Item Name",
slug: "item-slug",
// ... your custom CMS fields
},
_archived: false,
_draft: false
},
// ... more items
]Expression Examples
Here are common patterns for working with CMS data:
// Store all items for next actions
ctx.allItems = items
// Filter and store specific items
ctx.publishedPosts = items.filter(item => item.fieldData.status === 'published')
// Get the latest 5 items
ctx.recentItems = items
.sort((a, b) => new Date(b.fieldData.dateCreated) - new Date(a.fieldData.dateCreated))
.slice(0, 5)
// Create a lookup map by ID
ctx.itemsById = {}
items.forEach(item => {
ctx.itemsById[item.id] = item
})
// Extract specific field values
ctx.itemNames = items.map(item => item.fieldData.name)
// Filter based on previous action data
ctx.categoryItems = items.filter(item =>
item.fieldData.category === ctx.selectedCategory
)
// Count items by status
ctx.statusCounts = items.reduce((counts, item) => {
const status = item.fieldData.status || 'draft'
counts[status] = (counts[status] || 0) + 1
return counts
}, {})Accessing Field Data
CMS fields are accessible via the fieldData object. The available fields depend on your specific CMS collection structure:
// Text field
item.fieldData.title
// Rich text field (HTML)
item.fieldData.description
// Number field
item.fieldData.count
// Boolean field
item.fieldData.featured
// Date field
item.fieldData.publishDate
// Image field
item.fieldData.featuredImage
// Reference field (single)
item.fieldData.category
// Multi-reference field (array)
item.fieldData.tagsNote: The actual field names depend on your CMS collection structure. Common fields include name, slug, dateCreated, and dateUpdated, but your collection may have different field names.
Using the Slug Utility
The slug() function creates URL-safe slugs from text:
// Create slugs from names
ctx.itemSlugs = items.map(item => ({ id: item.id, name: item.fieldData.name, slug: slug(item.fieldData.name) }))
// Use existing slug or create one
ctx.processedItems = items.map(item => ({ ...item, finalSlug: item.fieldData.slug || slug(item.fieldData.name) }))Use Cases
Populating Reference Fields
The primary use case for CMS Data action is populating reference and multi-reference fields in other CMS collections:
// Get single item ID for reference field
ctx.selectedCategoryId = items.find(item => item.fieldData.name === 'Featured').id
// Get array of item IDs for multi-reference field
ctx.tagIds = items
.filter(item => item.fieldData.status === 'active')
.map(item => item.id)
// Get specific items by criteria for references
ctx.authorIds = items
.filter(item => item.fieldData.role === 'author')
.map(item => item.id)Content Aggregation
// Collect all blog posts for processing
ctx.blogPosts = items.filter(item => item.fieldData.type === 'blog')Data Validation
// Check for items with missing required fields
ctx.incompleteItems = items.filter(item => !item.fieldData.title || !item.fieldData.description )Dynamic Workflows
// Set different processing paths based on item count
ctx.processingMode = items.length > 100 ? 'batch' : 'individual'Reporting
// Generate content statistics
ctx.contentStats = {
total: items.length,
published: items.filter(i => i.fieldData.status === 'published').length,
draft: items.filter(i => i.fieldData.status === 'draft').length,
archived: items.filter(i => i._archived).length
}Data Transformation
// Transform data for external API
ctx.apiPayload = items.map(item => ({
external_id: item.id,
title: item.fieldData.name,
content: item.fieldData.description,
published: item.fieldData.status === 'published'
}))Best Practices
Performance Optimization
Filter early: Apply filters to reduce data processing
Limit results: Use
.slice()to work with smaller datasets when possibleAvoid deep processing: Keep complex operations minimal for large collections
Data Handling
Check for existence: Always verify fields exist before accessing them
Handle empty collections: Check
items.length > 0before processingPreserve original data: Store original items if you need them later
Context Management
// Good: Store processed data for next actions
ctx.processedItems = items.map(item => ({ id: item.id, name: item.fieldData.name, status: item.fieldData.status }))
// Good: Create summary data
ctx.itemCount = items.length
ctx.publishedCount = items.filter(item => item.fieldData.status === 'published').lengthError Handling
Common Issues and Solutions
Empty Results
// Check if data was retrieved
if (items.length === 0) {
ctx.warning = "No items found in collection"
return
}Missing Fields
// Safely access potentially missing fields
ctx.safeItems = items.map(item => ({ id: item.id, name: item.fieldData.name || 'Untitled', description: item.fieldData.description || '', status: item.fieldData.status || 'draft' }))Type Safety
// Ensure numeric fields are numbers
ctx.validNumbers = items.filter(item => typeof item.fieldData.count === 'number').map(item => item.fieldData.count)Expression Requirements
Your expression must:
Process the
itemsarray as neededStore results in the
ctxobject for next actionsNot explicitly return anything (the system returns
{ ctx: ctx }automatically)
The processed context data will be available to all subsequent actions in your workflow.
Last updated