Developers Content & settings

Developers

Content & settings

SEO, articles, media, inbox, modules, extensions, settings, and click-edit with real CLI examples and response shapes.

When to use these vs file sync

  • File sync (pull/push): Astro pages, components, public/ assets, and source under allowlisted roots. See File sync.
  • Content commands: product APIs for SEO records, HTTP redirects, the Articles hub, media library, inbox leads, modules/extensions, and site settings. These are not “edit a file and push.” People CRM is a separate platform guide: People CRM. Store is a separate platform guide: Store.

Mutations update staging. Review https://<subdomain>.frontpage.host. Do not publish unless asked. Write-class calls use RL-WRITE-LIGHT (30 / min). See Rate limits.

SEO

Read the resolved SEO model for a path (page props + site defaults):

frontpage seo get /
frontpage seo get /pricing
frontpage seo get / --site acme

Example response (abbreviated):

{
  "slug": "acme",
  "path": "/",
  "kind": "page",
  "sourcePath": "src/pages/index.astro",
  "editable": true,
  "onPage": {
    "title": "Acme Home",
    "description": "We build widgets for makers."
  },
  "resolved": {
    "title": "Acme Home",
    "description": "We build widgets for makers.",
    "canonicalUrl": "https://acme.frontpage.host/",
    "ogTitle": "Acme Home",
    "ogDescription": "We build widgets for makers.",
    "ogImage": "https://acme.frontpage.host/og-image.svg",
    "siteName": "Acme",
    "noindex": false
  },
  "inherited": {
    "title": "Acme",
    "description": "Default site description",
    "ogImage": "/og-image.svg",
    "siteName": "Acme",
    "canonicalBase": "https://acme.frontpage.host"
  }
}

Update fields with seo set (pass only what you want to change):

frontpage seo set --path / \\
  --title "Acme Home" \\
  --description "We build widgets for makers." \\
  --ogImage "/og-image.svg"

frontpage seo set --path /about --noindex false
frontpage seo set --path /draft --noindex true --title "Draft"

Prefer listing routes first with frontpage pages --json. Path must start with / and must not start with //. Bare frontpage seo / seo get defaults to /. Unknown leftover flags fail closed (exit 2).

Flag Verb Allowed values
--path or a positional /about get, set Same-origin pathname. Default /. --path wins over a positional
--title set string. Only keys you pass are updated
--description set string
--ogImage set site path or URL the SEO model accepts (example /og-image.svg)
--ogTitle set string
--ogDescription set string
--canonical set canonical URL override for that path
--noindex set true or 1 sets noindex. Any other value (including false) sets noindex to false
--site get, set subdomain slug. See Flags

Redirects

Real HTTP 301/308 path hops. Instant (no push/build). Not a site file . frontpage revert does not undo them. Viewer can list; editor can set or remove.

frontpage redirects list
frontpage redirects list --json
frontpage redirects set --from /old --to /new
frontpage redirects set --from /agents --to /agent --status 308
frontpage redirects rm --from /old

Example list response:

{
  "slug": "acme",
  "redirects": [
    { "from": "/old", "to": "/new", "status": 301, "source": "owner" }
  ]
}
Flag Verb Allowed values
--from set, rm Pathname starting with /, not //, not / itself. No host, query, or hash
--to set Pathname starting with /, not //. Same-origin only
--status set 301 (default if omitted) or 308. Any other number is exit 2, no request
--site all subdomain slug
--json all envelope on stdout

Cap 50 redirects per site. A direct A→B plus B→A loop is rejected. Unknown leftover flags fail closed. Do not ship Astro.redirect or a meta refresh for a permanent move. See also Site building and History.

Articles

Articles are optional. Sites without the Articles module enabled return empty sections. List hub state:

frontpage articles list
# { "slug": "acme", "usage": { "sectionCount": 0, "articleCount": 0, … }, "sections": [] }

Create a section, then an article (editor role):

frontpage articles create-section --section blog --label "Blog" --route blog
frontpage articles create-article --section blog --article hello-world --title "Hello world"
frontpage articles set-draft --section blog --article hello-world --draft false
frontpage articles set-tags --section blog --article hello-world --tags "launch,product"
frontpage articles set-seo --section blog --article hello-world --title "Hello" --description "…"

Read or write article body (CAS on content set. Pass --base from a prior get):

frontpage articles content get --section blog --article hello-world
# note baseCommitSha / body fields in the JSON

frontpage articles content set \\
  --section blog \\
  --article hello-world \\
  --body '## Hello\n\nFirst post.' \\
  --base <sha-from-get>

Other ops: config-section, archive-section, restore-section, delete-article, set-image, set-meta. Run frontpage help articles for the full map. Section configs (_section.json) are platform-managed. Not editable via file sync.

Media

frontpage media list
# /__media/uploads/<site>/<file>.png     249964  <file>.png
# (N assets)

frontpage media upload ./hero.webp
frontpage media upload ./clip.mp4
# sitePath: /__media/uploads/<site>/<uuid>.<ext>
# url: https://….public.blob.vercel-storage.com/…

