TL;DR. Download your artifact from Claude, rename the file to index.html, zip it, and deploy it at hatchable.com/deploy. You get a real public URL in about a minute. Then add a table and an API route (or ask your AI agent to) and the thing that used to forget everything on refresh starts remembering.

What an artifact is, and what it is missing

A Claude artifact is a self-contained page that runs inside a sandbox on claude.ai. It is genuinely useful: you describe a habit tracker or a pricing calculator or a client intake form, and a working interface appears next to the conversation.

Then you try to use it for real, and you hit the wall. As of July 2026:

None of that is a flaw in artifacts. A sandbox that renders a working UI in ten seconds is doing exactly its job. It is just that the job stops one step short of a product, and the missing step is hosting plus a database.

The two routes

There are two ways to close that gap, and they suit different moods.

RouteWhat you doGood for
Upload the file Download the artifact, zip it, import it in the browser. No agent, no terminal, no code. Getting the thing live in a minute, exactly as it looks now.
Hand it to an agent Connect Claude Code (or Cursor, Codex, any MCP client) to Hatchable and say "put this on Hatchable and give it a database". Everything past step one: storage, auth, iteration.

Our advice is to do both, in that order. Upload first so you have a live URL to look at and share, then bring in an agent to add the database. The rest of this guide walks that path.

Part 1: get the artifact online

  1. Get the file out of Claude

    Open the artifact in claude.ai. Next to the Copy button there is a chevron with a download option, which saves the artifact as an .html file. (Anthropic moves this UI around, so if you do not see it, the reliable fallback is to ask in the chat: "Give me the complete, self-contained HTML for this artifact as a single file." Then paste the result into a text editor and save it.)

    What you want is one file that opens in a browser on its own. If Claude hands you a bare React component instead of a page, ask again for a single self-contained HTML file. That distinction matters later, and we come back to it in the gotchas.

  2. Rename it to index.html

    The importer looks for index.html at the top level of the zip. Whatever the download was called (habit-tracker.html, claude-artifact-3.html), rename it.

  3. Zip it

    On macOS, right click the file and choose Compress. On Windows, right click and choose Send to, then Compressed folder. From a terminal:

    zip site.zip index.html

    If your artifact came with extra assets (images, a CSS file, fonts), put them next to index.html and zip the whole folder. Zipping a folder is fine, the importer unwraps a single wrapper directory for you.

  4. Import it

    Go to hatchable.com/deploy, sign in (free, no card), pick the "From a zip" tab and choose your file. Up to 50 MB per import.

    Hatchable recognises a plain website, meaning an index.html with assets and no Hatchable manifest, and sets it up for you: your files move under the served directory, build junk like node_modules and lockfiles is dropped, the project name and description are lifted from your page's <title> and meta description, and a hatchable.toml manifest is written so the project exports cleanly later.

  5. Open the live URL

    The first deploy is queued automatically. Thirty seconds or so later your artifact is a website at https://your-project.hatchable.site, served from a real origin with real caching, not a preview pane.

Private by default. New projects are personal, so you and any collaborators you invite can open them and everyone else hits a sign in screen. To open it to the world, hit "Publish to the web" on the project's overview page. Your first public app is free. Public sites show a small "Built on Hatchable" badge, and the Builder plan ($12/mo) lets you switch it off, adds custom domains, and lifts the limit on how many apps you can publish.

Part 2: give it a database

This is the part that turns a demo into something people can use twice. The pattern is always the same three moves, whether you write them yourself or ask an agent to.

1. A table

Add a file under migrations/. They run in filename order on deploy, once each, forward only.

-- migrations/0001_create_habits.sql
CREATE TABLE habits (
  id BIGSERIAL PRIMARY KEY,
  user_id TEXT NOT NULL,
  name TEXT NOT NULL,
  color TEXT NOT NULL DEFAULT 'slate',
  created_at TIMESTAMP NOT NULL DEFAULT now()
);

CREATE INDEX idx_habits_user_id ON habits(user_id);

2. An API route

Files under api/ become endpoints at the matching path. Each one declares who is allowed to call it, and that gate is enforced before your code runs.

// api/habits.js
import { db } from 'hatchable';

export const access = 'member';        // 'public' | 'member' | 'admin'
export const methods = ['GET', 'POST'];

export default async function (req, res) {
  if (req.method === 'GET') {
    const result = await db.query(
      'SELECT id, name, color FROM habits WHERE user_id = $1 ORDER BY created_at',
      [req.member.id]
    );
    return res.json({ habits: result.rows });
  }

  const name = (req.body.name || '').trim();
  if (!name) return res.status(400).json({ error: 'Name is required.' });

  const result = await db.query(
    'INSERT INTO habits (user_id, name, color) VALUES ($1, $2, $3) RETURNING id, name, color',
    [req.member.id, name, req.body.color || 'slate']
  );
  return res.status(201).json({ habit: result.rows[0] });
}

3. The swap in the page

Now find the place in the artifact where state was born and where it dies. Usually it is a useState([]) holding an array, plus a handler that pushes onto it. Load from the endpoint on mount, post to it on create, and the array stops being a lie:

