GuidesSecurity

Claude Live Artifacts: What Breaks, What Leaks, and How to Publish One Safely

HTMLvault Team·September 23, 2026·9 min read
Margo Sterling built Synergetics' new pricing calculator in an afternoon: a seat slider, a term toggle, and a total that recalculated as you dragged. It ran flawlessly inside Claude, which was the one place no prospect would ever open it. That gap is the practical story of Claude live artifacts: code that behaves perfectly in the chat can break, or leak a credential, once someone outside the chat needs to load it.

This guide covers what makes an artifact live, what Claude's sandbox does on your behalf, why fetch calls and API keys cause most export trouble, and a step-by-step path to a hosted link with a secret scan first. For the fundamentals of a Claude artifact, start with our primer on how artifacts work and how to share one.

What makes Claude live artifacts "live"

Many AI artifacts are static: a document, a table, a diagram. A live artifact executes code in the browser. In Claude that usually means one of two formats:

  • HTML with scripts: a page with inline JavaScript that responds to input, such as sliders, filters, or form math.
  • React components: JSX that Claude's environment compiles and renders, often with charting or icon libraries.

Both render client-side, meaning the viewer's browser does the work; no server computes the total when someone drags a slider. The code ships inside the page, so anyone who can open the page can read the code.

What the sandbox does for you

Inside Claude, the artifact runs in a sandboxed frame, an isolated browser context with its own rules. That sandbox quietly supplies a lot:

  • It compiles JSX, so a component file renders as a page.
  • It preloads common libraries, so imports resolve without a build step.
  • It restricts outbound network requests, so calls to your own APIs typically fail.
  • It can let the artifact call Claude at runtime, which works only inside Claude.

Download the file and all four go away. A React artifact becomes a component with no compiler, and its imports point at libraries that aren't there. The network restriction that made a broken fetch harmless in the chat no longer applies. Sandbox rules change over time; Anthropic's documentation has the current specifics.

What Claude's sandbox provides versus what an exported artifact must handle One artifact, two environments INSIDE CLAUDE'S SANDBOX JSX compiled for you Common libraries preloaded Outbound requests restricted A hardcoded key sits idle EXPORTED OR HOSTED FILE Needs a standalone HTML page Libraries bundled or linked Requests go out from the viewer Keys ship to every viewer LEAK
Claude's sandbox compiles code, preloads libraries, and blocks outbound requests, so an embedded key that sat harmless in the chat becomes readable by every viewer once the artifact is hosted.
Margo downloaded the calculator and opened it in a browser, where it rendered as a blank white page beneath a tab reading "Synergetics Pricing Experience." The sandbox had been compiling the React, loading the chart library, and styling every slider; the file had been taking the credit. The campaign email promising "a fully interactive pricing experience" was scheduled for 9 a.m.

Fetch calls and API keys: the usual failure and the usual leak

When an exported artifact breaks, the data layer is the usual suspect. Inside the sandbox, the numbers often came from sample data Claude wrote as a fallback, or from a fetch call that never succeeded.

The obvious fix is to make the fetch work: paste in the real endpoint and an API key and let Claude wire it up. Claude will, and the key lands in the page's JavaScript, because the page is the only place it can go.

That is the leak. Client-side code is delivered to every viewer's browser, where View Source shows it. Minifying it only makes it shorter. A link password controls who opens the page, but everyone who opens it can read the key. And because the sandbox blocked the request during testing, the key did nothing visible, so nobody had a reason to look for it.

A page you send outside the company should never hold a credential. Three workable alternatives:

  1. Bake the data in. Embed the numbers as a JSON object when the file is generated. For pricing, rate cards, or a lead-list snapshot, this is nearly always right.
  2. Call a public endpoint. If the data is already public and needs no key, a fetch is fine.
  3. Proxy it server-side. If the data must be live and private, a server you control holds the key and returns only what the page needs. That is an engineering project, not a prompt.

For finding keys in HTML, including ones that don't look like keys at first glance, see how to scan HTML for API keys before sharing.

How to move a live artifact to a hosted link, scan first

These steps assume HTMLvault's MCP server is connected to Claude, so Claude can call HTMLvault tools directly. The same sequence works through the REST API or by pasting the file in yourself.

