Skip to main content

Prompt Receipts

tests license: MIT

Prompts for making things with Claude Code and Codex, each shown with a receipt: what it cost, how long it took and what was switched on. Plus a script that prints the same receipt for your own runs in Claude Code, Codex, OpenCode, Qwen Code, Gemini CLI or GitHub Copilot CLI.

Browse the prompts · Browse receipts · Make a receipt for your own run · What's new

$ python3 receipt.py --prompt
Receipt v5.0 · Claude Code 2.1.292 · 6 Oct 2026, 8:16 PM EDT · no. 5631-4887
model    claude-opus-5-5 · effort medium
time     4 min (model working 4 min) · 1 prompt from me
cost     $0.83 (Claude Code's own total at API prices; the lines below add up to it)
         claude-opus-5-5
           input                  18 × $4.00/M   <$0.01
           cache read           273k × $0.20/M    $0.05
           cache write (1 h)     33k × $8.00/M    $0.27
           output               25k × $20.00/M    $0.51
extras   thinking 2 min · waiting on retries <1 s
prices   API list prices per million tokens ($/M), from LiteLLM 05166e2, 9 Oct 2026
billing  Max plan: a flat fee, not charged per run (your account today)
tokens   in 306k (273k cached) · out 25k
work     13 tool calls, 6 shell commands · web 0 · lines +537 -0
files    2 files written or edited (.html, .js)
add-ons  skills none (of 14 available) · MCP none (of 0 connected) · plugins none · subagents 0
hooks    none logged
memory   none loaded
settings bypassPermissions
id       680b62f5e76e (prompt fingerprint)
prompt   A mascot for my habit-tracker app: a round blob that breathes, blinks and
         giggles when you poke it. I'd like it in four moods: idle, happy, sleepy and
         surprised.

A round green blob mascot, with smaller versions in four moods: idle, happy, sleepy and surprised

That's plain Opus 5.5 making this blob mascot from one of the site's prompts. See the other models' versions, or this receipt on the site, made with --link.


Make a receipt for your own run

In the folder where you ran Claude Code:

curl -sO https://musharna.github.io/prompt-receipts/tools/receipt.py && python3 receipt.py

On Windows, in PowerShell:

curl.exe -sO https://musharna.github.io/prompt-receipts/tools/receipt.py; py receipt.py

Or install it as a command, receipt (also prompt-receipts):

uvx prompt-receipts              # run it without installing
pipx install prompt-receipts     # or keep it installed

It needs only Python 3.9 or later. It reads the logs these tools already keep, so it works on runs you've already finished:

Tool Add Logs it reads
Claude Code nothing ~/.claude/projects/, or under $CLAUDE_CONFIG_DIR
Codex --codex ~/.codex/sessions/, or under $CODEX_HOME
OpenCode --opencode ~/.local/share/opencode/opencode.db, or under $XDG_DATA_HOME
Qwen Code --qwen ~/.qwen/projects/, or under $QWEN_HOME
Gemini CLI --gemini ~/.gemini/tmp/, or under $GEMINI_CLI_HOME
GitHub Copilot CLI --copilot ~/.copilot/session-state/, or under $COPILOT_HOME

Run it somewhere else and it tells you where your sessions are; --list --all lists them from every folder.

A run with claude -p in a script or CI can be saved with --output-format stream-json --verbose > run.jsonl, and receipt run.jsonl reads it like a session log. That output has no prompt, effort, hooks or memory files, so the receipt says they aren't in it. If you still have the prompt, --asked prompt.txt puts it on the receipt, with a line saying it is your words and not the log's.

codex exec --json > run.jsonl saves a Codex run the same way. Its output has the replies, commands, files and tokens, but no prompt, model, version or times. --asked gives the prompt, and --model NAME names the model, so its tokens are priced; the receipt says both are your word. Codex logs only the run's total tokens, not each call's, so the price is at the model's standard rate.

Common uses

python3 receipt.py --list                  # this folder's recent sessions, numbered
python3 receipt.py --pick 2 --prompt       # a receipt for one of them, with your prompts
python3 receipt.py --hide cost --link      # leave out the cost and print a link to share
python3 receipt.py --turns --recipe        # a line per prompt, and the commands to rerun them
python3 receipt.py --replay LINK --run     # run someone's receipt again, in a new empty folder
python3 receipt.py --replay LINK --picture shot.png --run   # ...with a picture of what it made
python3 receipt.py --out receipt.png       # a picture, for posting where text gets mangled
python3 receipt.py --totals week --all     # cost, prompts and time by week, every folder

python3 receipt.py --json --prompt-id --out opus.json      # save one receipt per model,
python3 receipt.py --compare opus.json sonnet.json         # then set them side by side

What it shares

  • receipt.py itself never connects to the internet. It reads local files and prints text.
  • It never prints paths, your email, account ids or file contents. Your prompts and the model's reply appear only when you ask (--prompt, --reply, --recipe), and it stops if one holds an email address or a key.
  • --link puts the receipt after the # in the link, which browsers never send, so nothing is uploaded.
  • --bundle packs the files a run wrote, and --page puts your prompts, the model's replies and those files on one page, only when you ask. Their text is checked for email addresses and keys like --prompt.
  • --output-url only names where you'll put the page; receipt.py uploads nothing. The receipt site fetches it from there when someone opens the receipt.
  • Read the receipt before you share it. Prompts, tool names and times can say more than you mean to.

Choosing what it covers

Option What it does
--codex, --opencode, --qwen, --gemini, --copilot Use that tool's sessions instead of Claude Code ones
--list, then --pick N List this folder's recent sessions, then make a receipt for one of them
--all With --list or --pick: sessions from every folder
--last N Cover only your last N prompts, when one session held several tasks
--turns A-B Cover only prompts A to B (3, 3-5, 3- or -5). Its cost is worked out from those prompts' calls
SESSION.jsonl or ses_… Make a receipt for a log file, or an OpenCode session id, directly

Leaving things out

Option What it does
--hide cost,date Drop parts: version, date, model, time, cost, items (the priced lines), billing, tokens, work, files, output (the size of what it wrote and the replies), addons, hooks, memory, settings. Hiding the model or the cost hides the priced lines too, since they name both
--counts Show numbers instead of the names of skills, MCP servers, plugins, subagent types and memory files
--rename old=new Show one name as another. Stops with an error if the name isn't on the receipt, so a typo can't leave the real one in
--prompt Add your prompts, each one numbered. Home folders become ~, and it stops if a prompt holds an email address or a key
--asked FILE For a log that doesn't hold its prompt (claude -p output): put the prompt from FILE (or - for what you pipe in) on the receipt, checked like --prompt. The receipt says it is your words, not the log's, and a --record still vouches only for the log. It stops if the log holds its own prompt
--model NAME For a log that doesn't name its model (codex exec --json output): the model it ran on, so its tokens can be priced. The receipt says it is your word
--redact With --prompt, --asked, --reply, --recipe, --outcome or --reported: print the text with [email] and [key] in their place instead of stopping
--file-names Name the files the run wrote. Off by default: the receipt shows only how many and their types

Prompt by prompt

Option What it does
--turns Add a line per prompt: when you sent it, how long it ran, its cost (subagents included), tool calls and files. The receipt says whether the lines add up to the cost above
--reply Add the model's last reply, checked for email addresses and keys like a prompt
--outcome TEXT Add your own word on how it went, marked as yours
--recipe Add the commands that send the same prompts again, each with the model and effort it ran on (claude -p, codex exec, opencode run, qwen, gemini -p, copilot -p). Models give a different answer each time, so it reruns the run, not its output
--replay RECEIPT Show the rerun commands in a receipt link or saved receipt made with --recipe. With --run, run them one by one in a new empty folder (replay-<receipt no.>), with the model, effort and permission mode the receipt names, then print the new run's receipt. It runs only claude, codex, opencode, qwen, gemini or copilot, never through a shell, and says when the original ran with permission checks off. With --picture FILE (a .png, .jpg, .webp or .gif of what the original made), the picture goes into the new folder as look.png and the first prompt gets a line saying it's a picture of what this should look like. In a test of 5 gallery prompts, 3 runs each, the receipt with a picture made the same thing 15 times of 15, the receipt alone 10 and a picture alone 9 (the test)

Saving and sharing

Option What it does
--md, --json Wrap it for GitHub or Discord, or print it as JSON (hidden parts stay out)
--out FILE Save it to a .txt, .md, .json or .png file, or into a folder. A .png is a picture of a paper receipt, for posting where text gets mangled. It reads like one from a shop: what was asked for (with --prompt), what the run made, what it took, the total, and a barcode of the receipt's number. It prints alt text for the picture (1,000 characters at most) to paste in with it, and keeps a copy inside the PNG
--picture FILE With a .png: put a picture of what the run made on the receipt, under what was asked for. A .png goes on as it is, made smaller if it's wider or taller than the receipt is wide. A sound goes on as its spectrogram (time across, pitch up, louder brighter), and a video as 4 of its frames, each with a line saying how long it is. PNGs and WAVs need nothing else; other pictures, sounds (.mp3, .ogg, .flac…) and videos need ffmpeg (or set RECEIPT_FFMPEG to where it is)
--look LOOK With a .png: strip (the whole receipt, the default), card (cut down for a feed: the prompt large, the picture, the model, time, tool calls and the total; 1080 pixels wide and at most 1350 tall, so X, Bluesky and LinkedIn show it whole) or print (the strip set in a real font, drawn by Chrome, Edge or Chromium)
--theme THEME With a .png: the paper and ink, paper (the default), night, terminal, blueprint or pink. The barcode stays dark on light, so it scans on dark paper too
--report Also print a link to the report form with this receipt filled in
--link Also print a link that shows this receipt on the site. The receipt rides in the part after #, which your browser never sends, so nothing is uploaded. Long receipts make links too long for some chats; it warns over 2,000 characters
--share --link, and a link that sends the receipt to the gallery: a GitHub issue with the link filled in
--bundle FILE.zip Save one zip with the receipt, its JSON, a record, and the files the run wrote, plus RO-Crate metadata and a page that shows the receipt
--shot With --bundle or a .png: add a screenshot of the web page the run made (on a .png, it goes where --picture would), taken with Chrome, Edge or Chromium if one is installed. It shows the files in the bundle, served to the browser from your own computer only while the picture is taken; pictures the run didn't make aren't in it. On a .png, a run that made no page but a video or a sound gets its frames or its spectrogram instead, with no browser

What the run made

Every receipt says how much the run wrote: files 3 files written or edited (.html, .js ×2) · 612 lines, 24 KB · a web page, and replies 4 replies, 1,180 words. No names or text.

A run often makes its sounds, videos and pictures with a program it runs (a script, ffmpeg) rather than writing them itself. Those are counted on a line of their own: made 3 files changed in its folder while it ran (.mp4 ×3) · 76 MB · 3 videos, 0:16 in all. It is every file in the run's folder that changed while it ran and that its own tools didn't write, so a file you changed there at the same time counts too. Folders whose names start with ., node_modules, __pycache__ and virtual environments aren't looked in, nor is your home folder. They go in the record, the bundle and the page like the files it wrote.

Option What it does
--page FILE.html Save one page with the receipt, every prompt and the model's full replies, and each file the run made. A web page the run made runs inside it, in a sandboxed frame, with the .js, .css, pictures, sounds and videos it uses from the run put inside, so the one file works anywhere. Pictures show, and sounds and videos play, up to 16 MB in all; past that, with ffmpeg installed, a sound or video is shown as a smaller copy (the same bytes each time it's made), and without it, by its size. Text files are shown as the run wrote them, or as they are on disk now when only edited. With --redact, emails and keys are replaced instead of stopping
--output-url URL With --page: say where you'll put the page (an https:// address, such as a GitHub Pages site). The receipt gets a page line with the address and the start of the page's SHA-256. When someone opens the receipt's --link, the site fetches the page, checks it, and shows it only if it matches byte for byte. Upload the file unchanged; the site where it lives must let other sites read it, as GitHub Pages, raw.githubusercontent.com and gists do
python3 receipt.py --page run.html --output-url https://you.github.io/runs/run.html --link

To post the run as a picture, with the prompt, a screenshot of what it made and the cost on one receipt:

python3 receipt.py --prompt --shot --out receipt.png

For a feed, the card shows the same run in one screen, in the night theme here:

python3 receipt.py --prompt --shot --look card --theme night --out card.png

For a run that made a sound, put its spectrogram there instead:

python3 receipt.py --prompt --picture song.wav --out receipt.png

No site of your own? A public GitHub gist works, and --page prints these steps:

receipt --page run.html                            # make the page
gh gist create --public run.html                   # put it in a gist
gh api gists/ID --jq '.files[].raw_url'            # ID ends the gist's address
receipt --page run.html --output-url RAW_ADDRESS --link

Making the page again gives the same bytes, so the uploaded copy matches; if it doesn't (the run went on, or you hid something else), receipt.py says so and you upload the new one. The raw address names that version of the gist, so a later edit to the gist can't change what the receipt points at.

From someone's post

Found a post that shares a prompt, what it cost and what it made? --reported FILE makes a receipt of what the post says. FILE holds key: value lines: post (its address, needed), and any of by, date, tool, model, effort, time, cost, tokens in, tokens cached, tokens out, made and prompt (put it last; it can run over several lines).

$ receipt --reported post.txt
Reported v7.13 · Claude Code · 7 Oct 2026
REPORTED from a post, not read from a log: what it says, unchecked; no receipt number or
         record
post     https://musharna.github.io/prompt-receipts/#p1 · by Prompt Receipts
model    claude-opus-5-5 · effort medium
time     4 min
cost     $0.80 (the post's own figure)
         $0.65 at API prices for the model and tokens it states; more if some were cache
         writes
tokens   in 439k (402k cached) · out 21k
made     a full page with captions and speech bubbles
prompt   A three-panel comic page, drawn as a finished image file, about a pigeon who's
         convinced he's the town postman, for the kids' corner of our local newsletter.

Every look carries a REPORTED stamp, and anything the post leaves out reads "not stated". With a model and tokens, they are priced next to the post's own figure. That price is the least the run could have cost, since posts rarely say which tokens were cache writes. The receipt has no number, barcode or record, because there's no log to vouch for. It goes with --out, --look, --theme, --picture, --link, --share and --redact.

More than one run

Option What it does
--compare A.json B.json Set receipts side by side, for one prompt run on several models or efforts
--prompt-id Add a short fingerprint of the prompt (not the prompt itself), so --compare can tell runs of one prompt
--combine A.json B.json Add up receipts for one task spread over several sessions

Totals over time

--totals adds up every prompt in this folder's sessions (every folder's with --all), by day, week, month, folder or model:

$ python3 receipt.py --gemini --totals
Totals v6.0 · Gemini CLI · folder gwork · 9 Oct 2026 · by day
day              cost  sessions  prompts  time  tokens in / out
Fri 9 Oct 2026  $0.01         1        2  <1 s        62k / 312
---------------------------------------------------------------
total           $0.01         1        2  <1 s        62k / 312
Option What it does
--totals [BY] Add up cost, sessions, prompts, time and tokens by day (the default), week, month, folder or model. Each prompt's cost is worked out from its own calls at API list prices
--since DATE, --until DATE Count only prompts sent on or after, or on or before, a date (2026-10-01)