// before: const [habits, setHabits] = useState([]);
// after:
const [habits, setHabits] = useState([]);

useEffect(() => {
  fetch('/api/habits').then(r => r.json()).then(d => setHabits(d.habits));
}, []);

async function addHabit(name, color) {
  const res = await fetch('/api/habits', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ name, color }),
  });
  const d = await res.json();
  setHabits(h => [...h, d.habit]);
}

That is the whole conversion. Everything else in the artifact, the layout, the animations, the colour choices you argued Claude into, stays exactly as it was.

Do not hand-write any of this if you would rather not. Connect an MCP client to Hatchable and say it in English: "This project is a Claude artifact I imported. The habit list only lives in React state. Add a habits table, an API route to read and write it, and rewire the page to use them. Then deploy." The agent has the platform's own pattern library available to it, so it writes the shapes above rather than inventing its own. See the Claude Code guide or the Cursor guide for the one-line setup.

Who is "member", and do you need sign in?

The route above used access: 'member' and read req.member.id, which means every person gets their own habits and anonymous visitors never reach the handler. That is the right default for anything personal, like a tracker, a dashboard, a saved list.

If your artifact is meant to be open, a public leaderboard, a contact form, a shared guestbook, use access: 'public' and drop the user_id filter. Access is declared per file, so the common "anyone can read, only signed in people can write" split is just two files: a public GET route and a member POST route.

Sign in itself is a project setting, not something you build. Turn on auth and Hatchable handles the codes, the sessions, and the gate.

Gotchas specific to artifacts

The artifact was React, and the download is not a page

Some artifacts are a component rather than a document. If what you saved starts with import React from 'react' and exports a function, it is source code, not a website, and there is nothing for a browser to open. Ask Claude for a single self-contained HTML file, or hand the component to an agent and let it build the page around it. Note that Hatchable has no build step: JSX and TypeScript files are rejected at deploy, so React apps here use htm template literals instead of JSX. An agent connected to Hatchable knows this pattern and will do the translation for you.

The page loads React from a CDN

Artifacts commonly pull React, or anything else, from esm.sh or unpkg at runtime. It works on your machine and it is a real liability in production: any visitor whose network blocks that CDN, which corporate filters and DNS blockers do routinely, gets a blank page rather than a degraded one. We have watched it happen to a live dashboard. Fetch those libraries into your own project once, serve them from your own origin, and the failure mode disappears. Ask your agent to "vendor the CDN dependencies", it is a one time job.

The artifact called Claude directly

Artifacts can talk to Claude through helpers the claude.ai sandbox provides. Those helpers do not exist anywhere else, so any AI feature in your artifact goes quiet the moment it leaves the sandbox. On Hatchable you replace that call with a server side AI call and supply your own model key, which also means the key is never in the page where visitors can read it, and you can see exactly what you are spending.

localStorage was never really saving anything

If the artifact appeared to persist across a refresh, check what it was persisting into. Browser storage is per person and per device, so it is not a database: the data is invisible to you as the owner, invisible to every other visitor, and gone when the browser clears. Moving it into a table is the same swap shown above.

What you have when this is done

And the loop you liked in the first place still works. Describe the change, let the agent make it, watch the live site update.

Turn your artifact into a real site.

Import a zip, get a live URL with a database, auth, and storage. Free to start, no card.

Get started free →

Frequently asked questions

Do I need to know how to code to do this?

For part one, no. Downloading the artifact, renaming it to index.html, zipping it and uploading it is all browser work, and the result is a live public site. Part two, adding the database, involves a migration file and an API route, which you can either write yourself or ask an AI agent to write by connecting it to Hatchable over MCP. Most people do the second.

Will my artifact look exactly the same once it is live?

Yes, with one caveat worth checking. The HTML, CSS and layout carry over verbatim. If the artifact loaded libraries from a CDN at runtime, or called Claude through a helper that only exists inside claude.ai, those parts need rewiring. Both are covered in the gotchas above, and both are quick.

Can I import more than one file, like images and a stylesheet?

Yes. Put index.html at the top level with your assets alongside it and zip the folder. Everything is served from your project. Build artefacts like node_modules and lockfiles are dropped automatically, and anything skipped is listed for you after the import.

Is the site public as soon as I import it?

No. Imported projects are created private, so only you and people you invite can open them. Publishing is a deliberate click, "Publish to the web" on the project overview. Your first public app is free. Public sites show a small "Built on Hatchable" badge, which the Builder plan lets you switch off alongside custom domains.

Can I import a Figma or Claude Design export the same way?

Yes. Any plain website, meaning an index.html with assets and no build step, takes the same path: zip it, import it, and Hatchable sets up the project around it. The database steps in part two apply identically once it is in.

What happens to my data if I want to leave?

You export it. Every project downloads as a zip with its code and its hatchable.toml manifest, and its data downloads separately as SQL. Both re-import here, and the code is plain HTML, JavaScript and SQL that runs anywhere you can serve files and reach Postgres.