Cloudflare Pages and Netlify for AI-Generated Reports
Why reports belong on a static host
AI tools now make reports as web pages. A report can be an HTML summary with charts, a dashboard that reads a CSV, a set of Markdown notes or a PDF export. It can also be all of these in one folder. A static host (a service that serves plain files) such as Cloudflare Pages or Netlify serves that folder at a stable address. It can put the folder behind a login. You can replace the folder with the next run and keep the same link.
One rule saves the most trouble. Keep the report generator separate from the published folder. Prompts, scripts, API keys and raw data stay in your project. Only the finished output goes to the host, and only after it passes a quick check. A failed run then leaves the last good report online instead of an empty page.
Lay out the report folder
Give each report a predictable structure:
site/
index.html latest report
assets/ CSS, JavaScript, chart library, images
data/summary.csv data the charts load
files/report.pdf downloadable copy
archive/
2026-10-15/ last week's report, same layout
Use relative links (assets/style.css, not /assets/style.css), so that the report works in any subfolder, including the archive. Put index.html at the top level of the folder that you upload.
Choose the host
| Cloudflare Pages | Netlify | GitHub Pages | |
|---|---|---|---|
| Upload a finished folder | Dashboard drag and drop or Wrangler | Drag and drop or Netlify CLI | Commit to a repository |
| Deploy on every Git push | Yes, if you create the project from a repository | Yes | Yes |
| Restrict readers | Cloudflare Access with an emailed one-time code | Shared password on Pro plans | Private visibility only on GitHub Enterprise Cloud |
| Roll back a bad run | Rollback to this deployment | Publish Deploy on an earlier deploy | Revert the commit |
GitHub Pages sites are public on the internet even when the repository is private (GitHub docs). Use GitHub Pages only for reports that anyone can read.
First deploy on Cloudflare Pages
Run these commands in a terminal, from the folder above site/:
npx wrangler login
npx wrangler pages project create
npx wrangler pages deploy site
Wrangler prints the deployment address when it finishes. The production address of the project is <project>.pages.dev. In the dashboard, the same action is Workers & Pages > Create application > Get started > Drag and drop your files. Drag and drop accepts up to 1,000 files, and Wrangler accepts up to 20,000. Each file can be up to 25 MiB (Direct Upload docs). If you create a project by direct upload, you cannot connect it to a Git repository later. Decide now how future runs will deploy.
First deploy on Netlify
With the Netlify CLI, run:
netlify deploy --dir site
Without --prod, this command makes a draft deploy that you can open and review. When the draft is correct, publish it:
netlify deploy --prod --dir site
If you do not use the CLI, drag the folder onto app.netlify.com/drop. For later runs, drag the new folder onto the deploy dropzone at the bottom of the project’s Deploys page.
Restrict who can read it
Reports often contain revenue, client names or early findings. Set access before you send the link.
On Cloudflare, use Cloudflare Access. Add the One-time PIN login method under Zero Trust > Integrations > Identity providers. Then create an Allow policy. Use Emails for named readers, or Emails ending in for a whole company. The Enable access policy switch in the Pages project protects only preview deployments. The production address needs the extra steps in our Cloudflare Pages Access guide.
On Netlify, set a site password under Visitor access > Password Protection. Choose the option that protects all deploys (docs). Our Netlify guide explains the plan details.
Test in a private window. The report page, a direct link to data/summary.csv and a direct link to files/report.pdf must all ask for a login.
Update on a schedule without losing the last good report
A recurring report has three steps: generate, check, deploy. Run the deploy only when the check passes.
To update with GitHub Actions and Cloudflare Pages, store CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID as repository secrets. The token must have the Account, Cloudflare Pages, Edit permission. Cloudflare’s CI guide describes these steps. Then add a workflow such as this one:
name: Weekly report
on:
schedule:
- cron: "15 6 * * 1"
workflow_dispatch:
jobs:
report:
runs-on: ubuntu-latest
permissions:
contents: read
deployments: write
steps:
- uses: actions/checkout@v6
- run: ./generate-report.sh site
- run: test -s site/index.html
- uses: cloudflare/wrangler-action@v4
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy site --project-name=weekly-report
generate-report.sh stands for your own generator. If index.html is missing or empty, the test -s line stops the job, and nothing deploys. Add your own checks there, for example a minimum number of rows in the CSV. GitHub runs schedules with these rules (events reference). Times are in UTC by default. The shortest interval is five minutes. Runs can start late when GitHub is busy. In public repositories, GitHub turns off scheduled workflows after 60 days without repository activity.
You can also use a Claude Code scheduled task. Claude Code scheduled tasks (formerly routines) run a saved prompt in the cloud on a schedule. The prompt runs against a GitHub repository that you select. By default, Claude pushes its work to a branch that starts with claude/. If you connect the repository to a Cloudflare Pages project, each push to a non-production branch becomes a preview deployment. Each preview deployment has its own address (preview deployments). To publish, you review the preview and merge it into the production branch. A run that makes a broken report never reaches the production address.
With each runner, write each run into a dated folder under archive/ and into the top-level index.html. Then readers can compare weeks, and you can link to an older version again.
Roll back a bad run
On Cloudflare Pages, open Deployments in the project. Find the last good production deployment in All deployments. Choose Rollback to this deployment. Production switches immediately (rollback docs).
On Netlify, open the last good deploy and select Publish Deploy. If the project deploys from Git with auto publishing on, the next production deploy replaces the rollback. To prevent this, use Lock to stop auto publishing on the Deploys list until you fix the generator (manage deploys).
See whether people opened it
On Cloudflare Pages, enable Web Analytics in the project under Metrics (setup). It counts page views and visits. You can filter by path, referrer, country and device type. It does not tell you who the reader was. If Cloudflare Access is in front of the report, the Access authentication logs in the Zero Trust dashboard show which email signed in and when. If you need reading data for each page and each named person, send the PDF through a document-sharing tool instead. Our guide to verifying recipients and reviewing viewing activity describes this method.
Before you share the link
- The folder has
index.htmlat the top, relative links and no prompts, keys or raw data. - The report opens on the host in a fresh browser. The charts, downloads and the archive also open.
- Access is on, and direct file links ask for a login.
- The next scheduled run deploys only after its check passes.
- You know where the rollback button is.
A docs portal with Ask AI
and support tickets
Connect a repository, or describe your product to start. Each docs site has search, Ask AI, an API console, an MCP server and support tickets.
- Publishes from GitHub on every push
- Works with Mintlify repositories
- API console from your OpenAPI file
- MCP server and llms.txt for AI agents
- Ask AI and support tickets
- Analytics for people and AI agents
Frequently Asked Questions
Can a report run live queries instead of showing a snapshot?
A plain folder upload only serves files. For live data, add a server function on the host, such as Cloudflare Pages Functions or Netlify Functions. Keep API keys in the secret settings of the host (on Cloudflare, Settings, then Variables and Secrets). For most recurring reports, it is simpler to make the data when you build the report. That method also keeps working if the data source is down.
Related Articles

Add a Custom Domain to a Cloudflare Pages Site
Add a custom domain or www to a Cloudflare Pages site: set it up in Pages first, add the DNS record, fix stuck verification and redirect www.

What Is localhost:3000?
Your browser uses localhost:3000 to reach an app running on your own computer. Sending that address to someone else does not give them access to your app.

Move Exported Grok Website Files to Another Host
Export a Grok Build site to GitHub, deploy it on Cloudflare Pages, Netlify, Vercel or GitHub Pages, test it, then retire the grok.me copy.