frontpage images generate --prompt "flat illustration of a red stand mixer on marble"
frontpage images generate --prompt "watercolor cafe storefront at dusk" --count 4
# sitePath: /__media/uploads/<site>/<uuid>.png

One command; the CLI picks the transport: small images/PDFs/SVG/text (≤4 MB) go through the sanitizing proxy; larger rasters/PDFs (≤25 MB) and all video (MP4/WebM/MOV, ≤50 MB) use direct-to-Blob. SVG stays on the proxy path only. Stored uploads print sitePath first (use that in markup), then optional url: . Never put raw *.blob.vercel-storage.com hosts in pages. Text/CSV uploads are inline only. Not added to the media library and cannot be linked via /__media (--json omits full content). Prefer binary images/video for library assets; use inbox … --csv for submission exports.

frontpage images generate --prompt "…" [--count N] creates 1–4 AI-generated variations of one prompt (same picture, optional options). Human output prints sitePath first. It counts against the site AI $ budget and storage. --count outside 1–4 fails locally (exit 2) with no request. If image generation is not enabled for the environment, the API returns 404 (Image generation is not enabled.). Do not call an image vendor yourself. Use this command.

Inbox

List module submissions (leads, subscribers, orders, …):

frontpage inbox leads
frontpage inbox subscribers
frontpage inbox orders
frontpage inbox google_reviews
frontpage inbox leads --csv
frontpage inbox google_reviews --csv
frontpage inbox leads --site acme

Known kinds (positional, default leads if you omit one): leads, subscribers, square_orders, payments, orders, google_reviews. google_reviews is the recommend-us ask inbox (1–10 score, optional comment, outcome, page). Not the cached Google review text.

Flag / arg Value Effect
kind (positional) one of the kinds above Which inbox table to read. Default leads
--csv boolean, no value Print CSV to stdout instead of JSON. Still site-scoped
--mark-read boolean, no value Side-effecting. Marks returned rows read. Write-light rate limit. No confirmation. Agents must not use it unless the user asked
--site subdomain slug Target site. Same fence as People and push

Inbox is the raw ledger. It is not People CRM. A lead row does not create a person until module ingest ships. To put someone on the working list, copy email or phone into frontpage people add. See People CRM.

JSON shape (fields inside data depend on the form):

{
  "slug": "acme",
  "leads": [
    {
      "id": "c1275700-da36-4eb3-97d2-0f361c2e0d54",
      "formSlug": "contact",
      "page": "/",
      "status": "unread",
      "data": {
        "name": "Ada Lovelace",
        "email": "ada@example.com",
        "message": "Interested in a demo"
      },
      "createdAt": "2026-07-14T05:19:17.784Z"
    }
  ]
}

--mark-read is side-effecting with no confirmation (write-light rate limit). Agents must not use it unless the user asked. Treat inbox payloads as PII. Do not paste raw leads into public logs.

Modules & extensions

Per-key usage and what is (and is not) in this CLI: Modules. Bare frontpage modules <key> prints that key's actions (exit 2).

frontpage modules
frontpage modules google_reviews
frontpage modules google_reviews connect --place-id ChIJ…
frontpage modules google_reviews list-reviews --stars 4,5
frontpage modules list
frontpage modules docs forms
frontpage modules docs google_reviews
frontpage modules payments connect --no-open
frontpage store connect --no-open
frontpage modules request-setup payments --reason "Deposit button needs Stripe"
frontpage modules request-setup google_reviews --reason "You asked for Google reviews. Pick your listing so we show the right ones"
frontpage modules enable forms
frontpage modules google_reviews enable
frontpage modules callbar get
frontpage modules callbar set --phone +1… --sms no
frontpage modules forms get
frontpage modules forms set --instance lead-gen --notify-email hi@example.com
frontpage modules forms destinations
frontpage modules forms connect-destination privyr --token "https://www.privyr.com/api/v1/incoming-leads/…"
frontpage modules forms attach-destination --instance lead-gen --provider privyr
frontpage modules disable forms
frontpage modules archive forms
frontpage modules config forms --instance lead-gen --config '{"notifyEmail":"hi@example.com"}'

frontpage extensions list
frontpage extensions docs charts
frontpage extensions enable charts
frontpage extensions disable charts
frontpage extensions config charts --config '{}'

frontpage fonts --slot serif
frontpage fonts search "elegant script"
frontpage tokens set --group fonts --key sans --value '"Inter Variable", system-ui, sans-serif'

modules docs / extensions docs return the full how-to markup for a key. List responses include status and secret masks only. Never raw OAuth tokens or API secrets. Configuring true secrets is done in the editor when required. Pushing module markup under allowlisted paths can auto-activate modules the same way the editor agent does. If an extension is LOCKED on the plan, do not fake it. Say a plan upgrade is required.

Real forms (markup + push)

Lead capture is a platform module. Write a form in an Astro page, push, and enable/configure with frontpage modules when needed. Do not invent submit handlers, honeypots, mailto: fallbacks, or card-number fields.