The scan catches a hardcoded key only if it runs on the exported file, not the in-chat artifact, and any finding sends you back to strip it before a link exists.
  1. Ask for a standalone file. Have Claude convert the artifact into one self-contained HTML file:
    Convert this artifact into one self-contained HTML file.
    Plain JavaScript, no JSX, no build step, CSS inline.
    Remove every fetch call and API key; embed the pricing
    tiers as a JSON object. Add a mobile viewport meta tag.
  2. Read the script for live calls. Search for fetch, XMLHttpRequest, and any header carrying a token, and replace each with baked-in data or delete it. Do this before the scan, not instead of it: regex reliably catches keys with recognizable formats, but an unlabeled random string can slip past.
  3. Scan before you publish. Ask Claude to run scan_html on the file. HTMLvault's scanner is regex-based and costs zero tokens; it checks for api_key, ssn, financial, passport, address, person, dob, email, and phone. Teams and Enterprise workspaces can add an AI scan layer using their own Anthropic, OpenAI, or Google key; usage bills to that provider account, and HTMLvault never pays for tokens. Fix each finding and rescan until clean.
  4. Test outside Claude. Open the file in a desktop browser and on a phone. A total reading NaN is cheaper to find now than after a prospect does.
  5. Publish with create_link. Set an expiry that matches the deal or campaign window (Free links expire at 30 days; on Pro you can choose anything from one hour to never), add a link password if the audience is narrow, and send. HTMLvault links are never indexed by search engines. For long files, Claude can start with create_draft_link and add the rest with append_html.
  6. Read the analytics. get_analytics returns views, unique and repeat visitors, geo, device, referrer, scroll depth, and time-on-page. For a calculator, scroll depth shows whether prospects got as far as the total.

Worked example: a pricing calculator with a hardcoded key

Here is the calculator from the top of this post, taken through those steps.

The React version rendered correctly in Claude. Its tiers were supposed to come from an internal pricing service, but the sandbox blocked the request, so the component fell back to sample tiers Claude had written as defaults. On screen, nothing looked wrong.

Asked for a standalone file, Claude kept the data layer. This sat near the top of the script:

const PRICING_API_KEY = "sk_live_EXAMPLE0000000000000000";

async function loadTiers() {
  const res = await fetch("https://pricing-api.example.com/v2/tiers", {
    headers: { Authorization: `Bearer ${PRICING_API_KEY}` }
  });
  return res.json();
}

Hosted as-is, that page would have handed the live key to every prospect who opened it. Running scan_html before create_link returned one finding under api_key, and nothing was published.

The fix took three changes:

  1. Delete the key and the loadTiers function.
  2. Embed the tiers the calculator shows anyway:
    const TIERS = {
      starter: { perSeat: 18 },
      growth:  { perSeat: 29 },
      scale:   { perSeat: 41 }
    };
  3. Rescan, get a clean result, and publish with a 21-day expiry matching the campaign.

Two follow-ups fall outside the scanner's job. Rotate the key: it was pasted into a chat, so it has already left its system of record whether or not a prospect saw it. Then read what else the logic carries. A constant like MAX_DISCOUNT = 0.35 matches no secret pattern, but a prospect who opens View Source now knows your floor. Regex finds credentials and personal data; it can't tell which of your numbers are negotiating positions.

Margo traced the key to the wiki page she had pasted in for the tier names, titled "Pricing API — Internal Only, Do Not Share" and shared with the entire company since the second rebrand. Dwight read the title, then the sharing settings, then asked how many other chats that page had been pasted into this year. Nobody knew, which he wrote down as the answer.

Caveats: sandbox differences, external requests, and mobile rendering

Sandbox differences

A clean render in Claude proves the logic runs in Claude's environment, nothing more. Library versions there may not match what your standalone file loads, so a chart can shift or fail after export. And whatever the sandbox blocked may start working in the hosted copy, which is why you scan the exported file rather than trusting the version you saw in the chat.

External requests

Every script, font, or image loaded from another domain is fetched from the viewer's network when they open the page.

  • Corporate networks sometimes block public CDNs, and a calculator whose script never loads is a blank card. Inline small libraries where you can.
  • Each third-party request tells that party a viewer's IP address and that they opened something.
  • The scanner inspects the HTML you publish, not what an external script does after it loads.

HTMLvault's native analytics need no script from you. Any tracking code you inject is one more external request, so add it deliberately.

Mobile rendering

You likely built and tested on a laptop. On a phone, check for:

  • A missing viewport meta tag, which renders the page zoomed out and tiny.
  • Fixed pixel widths on containers and tables.
  • Hover-only tooltips, which don't exist on touch screens.
  • Slider handles too small to drag with a thumb.

Once the link is live, the device breakdown shows how many viewers are on phones. If it's most of them, the mobile layout is the page.

The page a prospect can actually open

If you're the marketer who asked for an interactive page, the goal was never the artifact. It was a page a prospect could open from a campaign email, on whatever device they had, drag a slider, and see a real number. Exported as one self-contained file, stripped of credentials, scanned, and published, the calculator becomes that page: it loads without Claude, carries no key, expires with the campaign, and shows you how far prospects scrolled toward the total and how long they stayed.

claudeclaude artifactsinteractive htmlsecret scanningapi keysmcp
HTMLvault

Share HTML securely — without losing your job.

The enterprise-grade platform for sharing HTML pages, reports, and dashboards with full PII scanning, access controls, and audit trails.

Start for free

Related Posts