--json, --md, --out and --link work on totals too.

A record of what went in and came out

A receipt says what a run cost. A record says which files it made and what it was given, as SHA-256 fingerprints, so anyone holding a file can check whether it came out of that run. It holds no prompts, file contents or paths: only fingerprints of your prompts, the system prompt, the instruction files as they were loaded (CLAUDE.md, AGENTS.md), every tool result the model saw, and the files it wrote, plus the model, effort, settings and, for Codex, the git commit.

Option What it does
--record FILE Save a record of the run. Its fingerprint goes on the receipt. --hide, --counts, --rename and --file-names apply to it too
--verify RECORD FILES… Say for each file whether it came out of the run, went into it, or isn't in the record. One changed byte and it isn't
--sign KEY Sign the receipt (--out) and the record with an SSH key (ssh-keygen -Y sign); the signature goes next to each as .sig
--verify FILE Check the signature next to a receipt or record. Add --signers allowed_signers to check whose key signed it
--prices FILE Price with a newer copy of LiteLLM's model_prices_and_context_window.json instead of the one built in

A record is in-toto's Statement format, written in one byte form (sorted keys, no spaces), so its fingerprint is the same wherever it's made. It makes a run checkable, not repeatable: neither tool lets you fix the model's randomness. Records of short prompts can be guessed by trying likely prompts, and a signature made after the run proves only what the log said when it was signed.

