Your AI tool has finished the work: a quarterly report, a pricing page, a pipeline dashboard. It renders and the numbers are right, but it has no address yet. Where it lives, who can open it, how long it stays open and who read it are still undecided. Settling those four things is secure AI artifact distribution.
This post is for the person whose AI tool (Claude, ChatGPT, Gemini, Cursor or an agent) produces reports and pages, and who decides where they go. The mechanics of sending any HTML file are in how to share HTML securely at work. This one covers what changes when an AI tool made the page and can publish it too.
The handoff: from finished AI output to a link someone opens
Secure AI artifact distribution is the step between a finished AI output and the person meant to read it. Four questions decide whether that step was governed or merely fast: what was in the page, who could open it, how long it stayed open, and where that is written down.
Start by mapping how output leaves your team now. Most of it travels four ways: attached to an email, pasted into a chat thread, copied into a shared doc, or uploaded to whatever host was quickest that afternoon. Each route answers one or two of the four questions. None answers all of them, and none tells you whether the page was read.
AI output strains those routes in three ways. There is more of it, so reviewing each page by hand is the first habit dropped under a deadline. It carries context nobody re-read, because the model wrote from whatever it was given. And the tool can publish on its own, so the handoff can happen mid-conversation with no human step unless you design one.
That last change is also the fix. If the destination answers the four questions and the AI tool can reach it directly, the governed route becomes the fast one. In practice, that is the difference between governing AI-generated deliverables and just producing more of them.
Generate anywhere, host where you own it
Most AI tools can give you a URL for a page they generated, and the convenience is real. But generating and hosting are different jobs with different owners, and a chat-hosted URL gives the hosting job to the vendor by default.
A page deployed from a chat platform lives on that vendor's infrastructure and domain, inside their account model. Their plan and workspace settings decide who can open it, how long it lasts and what record exists. Some tools offer no static export at all, so what gets deployed is a live build in their environment rather than a file you can move. For a workspace-private internal tool, that is often fine. Once the page goes to a customer, three things change:
- Branding and reputation. A proposal on a vendor's host puts the vendor's name in the address bar and builds that host's reputation, not yours. White-label domains put the link on your own name and your own sending reputation. Pro and Teams include one, Enterprise includes three, and a branded subdomain such as you.hvlt.io is the lighter option.
- The record. When someone asks who opened the page and when access ended, the answer should come from a system your organization controls, not a support ticket and a screenshot of a chat. The enterprise sharing checklist covers what that record should hold.
- Portability. You can swap one model for another, and you shouldn't have to pick a new host each time you do. An HTMLvault page is your own HTML, served as written: it carries its own CSS and fonts, its scripts run, and HTMLvault adds no stylesheet of its own. A report Claude wrote last quarter and one Gemini writes next week publish the same way, and leaving means taking the file with you.
HTMLvault doesn't write the HTML. It gives the finished page an address you own, checks it before it goes live and measures it after it lands. It is also the fallback when a chat platform's own storage misbehaves and an artifact will not save.
Publish from the tool that made it
You can copy HTML out of a chat window and paste it into an upload form, but that's the step people skip when the deadline arrives. Let the tool that wrote the page publish it.
Connect the MCP server to Claude, Gemini or Cursor (ChatGPT connects through a Custom GPT action schema), and the tool can call HTMLvault directly. scan_html shows what the PII and secret checks would find, without publishing anything. create_link publishes the page and sets its expiry. create_recipient_links gives each reader their own tracked URL to that page, so the analytics later say who read it, not just that someone did. When each reader needs their own version rather than their own link, create_links publishes up to 100 pages from one template in a single call, filling {{name}}-style placeholders from a vars map per row. A placeholder with no matching var passes through untouched; a var with no matching placeholder fails its row.
A single document can be up to 5 MB. For a long report written in sections, the model can start a draft with create_draft_link, send chunks of up to 200 KB with append_html and finalize on the last call. Nothing is public and no checks run until it is finalized.
Paste this prompt into Claude's project instructions or your agent's system prompt, and every report goes out the same way:
When a report is final, publish it to HTMLvault:
1. Run scan_html on the complete HTML. If it reports any
findings, list them for me and stop. Do not publish.
2. If the scan is clean, call create_link with the HTML and
expiry set to 7 days.
3. Call create_recipient_links on that link for: [names].
4. Reply with one line per recipient: name, then URL.
The same sequence runs without a chat window. Zapier, Clay or a script calls the REST API with an API key: POST /api/v1/links for one page, /api/v1/links/batch for up to 100 from a template, /api/v1/links/draft for append mode. There is no REST scan endpoint. The publish call does the checking: a refused publish returns the findings instead of a URL, so review happens in your script's error branch. If your pipeline produces a report fragment with charts, or a Word file, POST /api/v1/links/document builds a themed, self-contained page from it.
See what happened after you sent it
Per-link analytics record views, unique and repeat viewers, scroll depth, time on page, country and city, device and browser, and referrer. With one link per recipient, those numbers belong to a person: the finance lead read to the end, the sponsor stopped at the summary. Channel links (Pro and above) give one page a separate URL per channel with server-side UTM attribution. If the page should report into your own stack, add your GA4, Meta or HubSpot code.
The agent can read the numbers too. get_analytics returns them over MCP, so the tool that wrote and published a report can tell you a week later who opened it and how far they got. Webhooks send each view as it happens to Zapier, Clay or your own code, and from there to the CRM, so a recipient.viewed event can open the follow-up task.
Treat all of it as context, not a verdict. Three repeat visits from a second city and heavy scrolling on the pricing section usually means procurement, not your champion. Weigh it against what the account owner already knows. Scroll depth tells you where attention stopped, not why. And a report nobody opened may just have been unnecessary, because the decision was made in the meeting.
What generated markup carries that the page does not show
A model writes from the context it was given. If the prompt held a CRM export, a log snippet or a credential, the output can repeat it somewhere the rendered page doesn't show: a key in a fetch() header, contact rows in an inline JSON blob or a data- attribute, an internal filename in a meta tag, a signed storage URL on an image. In reports, the usual leak is the collapsed tab below the charts: a "raw data" section the model added, which reviewers scrolled past because it was closed.
Publishing drops HTML comments, so a note the model left in a comment is never served. Everything else in the markup is. Every publish and edit is checked against your account's PII and secret policy (regex, zero tokens), and every outside URL against Google's unsafe-URL lists. A refused publish returns the findings. On Teams and Enterprise, Publishing Rules decide which findings block. The guide to scanning the HTML for API keys covers what the checks catch and how to fix each finding.
When a finding is real, redact with context and keep what the reader needs. Show that six contacts share one company domain without printing six addresses. Show a credential's shape (Authorization: Bearer [redacted, 40 chars]) without its value. Rotate any key that appeared in a page that left your team, and rebuild whatever depended on it: a key in client-side code was never safe, only unnoticed.
Defaults for AI deliverables: expiry, password, retention, never indexed
There is no org-wide expiry default, so the default is whatever your prompt says. Put an expiry in the instructions your AI tool follows and every link it creates gets one. Over MCP, create_link accepts 1 hour, 24 hours, 3 days, 7 days, 30 days or never. On the web, Pro and above can also choose 1 year. Free links expire after 30 days. Match the window to the job: 24 hours for a daily status page, 7 days for a proposal under review, never for a reference page you keep current. Configurable expiry can be changed or extended after you send, so a short default costs little.
Revocation matters as much as expiry, because the reason to close a link rarely arrives on schedule. If the recipient list changes, a credential turns up in a sent page or the engagement ends, delete the link with delete_link or from the dashboard. Don't wait for the date.
Passwords are set on the web. On Pro and above you add one per link in the upload form or the links dashboard; MCP and the REST API cannot set one. For a sensitive report, let the agent publish, add the password before you send the URL, and send the password through a different channel. The password is checked on the server. A correct entry unlocks the page in that browser for up to a day, changing the password ends every earlier unlock, and a reader who doesn't have it can press "Ask for password" to email you. The details are in password-protected links.
Retention is one setting for the whole account; for an org member, the org owner's setting applies. It runs 7 days to 2 years on paid plans and 7 to 90 days on Free, counted from each link's expiry. After that, the content and per-visitor view data are deleted. There is no per-link retention and no way to set it through MCP or the API, so choose a data-retention window that fits the most sensitive thing your agents publish.
Never indexed needs no setting: every link is served noindex, with no robots file for anyone to forget. For pages hosted elsewhere, how AI crawlers are blocked is a separate topic. Together, these defaults give IT a short answer when it asks whether this is a tool defensible in procurement.
Test the pipeline with seeded examples
Before a team relies on the pipeline, feed it four examples built to fail in known ways. They show you where the controls are too weak, and where they're so heavy that people will work around them. Preview each one with scan_html, then publish it for real.
- A fake token. An invented, never-issued API key in a
fetch()header. The scan should flag it, and the publish should be refused with the finding. If it goes live, the policy is too loose for credentials. Never seed a real key, even a revoked one. - An email list. Made-up customer addresses in a collapsed tab below the charts. The scan should find every address. Then decide what ought to happen: in a client deliverable the addresses go, while an internal review might only need a password. On Teams and Enterprise, Publishing Rules can treat public and password-protected pages differently, and adding or removing a password re-runs them.
- An expired project. Publish a page with a 1-hour expiry and open it after the hour. Delete a live link and confirm the URL stops working. Check the account's retention window against what your policy says.
- A harmless summary. A clean one-page summary should go from prompt to link in one step. If it gets refused or needs three approvals, the pipeline is too heavy.
Rerun the set whenever the prompt, the rules or the tool changes. Security that people cannot use is merely a policy with better typography.
Honest trade-offs
- Documents, not stateful apps. HTMLvault hosts HTML pages that you distribute and measure. Scripts run, so a Chart.js dashboard works. A page that needs server-side sessions, per-user stored state or a database behind it needs a different kind of product.
- A regex scan is a net. It catches structured patterns (keys, emails, phone numbers, account numbers) at zero token cost. It won't catch an unreleased roadmap date, a discount you didn't mean to show, or margins in a collapsed tab. Teams and Enterprise can add a BYOK AI scan with their own Anthropic, OpenAI or Google key, which runs after the link is published. A person opening the source once still catches what both miss. See where regex and AI scanning each fail.
- Noindex is not "no forwarding." Keeping a page out of search closes one path. Anyone with the URL can open an unprotected link, and a forward only shows up as an unfamiliar city on someone's link. Passwords, short expiries, per-recipient links and deleting finished links close the rest.
- Automation stops at the password. MCP and the API cannot set one, so a fully automated pipeline publishes unprotected links. Send sensitive deliverables through the dashboard.
- Free is trial-shaped. 50 links a month and a 30-day expiry. Pro ($12/mo, $10/mo annual) adds unlimited links, configurable expiry, channel links and up to five webhooks.
Put the prompt from the publishing section into your project instructions and set the retention window once. From then on, every report your AI tool finishes goes out scanned, on your domain, set to expire in seven days, with a separate link for each reader. A week later, you can ask the same tool who read it.
