Skip to content

Custom pages on ComStack

What this is

A custom page is a ComStack page whose entire body is your own code — a complete Astro component or HTML document, uploaded as one opaque body_source with the upload-custom-page tool. The platform never rewrites it: what you author is what ships (Astro’s standard build applies; plain-HTML bodies are round-tripped through a standards-compliant parser). Layout, styling, animation, and interactivity are entirely yours.

Custom pages exist for everything a structured markdown template can’t express: landing pages, product launches, interactive demos, calculators, animated showpieces, brand-heavy marketing pages. The rest of the site — docs, blogs, FAQs — belongs to knowledge pages and their templates; see Knowledge vs custom pages.

What is possible

Treat a custom page as a blank canvas with a fast CDN behind it:

  • Total layout freedom — your own grids, sections, hero treatments, typography. No template structure is imposed on the body.
  • Animation — CSS keyframes, scroll-driven effects, transitions, SVG animation. Inline <style> and <script> tags ship as authored.
  • Interactivity — vanilla JS calculators, tabs, accordions, canvas effects, form-like widgets. No framework runtime is added or required.
  • Automatic translation — wrap your visitor-facing strings in markers and every configured locale gets a native version of the page at publish, same URL structure, correct hreflang. You write the page once.
  • Platform AEO for free — title/description metadata, JSON-LD, Open Graph, sitemap and llms.txt inclusion are handled by the platform shell around your body.

A page generated in Lovable, v0, or Bolt — or written by hand, or by an AI agent in one shot — can be live in minutes: add markers, upload, publish.

How it works

  1. Author a complete Astro component or HTML document elsewhere (any tool, any agent).
  2. Mark translatable strings with <T key="…" default="…"> (Astro/JSX) or data-t-key (HTML) — the upload extracts them into translatable_strings; publish translates them into every configured locale. Never hand-translate. See Translation.
  3. Upload with upload-custom-page (project_id, project_name, slug, body_source, title 10–60 chars, description 50–160 chars). The result is a draft — nothing is live yet.
  4. Publish with the standard two-step flow: publish (dry-run manifest + confirmation token) → publish-confirm → poll publish-status. See Publishing.

Re-uploading the same slug replaces the body in one call; the live URL stays up until you publish the new draft.

Hard boundaries

Three constraints are non-negotiable, by design:

  1. The body is opaque, but the envelope is not. Your code renders inside the platform shell that provides <head> metadata, AEO tags, locale routing, and security headers. You author the <body>-level content, not the document head.
  2. Dangerous href schemes are rejected at upload. javascript:, data: and vbscript: URLs in href/xlink:href attributes fail the upload outright — the body ships to the browser as authored, so the gate is at the door. data: URLs in src (inline images) are fine. See Troubleshooting.
  3. Quality is gated, not hoped for. Custom pages are audited against Lighthouse with a bar of 95 in performance, accessibility, best practices, and SEO at pre-publish. Build to that bar from the first line. See Quality gates.

When to use it

  • A landing or campaign page that must look nothing like the rest of the site
  • A product launch page with bespoke animation and scroll effects
  • An interactive page — calculator, configurator, quiz — in plain HTML/JS
  • Importing a vibe-coded export from Lovable, v0, or Bolt
  • Any page where a markdown template is the wrong tool

For structured editorial content (docs, articles, FAQs), use a knowledge page instead — you get templates, validation, and FAQ JSON-LD that custom pages deliberately do not have.

Example

The smallest valid custom page body (HTML form):

<section class="hero">
<h1 data-t-key="hero.title">Fresh bread, every morning</h1>
<p data-t-key="hero.sub">Family bakery in the old town since 1962.</p>
<a class="cta" href="tel:+34600000000" data-t-key="hero.cta">Call the bakery</a>
</section>
<style>
.hero { min-height: 60vh; display: grid; place-content: center; text-align: center; }
.cta { display: inline-block; padding: .8rem 1.6rem; border-radius: 999px; background: #1a7f5a; color: #fff; }
</style>

Upload it, publish, and /es/ (plus every other configured locale) renders the same layout with translated strings substituted into the marker positions. Two fully annotated walkthroughs — minimal and advanced — are in Recipes.

Common errors

  • Marker mistakes — unmarked strings stay untranslated; malformed markers reject the upload with character offsets. See Translation.
  • wrong_tool_knowledge_page — the slug already belongs to a markdown page. Pick another slug or edit that page with update-page.
  • Lighthouse failures — heavy images, render-blocking scripts, missing alt text. The fixes are mechanical; see Quality gates.

The full catalogue with exact messages and fixes: Troubleshooting.

Last updated: