wrangler deploy from your laptop, which deletes other people's pages,
and it predates commenting on published pages entirely.
Read version 2 instead — same guide,
corrected, plus the comment loop.
Every HTML artifact Claude builds for you has the same problem: it dies in the sandbox. Beautiful in the chat, useless as a deliverable. This page is the artifact that fixes that — and it tells you how to do the same thing for everything you build next.
What you'll do
// the end-state, before we build it
By the end of this guide, your setup will do four things:
share.yourdomain.com/<slug>. No expiring tokens. No sandbox links.Cost: $0 if you already own a domain on Cloudflare. Workers' free tier is 100k requests/day. Web Analytics is free. Cloudflare Access is free up to 50 users. You will not spend money to do this.
// boring but unavoidable
npx.// skip this if your domain is already on Cloudflare
Two paths:
Once your domain shows up under Websites in the dashboard with a green Active status, you're done with this step.
// one folder, two files, one command
Wrangler is Cloudflare's deploy CLI. A Worker with the new assets config is the simplest way
to serve a static site — no Workers Sites, no Pages config, just here's a folder, serve it.
— Step 1. Create the folder structure:
bash# Create a directory anywhere — examples below assume ~/share/ mkdir -p ~/share/deploy cd ~/share
— Step 2. Save this as wrangler.jsonc:
wrangler.jsonc{ "name": "share-worker", "compatibility_date": "2024-09-23", "assets": { "directory": "./deploy", "not_found_handling": "404-page" } }
— Step 3. Drop a placeholder deploy/index.html so the first deploy has something to serve. Anything works — an <h1>ok</h1> is fine.
— Step 4. Authenticate Wrangler with Cloudflare (one-time, opens a browser):
bashnpx wrangler login
— Step 5. Deploy:
bashnpx wrangler deploy
Wrangler prints a *.workers.dev URL. Visit it. You should see your placeholder. That's it —
you have a publishing surface.
// share.yourdomain.com instead of share-worker.username.workers.dev
share-worker.share.yourdomain.com. Cloudflare creates the DNS record and provisions a cert automatically. Wait 30-60 seconds.https://share.yourdomain.com/. Same placeholder you saw on the *.workers.dev URL. Real domain. Real cert. Real URL.
From now on, anything you put in deploy/<slug>/index.html is reachable at
share.yourdomain.com/<slug> after a deploy. That's the whole pattern.
The artifact problem isn't that they look the same. It's that they never leave the sandbox.
// teach Claude the loop, once, then never think about it again
The skill is a single Markdown file. Drop it in ~/.claude/skills/publish-artifact/SKILL.md and
Claude Code will trigger it any time you say "publish this", "give me a URL for this", or
"update the published version".
On first run the skill asks for two things — where your share directory lives and what your share domain is —
and writes them to ~/.config/publish-artifact/config.json. Nothing about your machine is baked in.
Copy the contents below into ~/.claude/skills/publish-artifact/SKILL.md:
SKILL.md--- name: publish-artifact description: Publish any HTML artifact to share.yourdomain.com with a clean URL, visitor analytics, and optional password protection. Triggers on "publish this", "make this shareable", "ship to share", "deploy this artifact", "give me a URL for this", or "update the published version". --- # Publish HTML Artifact ## Configuration Read config from ~/.config/publish-artifact/config.json: { "share_dir": "~/share", "share_domain": "share.yourdomain.com", "cf_beacon_token_path": "~/.config/publish-artifact/cf-beacon-token", "protected_path_prefix": "/c/" } If missing, ask the user for share_dir and share_domain on first run, then write the config. Expand ~ to the home directory before using. ## Pre-flight 1. Confirm the artifact is a single self-contained HTML file. If it has relative <img>, <link>, or <script> references, inline them or move the assets into the same slug folder. 2. Ensure the Cloudflare Web Analytics beacon is in <head>. Read the token from cf_beacon_token_path and substitute. Inject if missing. 3. If the user calls it "client work," "sensitive," or names a recipient, ASK whether to put it behind Cloudflare Access before deploying. ## Publish flow 1. Determine a slug (kebab-case, ~40 chars max). Confirm if ambiguous. 2. Write the artifact to: <share_dir>/deploy/<slug>/index.html 3. Run from <share_dir>: npx wrangler deploy 4. Report the live URL: https://<share_domain>/<slug> ## Update For "redeploy" or "update the published version": overwrite the existing <share_dir>/deploy/<slug>/index.html, preserve the analytics beacon, deploy. ## Protected publish For sensitive content, deploy under <protected_path_prefix><slug>/ (e.g. /c/<slug>/). Confirm with the user that a Cloudflare Access policy already covers <protected_path_prefix>* before claiming the path is protected. ## What not to do - Don't hardcode paths. Always read from the config file. - Don't deploy with unresolved relative refs — fail loud. - Don't claim a path is protected unless the user confirmed an Access policy. - Don't deploy artifacts containing secrets, API tokens, or PII — strip or refuse.
The skill auto-loads next time you open Claude Code. Test it: open a session, ask Claude to build a simple HTML page, then say "publish this as my-test". Watch it run the loop end-to-end.
// the moment it all becomes worth it
The whole loop, once everything above is in place:
claude code# You, in any Claude Code session, after Claude has built an HTML artifact: You: publish this as q2-proposal Claude: ✓ Wrote ~/share/deploy/q2-proposal/index.html (47 KB) ✓ Injected Cloudflare Web Analytics beacon ✓ Ran wrangler deploy Live at: https://share.yourdomain.com/q2-proposal
That's it. The URL is real, the page is live, the cert is valid. You can email it, link it from Notion, paste it in a Slack DM. The artifact escaped the sandbox.
// know if your prospect actually opened the proposal
<head> of every published artifact:html<!-- Cloudflare Web Analytics --> <script defer src="https://static.cloudflareinsights.com/beacon.min.js" data-cf-beacon='{"token": "YOUR_BEACON_TOKEN_HERE"}'></script>
The skill above already injects this on every publish — once you store your token at
~/.config/publish-artifact/cf-beacon-token (or wherever cf_beacon_token_path in
your config points), Claude reads it and substitutes. You'll see pageviews, referrers, and country
breakdowns in the Cloudflare dashboard within minutes of the first visit.
Privacy: Cloudflare Web Analytics doesn't use cookies, doesn't fingerprint, and is GDPR/CCPA friendly out of the box. You're not adding tracking debt.
// for the client work that should never have been on a public URL
Cloudflare Access (part of Zero Trust) puts an authentication gate in front of any path you choose. The lightest option: one-time email PIN. Recipient enters their email, gets a 6-digit code, enters it, sees the page. No accounts to create. No passwords to manage.
share.yourdomain.com with path
/c/* (convention: put all client work under /c/<client>/<slug>).
From now on, anything you publish under share.yourdomain.com/c/... is gated. Public stuff
stays public. The skill knows to ask before deploying to a protected path if you call something
"sensitive" or "client work."
Caveat: Cloudflare Access protects access, not extraction. If a recipient who has access takes a screenshot, the screenshot exists. Use it for "don't let the wrong eyes find this URL," not for DRM-grade containment.
// not in this guide, but worth your weekend
permanent. Stops link-rot.acme.share.yourdomain.com is one DNS record away from being a thing. Makes the deliverable feel bespoke.If you build any of these, I'd love to see them. Tag me on LinkedIn, or just publish your version to your share subdomain and send me the URL. That would be a fitting way to close the loop.