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.

  1. The folder has index.html at the top, relative links and no prompts, keys or raw data.
  2. The report opens on the host in a fresh browser. The charts, downloads and the archive also open.
  3. Access is on, and direct file links ask for a login.
  4. The next scheduled run deploys only after its check passes.
  5. 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
Start Free Questions? Ask AI in our docs

No card required.

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.

Share:
Markdown version

Related Articles

↧
Loading PDF…