A receipt after every Claude Code session

Put this in ~/.claude/settings.json (merge it with any hooks you already have) and every session leaves a receipt in ~/receipts when it ends:

{
  "hooks": {
    "SessionEnd": [
      { "hooks": [{ "type": "command", "command": "python3 ~/receipt.py --hook --out ~/receipts/" }] }
    ]
  }
}

Keep receipt.py in your home folder for this, or change the path. Sessions with no prompts leave no receipt.

Plan use on the status line

On a Pro or Max plan, Claude Code tells the status line how much of your 5-hour and weekly limits you've used. --statusline shows that, and keeps the readings so a receipt made later can say how much of your plan a run took:

{ "statusLine": { "type": "command", "command": "python3 ~/receipt.py --statusline" } }
Opus 5.5 · $0.28 · 3 s · 5-hour 2% · weekly 51%

Receipts for sessions that ran with it get a limits line, such as 5-hour +7%, weekly +2% while this ran. Other sessions running at the same time count toward the same limits, so the receipt says so. The readings are kept in ~/.cache/prompt-receipts/limits/ (under $XDG_CACHE_HOME if set, %LOCALAPPDATA% on Windows), only when a number changes. To keep the status line you have, call both from one script, passing each the same input:

#!/bin/sh
input=$(cat)
echo "$(echo "$input" | ~/.claude/my-statusline.sh) · $(echo "$input" | python3 ~/receipt.py --statusline)"

Good to know

  • Claude Code deletes session logs after 30 days unless you raise cleanupPeriodDays in ~/.claude/settings.json. Logs can be large, so check your free disk space before raising it a lot.
  • If you moved a tool's folder with CLAUDE_CONFIG_DIR, CODEX_HOME, XDG_DATA_HOME, QWEN_HOME, GEMINI_CLI_HOME or COPILOT_HOME, the receipt looks there.
  • For a whole Claude Code session, the cost and tokens are Claude Code's own totals and include subagents, added up over every time the session was opened. The lines under the cost price each call at API list prices, and the receipt says whether they add up to Claude Code's total or by how much they miss; long sessions that were compacted many times can miss. With --last, the cost is worked out from that part's calls.
  • A Claude Code session resumed into a new log file gets its own receipt; --combine adds them up.
  • Codex, Qwen Code, Gemini CLI and Copilot CLI don't log a price, so their cost is worked out from their token counts at API list prices (Alibaba Cloud's for Qwen models, Google's for Gemini). OpenCode's own figure is used when it has one. Open models, which many providers sell (MiMo, Nemotron, DeepSeek, GLM, Kimi, MiniMax, Mistral, Llama, gpt-oss), are priced at OpenRouter's list price, and the receipt says so. The built-in prices are LiteLLM's, dated on the receipt; python3 tools/update_prices.py refreshes them.
  • What you pay can differ from list prices. Qwen OAuth's free allowance isn't charged; Copilot bills a plan's premium requests or AI credits, and the receipt shows the AI credits when the log has them; a key for a service like OpenRouter is charged at that service's prices.
  • Qwen Code's background helpers (its memory extractor) make API calls of their own. They are counted, since Qwen Code logs them.
  • --record and --bundle cover all six tools. Files made by shell commands aren't in a bundle or on a page.
  • The billing line reads your account as it is today, so it shows your plan now, not necessarily when the run happened. A run on a local model (Ollama, LM Studio) says so on the model line.
  • Files count what the edit tools wrote, subagents' included. A file the run changed again with a shell command counts as the run left it on disk. Files made only by shell commands aren't counted, and what subagents read isn't in a record.
  • With --turns, some background work Claude Code prices itself (titles, summaries) logs no calls, so no prompt can hold it; the receipt says how much it is. A session that's still running keeps writing its log, so its numbers can move a little between runs.
  • Codex logs don't record hooks, and OpenCode's, Qwen Code's, Gemini CLI's and Copilot CLI's record neither hooks nor memory files. Gemini CLI logs no version, effort or approval setting either. Claude Code logs a hook run only when the hook prints something, so hook counts are a floor.
  • If a log has your prompts but no replies or token counts, the receipt says so: the tool may have changed how it writes logs. Please open an issue.
  • Checked on Linux, macOS and Windows (Python 3.9 and 3.13) on every change, and by hand on WSL and Windows 11.
  • A receipt is text you can edit. It shows what someone reports, not proof, unless it's signed by a key you trust.

