publish-webflow
Skill1 starsChanged 7 months agoMITView on GitHub
Use when the user wants to publish a blog post draft to Webflow CMS via the Webflow API v2. Reads a markdown draft, maps frontmatter to CMS fields, creates or updates the CMS item, and optionally publishes it live.
In this repository14 other files it gives its agents.
- blog-postSkill
- competitor-analysisSkill
- content-briefSkill
- content-calendarSkill
- content-marketingSkill
- editorial-guidelinesSkill
- email-copySkill
- landing-page-copySkill
- proofreading-style-checkSkill
- publish-wordpressSkill
- repurpose-linkedin-carouselSkill
- repurpose-threads-xSkill
- seo-auditSkill
- social-postSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
19 rules. About 0 are common, 7 are distinctive, and 12 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈7
Distinctive · estimate
This author's own choices. Worth a look.
12
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 37
Use AskUserQuestion for mode and existing-item handling.
- Very specific: line 43
Call GET /v2/collections/{WEBFLOW_COLLECTION_ID} and cache the field list.
- Distinctive: line 61
If the user provides a custom mapping file, it overrides the defaults.
- Distinctive: line 65
Read the draft file.
- Very specific: line 69
If hero_image is a local path, upload via the Webflow 2-step asset flow:
- Distinctive: line 72
If it's already a URL, use it directly.
- Very specific: line 79
If found and mode is skip → stop and report.
- Very specific: line 80
If found and mode is update → PATCH /v2/collections/{collection_id}/items/{item_id} with the new field values.
- Very specific: line 81
If found and mode is create-new → append a timestamp to the slug, then create.
- Distinctive: line 82
If not found → create.
- Very specific: line 98
Create live (mode = live, single call): use POST /v2/collections/{collection_id}/items/live with the same body and isDraft: false.
- Very specific: line 114
New item: use the POST /v2/collections/{collection_id}/items/live create-live endpoint above in step 4 instead of the staged create.
- Very specific: line 128
Ask via AskUserQuestion the first time a publish runs in a session.
- Very specific: line 132
If SLACK_WEBHOOK_URL is set and publish was successful:
- Distinctive: line 157
Image upload fails: ask the user to upload manually via Webflow and retry.
- Distinctive: line 158
Site publish rate limited: create/update the item anyway, skip the site publish, and note it in the log so the user can publish manually …
- Very specific: line 162
Default mode is draft. This skill never publishes live without explicit user confirmation in the current session.
- Very specific: line 163
Never delete existing items.
- Distinctive: line 169
If mode = live, the public URL returns 200.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Publish → Webflow
Publish a local markdown draft to Webflow CMS using the Webflow Data API v2.
Setup
Required:
WEBFLOW_API_TOKEN— a Data API token (Site Settings → Apps & Integrations → API Access). Scopes needed:cms:read,cms:write,sites:read, and (if publishing live)sites:write.WEBFLOW_SITE_ID— the site ID. Get it viaGET https://api.webflow.com/v2/sites.WEBFLOW_COLLECTION_ID— the collection ID for your blog. Get it viaGET /v2/sites/{site_id}/collections.
Optional:
SLACK_WEBHOOK_URL— Slack notification when a post goes live.
All requests use:
Authorization: Bearer ${WEBFLOW_API_TOKEN}
accept-version: 2.0.0
Content-Type: application/jsonInputs
- Draft path — markdown file under
posts/. - Mode —
draft(create as unpublished) orlive(create and publish). Defaultdraft. - Update existing? — if an item with the same slug exists,
skip,update, orcreate-new. Defaultupdate. - Field mapping override — optional: path to a JSON file mapping markdown frontmatter keys to Webflow field slugs. Default mapping is documented below.
Use AskUserQuestion for mode and existing-item handling.
Process
1. Validate collection schema
Call GET /v2/collections/{WEBFLOW_COLLECTION_ID} and cache the field list. For each required frontmatter field, confirm there's a matching Webflow field. If a field is missing, fail fast with a clear error naming which Webflow field to add.
Default frontmatter → Webflow field mapping:
| Frontmatter key | Webflow field slug | Type |
title | name | PlainText |
slug | slug | PlainText |
meta_title | meta-title | PlainText |
meta_description | meta-description | PlainText |
author | author | Reference (fallback PlainText) |
date | published-on | Date |
hero_image | hero-image | Image |
hero_alt | hero-alt | PlainText |
keyword | primary-keyword | PlainText |
status | — | (ignored; controlled by publish mode) |
| body | post-body | RichText |
If the user provides a custom mapping file, it overrides the defaults.
2. Load and transform the draft
- Read the draft file.
- Parse frontmatter.
- Convert the markdown body to Webflow-compatible HTML (rich text field accepts HTML). Preserve: headings, paragraphs, lists, code blocks, blockquotes, images, internal and external links. Strip any HTML comments.
- For the hero image:
- If
hero_imageis a local path, upload via the Webflow 2-step asset flow:POST /v2/sites/{site_id}/assetswith{ "fileName": "...", "fileHash": "<md5>" }. Response containsuploadUrlanduploadDetails(S3 presigned fields).- POST the file as multipart/form-data to
uploadUrl, including every field fromuploadDetailsbefore thefilefield. Use the returned assethostedUrlinfieldData.
- If it's already a URL, use it directly.
- If
- For author as a reference field: resolve the name to an author collection item ID via
GET /v2/collections/{authors_collection}/items?name={author}. If not found, create the author item (or fall back to PlainText if the field allows).
3. Check for existing item
GET /v2/collections/{WEBFLOW_COLLECTION_ID}/items?slug={slug}
- If found and mode is
skip→ stop and report. - If found and mode is
update→PATCH /v2/collections/{collection_id}/items/{item_id}with the new field values. - If found and mode is
create-new→ append a timestamp to the slug, then create. - If not found → create.
4. Create or update
Create (staged / draft):
POST /v2/collections/{WEBFLOW_COLLECTION_ID}/items
{
"isArchived": false,
"isDraft": <true if mode=draft else false>,
"fieldData": { ...mapped fields }
}For bulk creates (multiple posts at once), use POST /v2/collections/{collection_id}/items/bulk with { "items": [...] }. As of Dec 2024 newly-created items default to isDraft: true unless the live endpoint is used.
Create live (mode = live, single call): use POST /v2/collections/{collection_id}/items/live with the same body and isDraft: false. This creates and publishes in one shot.
Update:
PATCH /v2/collections/{WEBFLOW_COLLECTION_ID}/items/{item_id}
{
"fieldData": { ...mapped fields }
}Handle the response: capture id (item ID), lastUpdated, and the fieldData.slug.
5. Publish live (if mode = live)
There is no per-item "promote to live" endpoint in the Data API v2. Options:
- New item: use the
POST /v2/collections/{collection_id}/items/livecreate-live endpoint above in step 4 instead of the staged create. - Existing staged item: PATCH the item with
isDraft: falseviaPATCH /v2/collections/{collection_id}/items/{item_id}/live(the/livebulk-publish path accepts an item list) — or publish the entire site, which flushes all staged items.
Then publish the site so any staged changes are visible:
POST /v2/sites/{WEBFLOW_SITE_ID}/publish
{ "publishToWebflowSubdomain": false, "customDomains": [...] }Or if the user only wants the staging subdomain:
{ "publishToWebflowSubdomain": true }Ask via AskUserQuestion the first time a publish runs in a session.
6. Optional Slack notification
If SLACK_WEBHOOK_URL is set and publish was successful:
POST ${SLACK_WEBHOOK_URL}
Content-Type: application/json
{ "text": "📤 New post published: <{live URL}|{title}>" }7. Write a publish log
Append a line to publish-log.md at the project root:
| {YYYY-MM-DD HH:mm} | webflow | {mode} | {title} | {item_id} | {live URL or "—"} | {status} |8. Print summary
One block: mode, item ID, live URL (if live), Slack notified (Y/N), publish-log updated.
Fallbacks
- Missing required env var: fail fast with the exact variable name.
- Collection schema mismatch: print the missing field names and the expected types; do not guess.
- Image upload fails: ask the user to upload manually via Webflow and retry; don't create the item without the hero if the field is required.
- Site publish rate limited: create/update the item anyway, skip the site publish, and note it in the log so the user can publish manually from the Webflow dashboard.
Safety
- Default mode is
draft. This skill never publishes live without explicit user confirmation in the current session. - Never delete existing items. If a collision happens in
skipmode, stop and report.
Verification
- Item exists in the target collection (
GET /items/{id}returns 200). fieldDatacontains all mapped fields with expected values.- If mode = live, the public URL returns 200.
publish-log.mdhas a new row.- Slack notification delivered (if configured).
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

