Guide

Single HTML file apps:
what fits in one file, and where the data goes

An app that is one HTML file is the fastest thing an AI can write and the easiest thing to share. The part that breaks is state: shared data, a signed-in reader, an uploaded photo. This is what fits in the file, what the host has to provide, and how to ask for it.

Updated 2026-10-18 · by Hostus Team

You asked Claude, v0 or Cursor for a small app and got one HTML file: markup, styles and script together, no build step, opens anywhere. It works on your machine; then you send the link and the second person sees an empty list, because the app stored everything in its own browser. Every single-file app hits this wall the moment it has two users.

This page is the hub for that kind of app. Hostus is the option we put first, and the category matters: the home for the single-file app that needs data, a user or a file. Four small SDKs are injected when the page references them, and the file stays one file. Hyperclay, TiddlyWiki, Netlify Drop or Vercel, and the plain localStorage page each have a case, covered below. A "single page application" is a different thing: a framework app bundled from many files that routes in the browser.

What fits in one HTML file, and what must not

More than people expect: the interface, the logic, the styles, a chart drawn in SVG, a few hundred lines of state handling, all in a file you can open in a text editor. No build, no dependency drift, nothing to deploy but the file, and it is the format every AI assistant writes best: the whole app is in its context at once.

Three things must not be in it. A secret. Whoever opens the link can read the source, so an API key in the file is a key given away. Hostus scans every upload for what looks like a key (Anthropic, OpenAI, AWS, Stripe, GitHub, Slack, a PEM private key) and blocks the upload, naming the line; keys that are public by design, such as a Google API key, only warn, and you can allow a fixture. Server-side code. There is no server; anything that must stay hidden, or run when nobody has the page open, does not belong here. Shared state kept in the browser. localStorage and IndexedDB are per browser; state everyone should see has to live with the host, which the next three sections cover.

hostus.data: records the page keeps

If the page references hostus.data, Hostus injects a small SDK before your script runs, and the page reads and writes records that belong to that document. No key, no config: the server knows which document this is and who is reading it, through a signed cookie it issues to each visitor. No account, no login.

const { data } = window.hostus;

data.watch("items", (items) => render(items));   // now, and on every change
await data.add("items", { title, done: false });
await data.set("items", key, { ...value, done: true });
await data.remove("items", key);
const me = await data.me();

The owner sets the mode on the document, not in the page: shared (everyone reads and writes everything, the default), per_reader (each reader sees only their own records, the owner sees all), owner_only (readers only read). data_closed freezes writes. Records are up to 32 KB, 20 collections per document, 1,000 records per collection on the free plan and 20,000 on paid. A list returns at most 200 items, oldest first, so a page that may grow past that watches with where, orderBy: "created_at", order: "desc" and a limit. The Data tab lists them, exportable as CSV or JSON, and Claude reads them through the connector. Longer version: an HTML app with a database.

hostus.user and hostus.files: a reader with a name, and a file

hostus.user is magic-link sign-in for readers, for the app where a person's data should follow them from phone to laptop. It rides on hostus.data. The page calls hostus.user.signIn(): a small modal asks for an email, a link is sent, and the promise waits for the click, up to 15 minutes. No password, no account creation step. What the reader wrote as anonymous in that browser is adopted by the account after signing in, so a per_reader list keeps working across devices. The owner can also set data_require_login: anonymous readers then get login_required on any write, reads stay open, and the page calls signIn() and retries.

hostus.files lets readers upload to the page: files.upload(file, { collection, onProgress }), files.list(), files.url(id, { inline: true }) for an image or PDF shown in place, files.remove(id). Accepted: png, jpg, gif, webp, avif, pdf, csv, txt, md, json, docx, xlsx and pptx, up to 10 MB each; never html, svg, js, css or zip. Files are served from a storage origin, as a download by default, and do not count against your HTML storage: 200 files per document, 100 MB per document and 200 MB per account on the free plan, 1 GB and 5 GB on paid. Same modes as data, with one warning from the SDK: in shared mode any reader can delete any file, so a photo wall wants per_reader. There is no virus scan; say so when the page shows other readers' files.

hostus.ai: the page calls a model, and the owner pays

If the page references hostus.ai, it can call a model on behalf of whoever opens it: await hostus.ai.generate({ prompt, system, json }) for one answer (text, or an object against a JSON Schema), or hostus.ai.stream(...) for text as it arrives. No key in the page, ever: Hostus resolves the reader, checks the quotas and pays the provider.

It is off by default. The owner turns it on per document, in the dashboard or through hostus_update; until then hostus.ai.enabled is false and every call rejects with ai_disabled before any request leaves the page, so write the page to explain itself in that state. Because the owner pays, the quotas are hard caps: 15 calls per reader per hour, 50 per document and 50 per account per day on the free plan, 300 on paid. Prompts up to 8,000 characters, answers up to 1,024 tokens, two model aliases, fast on every plan and better on paid. One prompt in, one answer out: no tools, no agent loops, no images, and nothing that fires on every keystroke.

The prompt

With the Hostus connector on, this is the shape of the request: swap the app for yours, keep the bracket lines that apply and the last paragraph.

Write a [shared packing list for a trip] as one HTML file, mobile first.

State lives on Hostus, not in the browser: use hostus.data. data.watch("items", cb) renders the list live; data.add("items", value) adds one; data.set("items", key, value) edits; data.remove("items", key) deletes; data.me() tells the page who is reading and whether they can write. Handle err.code (forbidden, closed, quota, login_required) in the UI.

