← 返回
未分类 Key 中文

Framer CRM API

Framer CMS management via the Server API — list, create, read, update, and delete CMS collections and items, upload images, publish previews, deploy to produ...
使用服务器 API 管理 Framer CMS——列出、创建、读取、更新和删除 CMS 集合和条目,上传图片,发布预览,部署到生产环境
berthelol
未分类 clawhub v1.0.1 1 版本 100000 Key: 需要
★ 1
Stars
📥 356
下载
💾 0
安装
1
版本
#latest

概述

Framer CMS — Server API Skill

Manage Framer CMS content programmatically via the framer-api npm package. Push articles, upload images, create collections, and publish/deploy — all from the terminal, no Framer app needed.

First-time setup (onboarding)

If this is the first time the user uses this skill in a project, run the onboarding flow described in references/onboarding.md.

Quick check: Look for FRAMER_PROJECT_URL and FRAMER_API_KEY in the user's .env file or environment. If missing, onboard.


How it works

This skill uses the Framer Server API (framer-api npm package) which connects to Framer projects via WebSocket using an API key. It provides full CMS CRUD, image uploads, publishing, and deployment.

Important: The framer-api package must be installed in the project. If not present, run:

npm i framer-api

All operations use ES module scripts (.mjs files) with this connection pattern:

import { connect } from "framer-api"

// IMPORTANT: API key is passed as a plain string (2nd argument), NOT as {apiKey: "..."}
const framer = await connect(process.env.FRAMER_PROJECT_URL, process.env.FRAMER_API_KEY)
try {
  // ... operations ...
} finally {
  await framer.disconnect()
}

Available operations

CMS Collections

OperationMethodNotes
--------------------------
List collectionsframer.getCollections()Returns all CMS collections
Get one collectionframer.getCollection(id)By collection ID
Create collectionframer.createCollection(name)Creates empty collection
Get fieldscollection.getFields()Field definitions (name, type, id)
Add fieldscollection.addFields([{type, name}])Add new fields to collection
Remove fieldscollection.removeFields([fieldId])Delete fields by ID
Reorder fieldscollection.setFieldOrder([fieldIds])Set field display order

CMS Items (articles, entries)

OperationMethodNotes
--------------------------
List itemscollection.getItems()All items with field data
Create itemscollection.addItems([{slug, fieldData}])Create new items. Returns undefined — re-fetch with getItems() to get IDs
Update item fieldsitem.setAttributes({ fieldData: { [fieldId]: {type, value} } })MUST wrap in fieldData: — without it, values are silently ignored
Update item slug/draftitem.setAttributes({ slug: "new", draft: false })Slug and draft are set directly (NOT inside fieldData)
Delete itemitem.remove()Single item
Bulk deletecollection.removeItems([itemIds])Multiple items
Reorder itemscollection.setItemOrder([itemIds])Set display order

⚠️ Critical: How to update CMS item fields

The setAttributes method has a non-obvious API design — field values MUST be wrapped in a fieldData key:

// ✅ CORRECT — fields wrapped in fieldData
await item.setAttributes({
  fieldData: {
    [titleFieldId]: { type: "string", value: "New Title" }
  }
})

// ❌ WRONG — silently ignored, no error thrown
await item.setAttributes({
  [titleFieldId]: { type: "string", value: "New Title" }
})

// ❌ WRONG — also silently ignored
await item.setAttributes({
  [titleFieldId]: "New Title"
})

Partial updates work: Only specified fields are changed. Other fields are preserved.

Non-field attributes (slug, draft) go directly on the object, NOT inside fieldData:

await item.setAttributes({ slug: "new-slug", draft: false })

Field data format

When creating/updating items, field data is keyed by field ID (not name):

const fields = await collection.getFields()
const titleField = fields.find(f => f.name === "Title")

await collection.addItems([{
  slug: "my-article",
  fieldData: {
    [titleField.id]: { type: "string", value: "My Article Title" },
  }
}])

Supported field types and their value format:

