Draft. This page may change before it is final.
Frameworks
Carnival hosts the output of a build: plain files. Run the project's build, then publish the contents of its output folder, with index.html at the top level. Never the project itself: source, package.json and node_modules are refused.
Output folders
| Tool | Build | Publish the contents of | Settings |
|---|---|---|---|
| Plain HTML | none | the folder that holds index.html |
none |
| Vite (React, Vue, Svelte and other Vite apps) | npm run build (vite build) |
dist/ |
keep base at / |
| Astro | npm run build (astro build) |
dist/ |
keep the default static output (output: 'static') |
| Next.js | next build with output: 'export' |
out/ |
a static export only (below) |
| Eleventy | npx @11ty/eleventy |
_site/ |
keep pathPrefix at / |
| Hugo | hugo --baseURL / |
public/ |
links from the site's root (below) |
Another tool: publish the folder its build writes, the one with index.html at its top. A site whose start page has another name needs it renamed to index.html.
Next.js
Carnival hosts a Next.js app as a static export. In next.config.mjs:
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export',
images: { unoptimized: true }, // next/image without an image server
};
export default nextConfig;
next build then writes out/. A static export can't use what needs a server: API routes and route handlers that read the request, middleware, server actions, rewrites, redirects and headers in the config, incremental static regeneration, and dynamic routes that aren't generated at build time (generateStaticParams). An export usually has more than 30 files: send them over several calls with finalize=false (the recipe is in Read this first).
Hugo
Hugo writes absolute links from baseURL, and a Carnival site's address is only known after its first publish. Build with hugo --baseURL / so links start at the site's root.
Files Carnival accepts
- Types: html, htm, css, js, mjs, json, txt, xml, svg, png, jpg, jpeg, gif, webp, avif, ico, woff2, woff, ttf, otf, webmanifest, map, pdf. No video or audio: embed them from YouTube or Vimeo. No archives or programs.
- Paths: relative, like
img/logo.webp: letters, digits and- _ . ~ /, at most 200 characters and 10 segments. No dotfiles: leave out.nojekyll,.DS_Storeand.well-known/. - Other hosts' settings files:
_headers,_redirects,_routes.json,_worker.js,vercel.json,netlify.toml,wrangler.*,.htaccessand.envare refused. Carnival sets every response header itself and has no redirect rules. - No source:
.ts,.tsx,.jsx,.vue,.svelte,.scssand.lessfiles are framework source: publish what the build made from them. - Sizes (free plan): 250 files, 25 MiB a site, 4 MiB a file. Photos as WebP or AVIF; fonts as WOFF2. Source maps (
.map) are allowed but count toward the size: leave them out when space is short. New accounts can publish at most 8 new images a deploy, each under 2 MB: add the rest in an update. Every limit is on Limits. - Production builds: a development build (eval-based source maps) gets the
DEV_BUILDwarning.
Addresses and links
- Each site has its own address, like
gilded-carousel-b4x9t.carnival-staging.page, served from/. Root-relative links (/css/site.css) and relative links (css/site.css) both work. Don't write the site's own address into its files: it isn't known before the first publish. /aboutservesabout.html, or redirects to/about/when the file isabout/index.html. Addresses ending inindex.htmlor.htmlredirect to the short form.- Paths are case-sensitive:
Logo.pngandlogo.pngare different files. - An unknown address gets the nearest
404.html, looking upward from its folder, with status 404; without one, Carnival's own not-found page. - Single-page apps that route in the browser (React Router, Vue Router in history mode): pass
spa: truetocarnival_deploy, so a page address with no file servesindex.html. Missing files still return 404. Hash routing (/#/menu) works without it.
Caching
Pages and most files revalidate on every visit, so the next visit after an update gets it (updates go live within about 12 seconds). Files whose names end in a build hash (like index-BxK3f9aQ.js or main.3f9a1c2b.css) are cached by browsers for a year: build tools give a changed file a new name. A hand-made name can look like one: change photo-20240101.jpg and it needs a new name too.
What sites can't do
Carnival sends the same fixed headers with every site's files:
- No camera, microphone, location, payment requests, USB, Bluetooth, clipboard reading and similar browser features. For directions, link to a map instead of asking for the visitor's location. Fullscreen (for embedded video) works.
- No service workers: registering one fails, so turn off offline and PWA plugins. A site that tries gets the
SERVICE_WORKERwarning. - No
<object>or<embed>, and no<base>pointing at another site. - No framing by other sites: a Carnival site can't be shown in a frame on another site.
- Cookies: Carnival sets none. A site's scripts may set their own, for its own address only.
- Search engines: sites are marked
noindex, because they expire.
Scripts, forms and embeds
- Scripts from other sites: load a pinned version from cdnjs.cloudflare.com, cdn.jsdelivr.net or unpkg.com, or include the file in the site. A script from another host, or from an unpinned
@latestor branch URL, gets theSCRIPT_HOST_UNLISTEDwarning, and Carnival may review the site. - Forms: a static site has no server to receive them. Send forms to Formspree, Web3Forms, Basin, Getform, Google Forms or Tally, or use a
mailto:link. Another service gets theFORM_BACKEND_UNLISTEDwarning. - Payments: link to a hosted checkout (for example a Stripe Payment Link or Square), or take payment on pickup. Never card fields.
- Embeds: maps, video and booking widgets from services such as Google Maps, YouTube, Vimeo and Calendly are fine. A frame that shows another site full-screen is not: link to it instead.
- Keys: every file is public, including the environment variables a build compiles in (
VITE_*,NEXT_PUBLIC_*, Astro'sPUBLIC_*). A private or secret key rejects the deploy; a browser key, like a Google Maps key startingAIza, gets theSECRET_LIKELYwarning: restrict it to the site.
House rules
Carnival checks every deploy against the content policy before it goes live. House rules are the technical part an agent can fix: a hit comes back in filter.reasons with rule, path, line and fix.
These stop the publish (CONTENT_REJECTED):
| Rule | The site has | Do instead |
|---|---|---|
H-PASSWORD |
a password field | link to a service that hosts the sign-in |
H-CARD |
card number, CVV or expiry fields | link to a hosted checkout, or take payment on pickup |
H-GOVID |
government ID fields (SSN, SIN, CURP, RFC, passport, driver's licence, tax ID) | collect them in person or through a service built for it |
H-SEED |
wallet recovery phrase or private key fields | remove them |
H-EXFIL-CHAT |
code sending data to Telegram bots, or Discord or Slack webhooks | use a form service such as Formspree or Tally |
H-SECRET-KEY |
a private or API key | remove it, and tell the user to rotate the key |
H-REDIRECT-ONLY |
a page that only sends visitors to another site | publish the page's own content, or link to the other site |
H-IFRAME-FULL |
another site shown full-screen in a frame | link to it, or embed from a supported service |
H-EXEC |
programs, installers or archives, or links to them | link to the official app store or vendor page |
H-PDF-ACTIVE |
a PDF with JavaScript, a launch action or an embedded file | export it again as a plain PDF |
H-MINER |
a cryptocurrency miner | remove it |
H-DRAINER |
wallet approval or signing requests | link to the project's official app |
H-IMAGE-BATCH |
more than 8 new images, or one over 2 MB, from a new account | resize the images, publish, then add the rest in an update |
These let the site go live, but Carnival may review it and take it down: apply the fix as an update.
| Rule | The site has | Do instead |
|---|---|---|
S-NOTIF |
a notification permission request when a page opens | remove it |
S-OTP |
one-time, 2FA or verification code fields | remove them: a static site has nothing to verify |
S-BANK |
bank account, routing, IBAN or PIN fields | link to a hosted payment page |
S-FORM-ODD |
a form that submits to an IP address, a link shortener, a data: URL or javascript: |
point it at a form service |
S-REDIRECT |
a page that redirects visitors to another site | use a normal link |
S-SHORTENER |
links through URL shorteners | link to the full address |
S-OBF-PACKER, S-OBF-OBFUSCATOR, S-OBF-ESOTERIC |
packed, obfuscated or encoded JavaScript | publish the normal build (minified is fine) |
S-EVAL-DECODE |
code that runs decoded strings with eval, new Function or setTimeout |
ship the code directly |
S-COOKIE-DOMAIN |
cookies set for a parent domain, or more than 4 KB of them | drop the domain attribute; use localStorage |
S-DOWNLOAD |
download links to files on other sites | link to the page that offers the file |
S-HIDDEN-TEXT |
a lot of hidden text | make it visible or remove it; keep screen-reader-only text short |
Scripts from unrecognised hosts, unrecognised form services, service workers and development builds come back as the warnings above, in warnings, not as rules.