[Own list per person across devices: use hostus.user; call hostus.user.signIn() when a write returns login_required.]
[Photos: use hostus.files; upload with onProgress, show images with files.url(id, { inline: true }).]
[Drafting text: use hostus.ai.generate with a short prompt; show a note when hostus.ai.enabled is false.]

No backend, no localStorage, no key in the page, one HTML file. Publish it to Hostus, set the data mode to shared, and give me the link.

The page is born private: switch it to public (or email-gated) in the Hostus dashboard before sharing the link. The data mode, data_require_login and the AI switch are document settings Claude can set with hostus_update. Test in a private window as an anonymous reader: the owner is exempt from the mode, from data_closed and from the rate limits.

Twelve single-file apps you can open

Each is one HTML file on the free plan, for a fictional business or group. Where a page keeps shared records, they are real, written by whoever opened the link before you; the form pages keep each person's submission for the owner alone.

Hyperclay, TiddlyWiki, Netlify Drop, Vercel, a localStorage page: pick it if

Hostus first, for the case this page is about: the single-file app that needs shared data, a signed-in reader or an uploaded file, hosted free. Each project's own site was read on 2026-10-18.

  • Hyperclay. Pick it if you want the app to edit and save itself from inside the page, and you are the one editing. Its site describes file-based software with a minimal, open-standard backend: one HTML file holds interface, behavior, content and state, and saving stores the live document as the next version. Personal is $6 a month or $48 a year, Maker $15 or $120 with three editors; no free plan is listed, and "Viewers and share links are always free". Whether visitors can save is not stated.
  • TiddlyWiki. Pick it if the app is a notebook for you, free and open source. It describes itself as a non-linear personal web notebook, runs as a single HTML file in the browser or as a Node.js application, under the BSD 3-Clause license. Saving writes the file back where it lives: one copy, not shared state for a group.
  • Netlify Drop or Vercel. Pick them if the app has no state to share and you want a free static host. Netlify's free plan is "$0 forever" and Drop needs no account to publish; Vercel's Hobby plan is $0 for non-commercial use. Host only: shared state would need a database and a key in the page.
  • A localStorage page. The default an AI writes. Pick it if the app has one user on one device and nothing to lose: a timer, a scratchpad. Free, no host. The honest limits: per browser, gone when the browser data is cleared, and the second person who opens the link starts from zero.
OptionData shared between readersReader sign-inFile uploadModel calls from the pageHost for freeWhat happens when the browser is cleared
HostusYes, hostus.data, three modesYes, magic link (hostus.user)Yes, hostus.files, 10 MB eachYes, hostus.ai, owner opt-inYes: 20 docs, 2 MB, no clockNothing; records live on the document
HyperclayEditors save; visitors not statedEditors, three on MakerUnder 20 MB each on Personal; uploader not statedNot statedNo free plan listed; from $6 a monthNothing: the file is saved on the host
TiddlyWikiNo, one file, one copyNoNot statedNoFree, open source; you host the fileDepends on where the file was saved
Netlify Drop or VercelNo, static onlyNoNoNoYes: $0 forever; Hobby $0 non-commercialNothing was on the host
localStorage pageNoNoNoNoAny static hostThe data is gone

Good to know before you switch

hostus.data is not a database: a key and a value per collection, 32 KB per record, 20 collections per document, 1,000 records per collection on the free plan, no joins, no queries across collections. The SDKs only work while the page is hosted on Hostus, because the server is what resolves who each reader is; the HTML is yours to download, but opened from your desktop the list is empty. hostus.ai costs the owner per call, which is why it is off by default and capped. There is no server-side code: nothing runs when nobody has the page open, and nothing in the file is hidden from whoever opens the link.

The free plan is 20 documents and 2 MB of HTML storage in total, media included; reader uploads have their own caps. No custom domain: the link is your-slug.hostus.page. No card, no clock.

Questions people ask

Can a single HTML file app have a database?

It can have shared storage, which is what most people mean. On Hostus the page calls hostus.data and records are stored against the document, with the host resolving who each reader is. It is key and value per collection, three access modes, no joins.

How do I add login to a single HTML file app?

With hostus.user: the page calls hostus.user.signIn(), the reader gets a magic link by email, and the promise resolves when they click it. No password and no account form in your page; what they wrote anonymously is adopted by the account, so their data follows them across devices.

Can visitors upload files to a single HTML file app?

Yes, with hostus.files: images, PDFs, CSV, text and Office files up to 10 MB each, served from a storage origin, never html or scripts. Pick per_reader for a gallery, because in shared mode any reader can delete any file.

Can a single HTML file call an AI model without exposing my API key?

On Hostus, yes: hostus.ai.generate runs the call through Hostus, which pays the provider, so no key is ever in the file. It is off by default, turned on per document, and capped at 15 calls per reader per hour and 50 per document per day on the free plan.

What is the difference between a single HTML file app and a single page application?

A single page application is a framework app, built from many source files into a bundle, that routes between views in the browser. A single HTML file app is one file you can read, with no build step, however many views it has.

Why does my vibe-coded app lose its data when I share the link?

Because it stored the data in localStorage or IndexedDB, which live in one browser: the person you sent the link to starts from an empty page, and so do you on another device. Ask for the state to live with the host, with hostus.data, and the same link shows everyone the same list.

Can I host a single HTML file app for free?

Yes. Hostus hosts 20 documents on the free plan with all four SDKs, 2 MB of HTML storage in total, no card and no clock. Netlify Drop and Vercel's Hobby plan host a static file for free too, without shared state.

One file, one link, and the state lives with the host.

Free plan, no card, no clock. Bring the HTML your assistant just wrote.