TypeValue formatExample
----------------------------
stringstring{ type: "string", value: "Hello" }
numbernumber{ type: "number", value: 42 }
booleanboolean{ type: "boolean", value: true }
datestring (UTC ISO){ type: "date", value: "2026-04-06T00:00:00Z" }
formattedTextstring (HTML){ type: "formattedText", value: "

Title

Text

" }
linkstring (URL){ type: "link", value: "https://example.com" }
imageImageAsset objectSee image upload section
enumstring (case name){ type: "enum", value: "Published" }
colorstring (hex/rgba){ type: "color", value: "#FF0000" }
fileFileAsset objectSimilar to image
collectionReferencestring (item ID){ type: "collectionReference", value: "itemId123" }
multiCollectionReferencestring[]{ type: "multiCollectionReference", value: ["id1","id2"] }

Images

Upload images from public URLs, then use the returned asset in CMS items:

const asset = await framer.uploadImage("https://example.com/photo.jpg")
// asset = { id, url, thumbnailUrl }

await item.setAttributes({
  fieldData: {
    [thumbnailField.id]: { type: "image", value: asset.url }
  }
})

Publishing & deployment

// Create a preview deployment
const result = await framer.publish()
// result = { deployment: { id }, hostnames: [...] }

// Promote preview to production
await framer.deploy(result.deployment.id)

Always ask the user before deploying to production. Publishing a preview is safe; deploying is live.

Project info & changes

await framer.getProjectInfo()       // { id, name, apiVersion1Id }
await framer.getCurrentUser()       // { id, name, avatar }
await framer.getPublishInfo()       // Current deployment status
await framer.getChangedPaths()      // { added, removed, modified }
await framer.getChangeContributors() // Contributor UUIDs
await framer.getDeployments()       // All deployment history

Other operations

OperationMethodNotes
--------------------------
Color stylesgetColorStyles(), createColorStyle()Design tokens
Text stylesgetTextStyles(), createTextStyle()Typography tokens
Code filesgetCodeFiles(), createCodeFile(name, code)Custom code overrides
Custom codegetCustomCode()Head/body code injection
FontsgetFonts()Project fonts
LocalesgetLocales(), getDefaultLocale()i18n
PagescreateWebPage(path), removeNode(id)Page management
Screenshotsscreenshot(nodeId, options)PNG buffer of any node
RedirectsaddRedirects([{from, to}])Requires paid plan
Node treegetNode(id), getChildren(id), getParent(id)DOM traversal

Common workflows

Push a new article to CMS

See references/cms-operations.md for the full pattern including field resolution, image upload, and error handling.

Bulk update articles

const items = await collection.getItems()
for (const item of items) {
  await item.setAttributes({
    fieldData: {
      [metaField.id]: { type: "string", value: generateMeta(item) }
    }
  })
}

Publish after CMS changes

const changes = await framer.getChangedPaths()
if (changes.added.length || changes.modified.length || changes.removed.length) {
  const result = await framer.publish()
  console.log("Preview:", result.hostnames)
  // Ask user before: await framer.deploy(result.deployment.id)
}

Important notes

  • API key scope: Each key is bound to one project. For multiple Framer sites, store multiple keys.
  • WebSocket connection: The connect() call opens a persistent WebSocket. Always call disconnect() when done, or use using framer = await connect(...) for auto-cleanup.
  • Field IDs, not names: CMS operations use field IDs. Always call getFields() first and resolve names to IDs.
  • Image fields: Pass the full framerusercontent.com URL from uploadImage(), not the asset ID.
  • Proxy methods: Most methods (getCollections, publish, etc.) are proxied — they don't appear in Object.keys(framer) but work correctly.
  • Rate limits: No documented rate limits, but avoid hammering. Add small delays for bulk operations (100+ items).
  • formattedText fields: Accept standard HTML (h1-h6, p, ul, ol, li, a, strong, em, img, blockquote, pre, code, table, etc.).
  • Draft items: Items can have draft: true — drafts are excluded from publishing.
  • Blog Posts collection: Collections managed by "thisPlugin" are read-only via the API. Only "user" managed collections can be modified.

版本历史

共 1 个版本

  • v1.0.1 当前
    2026-05-07 06:36 安全 安全

安全检测

腾讯云安全 (Keen)

安全,无风险
查看报告

腾讯云安全 (Sanbu)

安全,无风险
查看报告

🔗 相关推荐

content-creation

Scrapping

berthelol
当用户想要获取、抽取或查询社交媒体平台的公开数据(如个人资料、帖子、视频、评论、粉丝等)时使用此技能。
★ 1 📥 676

Gleap

berthelol
Gleap REST API 集成,用于客户支持分析和工单管理。当用户请求获取支持工单、分析客户支持指标时使用。
★ 1 📥 371

Infographic creator socials

berthelol
使用 OpenAI gpt-image-2 生成现代操作员风格的社交媒体信息图(Twitter、LinkedIn、Instagram)。当用户想要...时使用此技能。
★ 0 📥 407