# Publish a weekly client report to one link that updates itself · Stacktree

Source: https://stacktr.ee/workflows/recurring-client-report

[Skip to content](#main) [Stacktree](/)[Developers](/developers)[Agents](/agents)[Docs](/docs)[Use cases](/use-cases)[Pricing](/pricing)[Blog](/blog)[Dashboard](https://app.stacktr.ee)[Sign in →](https://app.stacktr.ee)      By [ Steve Smith ](/about) · Founder, Stacktree  ·  Last updated September 20, 2026          workflow

#  Publish a weekly client report to one link that updates itself.

   The client bookmarks one URL. Every week your agent, an n8n workflow, or a CI job renders fresh HTML and replaces the page in place, so the link you sent months ago still opens this Monday's numbers. Gate it with a passcode or their email domain; they never create an account.

  [ Get started free ](https://app.stacktr.ee/?join=1&from=seo_workflows_recurring_client_report)   install npx stacktree-install
Copy
     No card · 3 pages free · about a minute

##  How do you send a client a report that stays current?

Publish the report once and send one link. Each week the agent renders fresh HTML and calls update_site on the same page, so the client's bookmark always shows the current numbers. No re-sending, no v3 attachments. Add a passcode or an email gate; the client never creates an account.

## Why one link beats a weekly attachment

 A weekly report sent as an attachment forks every week: report_final.pdf, report_final_v2, the one from the email thread the new stakeholder was not on. A single URL cannot fork. Whoever opens it sees the current version, and when someone asks in March what January looked like, you regenerate that view instead of excavating email.

 This is the most common real workflow on Stacktree. Recurring client briefs are the biggest single category of pages people publish, ahead of one-off reports and audits, and the update-in-place primitive is why: the second send costs nothing, so the report becomes a place rather than a file.

 What the client receives is a finished page, not a portal. See [a live example report](/examples/monthly-performance-report), a fictional monthly performance report published exactly this way, or browse [the whole gallery](/examples).

## Typical flow

  - Monday, 8am: a schedule fires. Your agent (or an n8n workflow, or a GitHub Actions cron) pulls the week's numbers.
 - It renders them as one self-contained HTML file: KPI band on top, channel table, what moved, what stalled.
 - First run only: it publishes with publish_html and you send the returned URL to the client, with a passcode or gated to @client.com. Filing it under the client with client: "Acme" puts it behind their space.
 - Every later run: it calls update_site with the same site id. Same URL, new numbers.
 - You check the share-link records to see who opened it before the call.

## Three ways to automate the schedule

 From the agent itself. Any MCP client that runs on a schedule can own the whole loop: render, `update_site`, done. The agent keeps the site id from the first publish.

 From n8n. The [n8n-nodes-stacktree community node](/n8n) has publish and update operations. Schedule trigger, query node, LLM or code node renders the HTML, Stacktree node updates the page, Slack node tells the channel.

 From CI. The GitHub Action pins the site id and replaces in place on every run:

```
`- uses: stevysmith/stacktree-actions@v1
  with:
    file: dist/weekly-report.html
    api-key: ${{ secrets.STACKTREE_API_KEY }}
    site-id: ${{ vars.STACKTREE_SITE_ID }}`
```

 Omit `site-id` on the first run, then pin the returned id so the URL stays stable.

## What it costs, honestly

 Free keeps 3 pages for 7 days each with passcodes included, which is enough to trial the loop for a week. A weekly link that must not die wants a page with no expiry, and that starts on Solo at $19 a month, which also adds the email-domain gate, open counts, and serving the report from your own domain instead of stacktr.ee.

## Run it now

### 1. Paste one line into your agent

```
`Fetch and follow https://stacktr.ee/prompt.md, then publish this week's report as a private link and update the same URL on every future run.`
```

 Works in any agent that can fetch a URL. [The instructions](/prompt.md) are plain Markdown you can read first.

### 2. Install once

```
`npx stacktree-install`
```

 Configures Claude Code, Cursor, Codex CLI, OpenCode, or Amp. On Claude.ai, add the connector URL `https://api.stacktr.ee/mcp` instead; [one-click setup](/claude-ai-connector).

### 3. No signup: curl it

```
`curl -X POST https://api.stacktr.ee/sites -F file=@weekly-report.html`
```

 Publishes anonymously: a private URL that lives 24 hours, no account and no key. The response includes a claim token so you can keep the page and start updating it in place.

FAQ

## Frequent questions

     Does the link change when I update the report? +  No. That is the point of the workflow. update_site replaces the content under the same URL, so the link you sent in January still opens this Monday's report. A replace also does not count as a new publish against your page allowance.   Does the client need an account to open it? +  Never. The unguessable URL is the credential. If you add a passcode, they type it once; if you gate by their email domain, anyone @theirco.com passes a one-time magic-link check. Nothing to install, nothing to sign up for.   How do I know they actually read it? +  Give each recipient their own share link and Stacktree records who opened theirs and when. From Solo you also see opens, unique viewers, and when the page was last read; Studio adds time on page, scroll depth, and an attention heatmap, all aggregate rather than surveillance.   Can I run this on the free plan? +  You can trial it: free keeps 3 pages, each live for 7 days, with passcodes included. A standing weekly link wants a page that does not expire, and that starts on Solo at $19 a month, which also adds email-domain gates, your own domain, and open counts.
Keep reading

## Related guides

   -  [ Have your agent publish its own run report as a link End every agent run with a link, not a wall of terminal text: the agent renders an HTML run report, calls publish_html. ](/workflows/agent-publishes-its-own-report)
-  [ Send a client report as a link The one-off version of this workflow, and why links beat PDFs. ](/send-client-report-as-link)
-  [ Host an agent-built dashboard When the recurring thing is a dashboard rather than a document. ](/workflows/agent-built-dashboard)
-  [ Client spaces One address per client that every weekly report files behind. ](/client-spaces)
-  [ Publish from n8n The community node this workflow runs on when n8n owns the schedule. ](/n8n)
-  [ Example deliverables Live fictional reports showing the finished form. ](/examples)
-  [ All workflows The other three recipes. ](/workflows)

References

## Sources and further reading

   -  [ stacktree-actions on GitHub ↗ The composite action: file or folder in, private URL out, site-id pinning for stable links. ](https://github.com/stevysmith/stacktree-actions)
-  [ n8n docs: community nodes ↗ How to install n8n-nodes-stacktree, self-hosted or on n8n Cloud. ](https://docs.n8n.io/integrations/community-nodes/installation/)
-  [ Google: Gmail attachment limits ↗ The 25 MB cap that makes attachment-based reporting fragile in the first place. ](https://support.google.com/mail/answer/6584)

##  Send the report once. Never send it again.

 Publish this week's report free, no card. If the loop sticks, permanence starts at $19 a month.

 [ Sign up free → ](https://app.stacktr.ee/?join=1&from=cta_workflows_recurring_client_report)   install npx stacktree-install
Copy
       Private hosting for the HTML your agents make.

[](https://betalist.com/startups/stacktree?utm_campaign=badge-stacktree&utm_medium=badge&utm_source=badge-featured)[Featured on](https://devhunt.org/tool/stacktree)[](https://buildlist.io)[Get started free](https://app.stacktr.ee/?join=1)

## Product

- [Templates](/templates)
- [Example deliverables](/examples)
- [Custom domains](/custom-domains)
- [Client feedback](/client-feedback-loop)
- [One-time links](/one-time-view-links)
- [See how pages get read](/page-engagement)
- [Made with Stacktree](/made-with)
- [Security](/security)
- [Watch the demo](/demo)

## Agents

- [All integrations](/agents)
- [Claude Code](/claude-code)
- [OpenAI Codex](/codex)
- [Cursor](/cursor)
- [Claude.ai connector](/claude-ai-connector)
- [MCP server](/mcp-publish-html)
- [Deploy from Claude Code](/deploy-html-from-claude-code)
- [Skills](/skills)
- [Slack app](/slack)
- [n8n node](/n8n)
- [Agent payments (x402)](/x402)

## Alternatives

- [All comparisons](/alternatives)
- [Head-to-head comparisons](/compare)
- [Tiiny Host](/tiiny-host-alternative)
- [GitHub Pages (private)](/github-pages-private-alternative)
- [Vercel](/vercel-alternative-for-agents)
- [ngrok](/ngrok-alternative-for-html)
- [Display.dev](/display-dev-alternative)
- [Static.app](/static-app-alternative)
- [OpenAI Codex Sites](/openai-codex-sites-alternative)
- [here.now](/here-now-alternative)
- [Shippage](/shippage-ai-alternative)
- [Best private hosting](/best-private-html-hosting)

## Use cases

- [All use cases](/use-cases)
- [Share with clients](/share-with-clients)
- [Send a file to a client](/share-html-file-with-client)
- [Share Claude artifacts](/share-claude-artifacts)
- [Share Jupyter notebooks](/share-jupyter-notebook-html)
- [Host Storybook privately](/host-storybook-privately)
- [Architecture diagrams](/share-architecture-diagrams)
- [AI-generated reports](/host-ai-reports)
- [Internal HTML tools](/internal-tool-hosting)
- [Private HTML hosting](/private-html-hosting)
- [Vibe-coded page hosting](/vibe-coding-hosting)
- [Leave a website builder](/website-builder-migration)

## Learn

- [Blog](/blog)
- [Glossary](/glossary)
- [FAQ](/faq)
- [Agent-loop hosting](/agent-loop-hosting)
- [Why agents need a publish primitive](/blog/why-agents-need-a-publish-primitive)
- [MCP servers explained](/blog/mcp-servers-explained-for-developers)
- [What changed in the 2026-07 MCP spec](/blog/mcp-2026-spec-changes)
- [Sites in Codex explained](/blog/sites-in-codex-explained)
- [Private-by-default hosting](/blog/private-by-default-html-hosting)
- [An agent paid us $1 (x402)](/blog/agent-paid-to-provision-itself)
- [When a loop hits a paywall](/blog/loop-engineering-paywall)
- [Pricing](/pricing)
- [Self-host (new)](/self-host)
- [Changelog](/changelog)
- [Docs](https://stacktr.ee/docs)
- [About](/about)
© 2026 Stacktree · stacktr.ee

[Privacy](/privacy)[Terms](/terms)[Security](/security)[Dashboard](https://app.stacktr.ee)[npm](https://www.npmjs.com/package/stacktree-mcp)[Sitemap](/sitemap.xml)[llms.txt](/llms.txt)[API spec](/openapi.json)

---
Full markdown summary of the Stacktree marketing surface: https://stacktr.ee/llms-full.txt