The prompts

One prompt, run once on each model: Opus, Sonnet and Haiku 5.5 in Claude Code, and GPT-5.6 Sol, Terra and Luna in Codex

Each prompt on the site was run once on plain Claude Code (Opus, Sonnet and Haiku 5.5) and on GPT-5.6 Sol, Terra and Luna in Codex, all at medium effort, plus GPT-6-Astra, Codex's default model. Every run shows what came out, what it cost and how long it took, and links to its receipt.

Tried one? Use the "Tell us how it went" button on its card. Runs that didn't work are as useful as ones that did.

The gallery shows every run on the site and ones people send in: what each made, whether it worked, what it cost and how long it took, grouped by prompt, with a summary for each model. Play it opens what a run made when it's something a browser opens (66 of the 308): a page, a toy or a 3D scene, as the run left it, from play/ (play/runs.json gives each page's run by its receipt number).

To add yours, run receipt.py --prompt --turns --recipe --redact --share in the folder you worked in. That shows how you made it: each prompt you sent, with its time, cost and what it did, and the commands to run them again (--turns 3-5 covers only prompts 3 to 5). Or paste your --link into the gallery's Add yours box, or open the link and press Add to the gallery. Each opens a GitHub issue with the link filled in, where you can say whether it worked and what it made. A bot replies with the receipt as the gallery will show it (a run of several prompts shows the first and how many), or says why it can't go in, and it goes in when the site's owner adds the gallery label. Everything in it is public, so leave out anything private first (--redact, --hide prompt).

The gallery can't check a receipt against the log it came from, since a link can be edited, so receipts sent in are marked as sent. Reported ones keep their REPORTED badge. tools/gallery.py does the checking.

License

The code (tools/receipt.py, the tests and the site's scripts) is MIT: see LICENSE. Prompts and page text are CC BY 4.0: see LICENSE-prompts. The outputs were made by the models named on each card.

Metadata

Release files for prompt-receipts 7.13

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for prompt-receipts 7.13
File Size Uploaded
prompt_receipts-7.13.tar.gz 163.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for prompt-receipts 7.13
File Interpreter ABI Platform
prompt_receipts-7.13-py3-none-any.whl Python 3 none any Details

Total release size: 268.7 kB

Release files / prompt_receipts-7.13.tar.gz

Download URL prompt_receipts-7.13.tar.gz
Size 163.4 kB
Tags Source
SHA-256 checksum
How to use checksums
f4b7436bd91525f1ca7279a7067e30d72eef718da39076ca646b7a5ae88fc55c
BLAKE2b-256 checksum
How to use checksums
14d7f576707a22c0b8d31c280735d8d69d3d6ff07db0ad350d691f9ef05ff785
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / prompt_receipts-7.13-py3-none-any.whl

Download URL prompt_receipts-7.13-py3-none-any.whl
Size 105.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
71c8172c9674dbbd11a1fb9d6f9f12f3916ce4de58348c015db04e739ea262c4
BLAKE2b-256 checksum
How to use checksums
d955c4b51772386f32fdcae66fd5c49a4f31820c4d91c62b389ae3f956a81a9f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release history Release notifications | RSS feed

This release

7.13 This release

2 release files

7.12

2 release files

7.11

2 release files

7.10

2 release files

7.8

2 release files

7.6

2 release files

7.5

2 release files

7.4

2 release files

7.3

2 release files

7.2

2 release files

7.1

2 release files

7.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page