← Back to Skills Marketplace
berthelol

Framer CRM API

by berthelol · GitHub ↗ · v1.0.1 · MIT-0
cross-platform ✓ Security Clean
124
Downloads
1
Stars
0
Active Installs
2
Versions
Install in OpenClaw
/install framer-crm-api
Description
Framer CMS management via the Server API — list, create, read, update, and delete CMS collections and items, upload images, publish previews, deploy to produ...
README (SKILL.md)

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

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

CMS Items (articles, entries)

Operation Method Notes
List items collection.getItems() All items with field data
Create items collection.addItems([{slug, fieldData}]) Create new items. Returns undefined — re-fetch with getItems() to get IDs
Update item fields item.setAttributes({ fieldData: { [fieldId]: {type, value} } }) MUST wrap in fieldData: — without it, values are silently ignored
Update item slug/draft item.setAttributes({ slug: "new", draft: false }) Slug and draft are set directly (NOT inside fieldData)
Delete item item.remove() Single item
Bulk delete collection.removeItems([itemIds]) Multiple items
Reorder items collection.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:

Type Value format Example
string string { type: "string", value: "Hello" }
number number { type: "number", value: 42 }
boolean boolean { type: "boolean", value: true }
date string (UTC ISO) { type: "date", value: "2026-04-06T00:00:00Z" }
formattedText string (HTML) { type: "formattedText", value: "\x3Ch2>Title\x3C/h2>\x3Cp>Text\x3C/p>" }
link string (URL) { type: "link", value: "https://example.com" }
image ImageAsset object See image upload section
enum string (case name) { type: "enum", value: "Published" }
color string (hex/rgba) { type: "color", value: "#FF0000" }
file FileAsset object Similar to image
collectionReference string (item ID) { type: "collectionReference", value: "itemId123" }
multiCollectionReference string[] { 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

Operation Method Notes
Color styles getColorStyles(), createColorStyle() Design tokens
Text styles getTextStyles(), createTextStyle() Typography tokens
Code files getCodeFiles(), createCodeFile(name, code) Custom code overrides
Custom code getCustomCode() Head/body code injection
Fonts getFonts() Project fonts
Locales getLocales(), getDefaultLocale() i18n
Pages createWebPage(path), removeNode(id) Page management
Screenshots screenshot(nodeId, options) PNG buffer of any node
Redirects addRedirects([{from, to}]) Requires paid plan
Node tree getNode(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.
Usage Guidance
This skill appears to be what it says: a Framer Server API helper. Before installing or running it, consider the following: 1) The skill's source/homepage is not provided — verify you trust the publisher before giving it access to project credentials. 2) It will ask you for FRAMER_PROJECT_URL and FRAMER_API_KEY and may write them into the local project's .env; ensure .env is in .gitignore and avoid committing secrets to version control. 3) The skill instructs running 'npm i framer-api' — review the 'framer-api' npm package (maintainer, downloads, code) yourself before installing. 4) Require the agent to prompt you for confirmation before performing impactful actions (publish/deploy, deletes, bulk operations). 5) Where possible create an API key with limited scope for automation and rotate/revoke keys if you stop using the skill. If you want higher assurance, ask the publisher for provenance (homepage, repo link) or prefer a skill whose source code you can audit.
Capability Analysis
Type: OpenClaw Skill Name: framer-crm-api Version: 1.0.1 The skill provides a legitimate and well-documented interface for managing Framer CMS content and site deployment via the official `framer-api` npm package. It includes a structured onboarding flow in `references/onboarding.md` that handles sensitive credentials (`FRAMER_API_KEY`) responsibly by instructing the agent to store them in a `.env` file and ensuring that file is added to `.gitignore`. The instructions in `SKILL.md` and the reference files are consistent with the stated purpose and include safety checks, such as requiring user confirmation before production deployments.
Capability Assessment
Purpose & Capability
Name/description, required binaries (node, npm), and required env vars (FRAMER_PROJECT_URL, FRAMER_API_KEY) align with the stated Framer Server API CMS management purpose. Asking to install the 'framer-api' npm package is expected.
Instruction Scope
SKILL.md instructs the agent to read the user's environment or .env file and, during onboarding, to append credentials to the project's .env and run npm install/init. These actions are within scope for a CMS automation skill, but they involve reading and writing a credentials file and installing packages in the user's project — the user should confirm these operations and ensure secrets are handled safely. The skill explicitly warns to confirm before deploy, which is good.
Install Mechanism
This is an instruction-only skill (no install spec). The only install action described is running 'npm i framer-api' in the project, which is standard and traceable to npm. No arbitrary downloads or extract-from-URL steps are present in the skill instructions.
Credentials
The only required environment variables are FRAMER_PROJECT_URL and FRAMER_API_KEY (the primary credential). These are proportional to a skill that connects to a Framer project. The onboarding flow also appropriately recommends storing keys in .env and checking .gitignore.
Persistence & Privilege
Skill flags show no forced persistence (always: false) and normal autonomous invocation settings. The skill's runtime instructions write only to the project's .env and optionally install a package; it does not request system-wide configuration or modify other skills.
How to Use
  1. Make sure OpenClaw is installed (local or Docker)
  2. Run the install command in chat: /install framer-crm-api
  3. After installation, invoke the skill by name or use /framer-crm-api
  4. Provide required inputs per the skill's parameter spec and get structured output
Version History
v1.0.1
**Critical corrections and clarification for CMS field updates.** - Updated documentation to clarify that when using `item.setAttributes` to update CMS item fields, all field values must be wrapped in a `fieldData` object. Not wrapping causes updates to be silently ignored. - Added clear examples of correct and incorrect usage of `setAttributes`. - Clarified that non-field properties (like slug, draft) must be set directly, not inside `fieldData`. - Minor adjustments for accuracy in update/create CMS item workflows. - No code changes; documentation and usage guidance only.
v1.0.0
Initial release of framer-cms skill for managing Framer CMS content and deployments via the Server API. - Supports listing, creating, reading, updating, and deleting CMS collections and items. - Enables image uploads, site preview publishing, production deployment, and project asset management — all without opening Framer. - Onboards users automatically if Framer API credentials are missing. - Designed to automate Framer CMS workflows such as pushing articles, syncing content, and managing collections programmatically. - Clearly distinguishes from Framer design/animation tasks; strictly focused on CMS/content API automation.
Metadata
Slug framer-crm-api
Version 1.0.1
License MIT-0
All-time Installs 0
Active Installs 0
Total Versions 2
Frequently Asked Questions

What is 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... It is an AI Agent Skill for Claude Code / OpenClaw, with 124 downloads so far.

How do I install Framer CRM API?

Run "/install framer-crm-api" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.

Is Framer CRM API free?

Yes, Framer CRM API is completely free, licensed under MIT-0. You can download, install and use it at no cost.

Which platforms does Framer CRM API support?

Framer CRM API is cross-platform and runs anywhere OpenClaw / Claude Code is available (cross-platform).

Who created Framer CRM API?

It is built and maintained by berthelol (@berthelol); the current version is v1.0.1.

💬 Comments