--- name: clickfunnels-page-markup description: > Reference for PML (Page Markup Language), the XML-like DSL that ClickFunnels 2.0 uses to describe page content. Read this skill when authoring or editing markup for any surface that accepts a `markup` field - currently pages and blog posts. Writing `markup` replaces the entire page and PML covers only a subset of what the ClickFunnels editor can build, so read the approval guardrail before touching a page that already exists. This is a language reference; for the HTTP APIs that consume it, see the Pages Skill (for funnel/site pages) or the Blogs Skill (for blog posts). version: "1.0" author: ClickFunnels tools: [] references: - path: https://accounts.myclickfunnels.com/llms.txt description: Quick-reference index - product overview, login, funnels, broadcasts, API docs. - path: https://accounts.myclickfunnels.com/.well-known/pages/skill.md description: The Pages API - read this for authentication, the page CRUD endpoints, and the checkout-products attachment shape. - path: https://accounts.myclickfunnels.com/.well-known/blogs/skill.md description: The Blogs API - read this to create or update blog posts whose body is PML. - path: https://accounts.myclickfunnels.com/.well-known/funnels/skill.md description: Funnel workflow APIs (split tests, conditional splits) that compose pages built with this DSL. --- # ClickFunnels Page Markup Language (PML) PML is an XML-like DSL compiled by the CF2 page engine into the full page tree the editor renders. It is the canonical authoring format for both funnel/site pages (via the Pages API) and blog posts (via the Blogs API). This document is a **language reference** - elements, attributes, design system, patterns, common errors. It contains no HTTP details. For that, follow the references above. ## When to read this skill - Authoring markup for a new page or blog post from scratch - Editing existing markup returned by `expand[]=markup` on any surface - Debugging a `400 Markup is not valid PML` response - Designing a new conversion-oriented page and choosing fonts, colors, gradients - Composing a multi-section page that follows CF2's design system ## STOP: get approval before overwriting an existing page PML covers a subset of what the ClickFunnels page editor can build. Four properties of that subset make writing `markup` to an existing page dangerous: - **Reading is lossy.** `expand[]=markup` runs the stored page through a serializer that has an equivalent for the elements documented in this skill and nothing else. Any other element the editor supports is dropped from the string you get back: the element, its settings and its styling are simply absent. There is no error, no warning, and no placeholder marking the hole. - **An empty read does not mean an empty page.** Because dropped elements leave no trace, a page built entirely from elements PML cannot express reads back as an empty string. `""` is therefore not evidence that the page is blank, and it is not a reason to skip the approval below. - **A failed read looks like content.** If the read comes back as ``, the serializer could not handle the page at all. Treat the page as unreadable and do not write. Sending that string back replaces the page with nothing. - **Writing replaces everything.** Sending `markup` rebuilds the page from your string and overwrites both the published page and the draft the editor opens. Nothing is merged, and there is no partial write. Put together, a read-modify-write cycle on a page a person built in the editor silently destroys whatever PML could not express, in the live page and in the editor, and the API cannot put it back. **The rule:** if the page or post could have been created or edited in the ClickFunnels editor, STOP and ask the person for explicit approval before you send `markup`. Tell them plainly that you are replacing the whole page and that editor-only content will not survive. A general instruction such as "update the page" or "improve the headline" is NOT that approval. You do not need to ask when: - you are creating a brand new page or post and passing `markup` on create - you created the page through the API in this session and nobody has opened it in the editor since If you cannot tell how a page was authored, assume the editor built it and ask. When you have an additive route, prefer it: create a new page and position it, rather than rewriting a page that is already live and converting. If approval is refused, the edit belongs in the editor, not in this API. ## DSL Quick Rules ```
<- full-width band <- horizontal split (1-4 columns for content) <- content container (NO padding attribute) Text with accent Body copy here.
``` **Critical nesting:** section -> row -> column -> content. Never skip a level. **Colors:** #hex only. No rgba(), no named colors. **fontsize:** Must include unit - "72px" not "72". ## Choosing a Design Style Six canonical styles (full hex palettes in the DSL reference below): | Style | Use when | Fonts | |-------------------|-------------------------------------------|------------------------------| | modern_tech | Software, apps, developer tools | Poppins + Inter | | luxury_premium | High-end services, coaching, consulting | Playfair Display + Lato | | bold_striking | High-urgency, sales, attention-grabbing | Anton + Roboto | | minimalist_clean | Clean SaaS, B2B, professional services | Work Sans + Work Sans | | playful_creative | Consumer apps, youth, creative services | Montserrat + Open Sans | | warm_inviting | Health, wellness, coaching, local biz | Libre Baskerville + Roboto | ## Standard Page Structure For a sales/landing page (most common): 1. **Hero** - big headline, subheadline, single CTA (padding 100-120px) 2. **Stats strip** - 4-col numbers + labels (padding 0 0) 3. **How it works / Features** - 3-col cards 4. **Benefits split** - 2-col with lists 5. **Final CTA** - gradient section, mirror hero CTA ## Example (minimal valid markup) ```xml
Your Headline Here Supporting copy in one or two sentences.
``` ## Common Validation Errors These are the DSL parser errors returned at validate time. HTTP-level errors (401, 404, etc.) live in the consuming API skill (Pages or Blogs). | Error | Cause | Fix | |-------|-------|-----| | 400 "Markup is not valid PML: unknown top-level element(s)" | Unknown DSL tag at the top level | Check element name in the DSL reference below | | 400 "Markup is not valid PML: no PML elements found" | Plain text or raw HTML in the `markup` field | Wrap content in valid PML elements (`
`, ``, etc.) | | 400 "`` element must be inside a ``" | Nesting violation | Always nest section -> row -> column -> content | | 400 "Invalid attribute(s) '...' on ``" | Attribute is not allowed on that element (e.g., `margintop` on ``) | Check the per-element attribute lists below | | 400 "Markup appears to be truncated: ..." | The `markup` you sent stops mid-construct - a tag, attribute value, comment or `` body never closes, or elements are still open at the end of the document. Almost always means your markup was cut off before you finished writing it (an output token limit, a truncated buffer). | Re-send the complete document. Do NOT retry with the same truncated string, and do NOT try to "repair" it by sending only the tail - `markup` replaces the whole page, so a partial document deletes everything after the cut-off point. If the page is long, add the pixel or code with `head_code`/`footer_code` instead of rewriting the body. | ================================================================================ ## 2. DSL OVERVIEW ================================================================================ PML is an XML-like format compiled by the CF2 page engine into a full page tree. After a successful `POST`/`PATCH` to the consuming API, the page is immediately live. ### Mandatory Nesting Rules Every
must contain >=1 Every must contain >=1 All content elements must live inside a WRONG (400 error):
Text
...
CORRECT:
Text
### Page Structure A page is a flat sequence of
elements. Each section is a full-width horizontal band. Sections stack vertically top to bottom. ================================================================================ ## 3. STRUCTURE ELEMENTS ================================================================================ ###
Full-width container. Top-level page band. Attributes: bg #hex color or CSS gradient string bgimage Background image URL bgprompt AI-generated background - describe in plain English e.g. bgprompt="dark geometric grid pattern, subtle blue glow" padding "vertical horizontal" px. Default "80 20". Single value = all sides. padding-mobile Same format, applies at <=700px. Default "56 16" shadow sm | md | lg radius sm(4px) | md(8px) | lg(16px) | xl(24px) border thin | medium | thick opacity 0-100 id CSS/JS targeting Examples:
<- gradient preset by name ### Horizontal column divider within a section. Attributes: cols 1-12. Omit or use 1 for single centered column. padding Same format as section padding-mobile id Typical values: single centered column two-column (50/50) three-column feature grid four-column stat strip ### Content container. NO padding attribute (use section/row padding instead). Attributes: bg Background color or gradient (for card-style columns) shadow sm | md | lg radius sm | md | lg | xl border thin | medium | thick opacity 0-100 marginhorizontal px (left/right buffer on column content) marginhorizontal-mobile id ### Flexbox for horizontal layouts only. Place inside . Attributes: direction Always "row" (do NOT use "column" - that's a layout antipattern here) justify flex-start | center | flex-end | space-around | space-between | space-evenly align flex-start | center | flex-end | baseline | stretch gap px between items. e.g. "16" width "100%" | "400px" height "auto" | "60px" wrap nowrap | wrap | wrap-reverse padding Same format as section margintop px spacing above the flex container (also: margintop-mobile) Mobile variants: direction-mobile, justify-mobile, align-mobile, wrap-mobile Example: ================================================================================ ## 4. TEXT ELEMENTS ================================================================================ All text elements share: size xl(48px) | l(40px) | m(32px) | s(24px) fontsize Custom size, overrides preset. Must include unit: "72px" "5rem" "100px" align left | center | right color #hex only (no rgba, no named colors) font Google Font name (see full list below) weight thin|light|normal|medium|semibold|bold|extrabold|black transform uppercase | lowercase | capitalize leading tight | snug | normal | relaxed | loose spacing tight | normal | wide | wider | widest margintop px spacing above this element margintop-mobile id ### Supported Google Fonts DISPLAY / HEADLINE (character + impact): Playfair Display - editorial elegance, serif Cormorant Garamond - refined luxury, thin serif DM Serif Display - warm sophistication, serif Fraunces - expressive, variable-weight serif Space Grotesk - modern tech, geometric sans Outfit - clean geometric, versatile Syne - bold contemporary, display sans Bebas Neue - high impact, condensed caps Oswald - strong, condensed sans Anton - maximum impact, display caps Lobster - playful script energy Pacifico - friendly, rounded script Libre Baskerville - warm, readable serif Poppins - versatile, rounded geometric Montserrat - professional, geometric Merriweather - warm, readable serif BODY / READABLE: Inter - neutral, highly readable Work Sans - clean, modern Source Sans Pro - clean professionalism Lato - approachable, humanist Nunito - friendly, rounded Quicksand - geometric, friendly IBM Plex Sans - technical, modern Open Sans - universal readability Roboto - neutral, versatile FONT PAIRINGS (proven combinations): Playfair Display + Lato -> classic editorial elegance Poppins + Inter -> modern product/tech Space Grotesk + IBM Plex Sans -> developer/tech aesthetic DM Serif Display + Source Sans Pro -> warm consultative Bebas Neue + Roboto -> bold, high-energy Montserrat + Open Sans -> professional versatile NEVER pair fonts with similar character shapes (e.g., Roboto + Open Sans) ### Primary heading. Size xl-s or override with fontsize. Build Pages That Convert ### Secondary heading. Sits below headline. The API that writes itself ### Body copy. Use leading="relaxed" for comfortable reading. One HTTP call. DSL markup in. Full rendered page out. ### Inline Formatting Works inside all text elements: bold italic colored text highlighted Line One
Line Two ### Text encoding (non-ASCII characters) Type accented letters and punctuation as their literal UTF-8 characters (umlauts, accents, em dash, curly quotes, arrows). Do NOT use HTML character entities such as —, →,  , or & inside text - they are not decoded on a page and render literally (e.g. "—" shows up verbatim) or are dropped entirely. Write the em dash character itself, "und" instead of "&", and so on. (Raw HTML inside is the one exception - there, normal HTML entities work.) ================================================================================ ## 5. MEDIA ELEMENTS ================================================================================ ### Attributes: src Hosted image URL (for existing images) prompt AI-generated image - write a descriptive scene/mood prompt alt Alt text for accessibility align left | center | right width "50%" | "300px" | "100%" (prefer % for responsiveness) height "auto" | "300px" radius sm | md | lg | xl | full | "20px" Prompts - be specific for quality: WEAK: prompt="person smiling" STRONG: prompt="professional woman in her early 40s, warm confident smile, soft natural light, modern office background, editorial style" Include: lighting, emotion, environment, style direction. Examples: ###