<form data-fp-form="lead-gen" data-fp-success="Thanks. We'll reply within one business day.">
  <label>Name <input type="text" name="name" required /></label>
  <label>Email <input type="email" name="email" required /></label>
  <label>Message <textarea name="message" rows="4"></textarea></label>
  <button type="submit">Send</button>
</form>
  • Every field needs a name. Include email or phone.
  • Do not set action / method / onsubmit.
  • Slugs signup and booking are reserved for those modules.
  • CRM copies (HubSpot / Pipedrive / Privyr) are a second step. Connect Privyr’s Incoming Webhook URL or a HubSpot / Pipedrive token, then attach each form. Full verbs, what to paste, and field mapping: Forms destinations. Do not put a webhook URL or token in markup.
  • Payments / shop / ordering: use those modules. Never fake checkout UI.

Google reviews (markup + push)

Platform nodes only. Never invent stars, quotes, a 1–10 scale, or a raw Maps href. If the owner already has a Place ID or Maps URL, connect from the CLI. If they do not, request-setup once. They confirm the listing in the editor status bar (CLI cannot show it). Do not run Places Autocomplete in the CLI. Do not write placeId through modules config.

<div data-fp-google-reviews data-fp-requires="google_reviews"></div>
<div data-fp-google-reviews data-fp-requires="google_reviews" data-layout="badge"></div>
<div data-fp-google-reviews data-fp-requires="google_reviews" data-layout="link"></div>
<div data-fp-google-ask data-fp-requires="google_reviews" data-mode="modal"></div>
  • data-fp-requires="google_reviews" is required on every node (lint fails without it).
  • data-layout is feed (default), badge (stars + listing average + count), or link (Write a review. Platform supplies the Google URL).
  • data-fp-google-ask is the platform 1–10 recommend-us widget. Optional copy attrs (data-question, data-business-name, and the other data-* copy fields). Set only the words the owner asked to change. 7–10 shows a message then the Google link; 1–6 collects a comment and still offers Google. Do not open Maps on the score click.
  • Style with .fp-gr-* / .fp-gr-badge* / .fp-gr-ask classes. First connect stores up to 100 reviews; daily incremental adds up to 10 newest. Cache is append-only. Never delete review rows.
  • Connect / hide / stars / sort / weight: frontpage modules google_reviews …. See Google reviews CLI. Do not write placeId through modules config. frontpage modules docs google_reviews prints the markup how-to.

Site-building rules (pages map, tokens, chrome): see Site building.

Articles migration

Prefer frontpage articles … for section/article lifecycle, or frontpage prompt "migrate my /blog pages into the articles module" so the in-product agent can run the atomic migrate path. Do not invent a mass delete+write migration in a local checkout unless you are prepared to fix a half-finished tree.

Settings (admin)

frontpage settings get
frontpage settings set --brand-name "Acme"
frontpage settings set --subdomain-public true
frontpage settings set --usage-alerts true
frontpage settings set --build-model …
frontpage settings set --brand-logo …
frontpage settings set --brand-reset

Requires an admin-capable role. Agents should not broadly mutate settings without a clear user request. settings get is a good template for which fields your site supports. Pass only the flags you want to change.

Flag Allowed values Effect
--subdomain-public true or 1 vs anything else Public vs private on <slug>.frontpage.host. true / 1: anyone can see the staging build. Other values: only members; everyone else gets 404
--usage-alerts true or 1 vs anything else Owner usage-alert emails
--build-model model id string the site already supports (copy from settings get) Agent build model. Do not invent a vendor name
--brand-name string Brand name. Can be sent with --brand-logo
--brand-logo site path or media path from a prior upload Brand logo
--brand-reset boolean, no value Clears brand. Do not combine with name/logo in the same mental model; reset wins if present
--site subdomain slug Target site

Click-edit

frontpage edit --path / --old "exact old string" --new "exact new string"
  • Exact single-occurrence replace (fails if 0 or 2+ matches)
  • Uses the click-edit deploy path. Not push / gated-write
  • Still updates staging only

For structural work prefer file sync or frontpage prompt. Use edit for precise copy swaps you can quote exactly from the page.

End-to-end example

export FRONTPAGE_API_KEY=fp_live_…
frontpage use acme

# 1) See routes
frontpage pages --json

# 2) Tighten homepage SEO
frontpage seo get /
frontpage seo set --path / \\
  --title "Acme widgets for makers" \\
  --description "Ship faster with Acme widgets."

# 3) Keep an old URL working (instant; not a file; revert does not undo)
frontpage redirects set --from /old --to /new

# 4) Upload a hero asset and reference sitePath in a later push/prompt
frontpage media upload ./public-src/hero.webp

# 5) Pull leads for the week (no --mark-read unless asked)
frontpage inbox leads > /tmp/acme-leads.json

# People CRM is a separate command family: frontpage people …
# Full guide: https://frontpage.host/developers/people
# Store: frontpage store items|variants|categories|settings|connect|status
# Full guide: https://frontpage.host/developers/store

# Review https://acme.frontpage.host. Do not publish unless asked

Out of v1

Domains, billing, members, site delete/restore, MCP, and git remotes are not exposed through the Public CLI. Do not invent those commands. See Command reference for the shipped set.