Cost & Token Usage Tracking
Navigation: README | Diagram Architecture | How It Works | Database Schema | Challenge Requirements | Cost Tracking
Overview
KidStory includes a built-in cost tracking system that logs every AI API call with token counts, duration, and calculated cost. All 9 agents are built with Google ADK v1.0 and run Gemini 2.5 Pro on Vertex AI — each agent call is captured with full token and cost breakdown. This runs only in development mode (npm run dev) — it is automatically disabled in production to avoid file I/O overhead.
How to Test Locally
# 1. Clone and install
git clone https://github.com/ajitonelsonn/Storybook-for-Kids.git
cd Storybook-for-Kids/storybook-for-kids-app
npm install
# 2. Set up environment variables
cp .env.example .env.local
# Fill in your Google Cloud credentials
# 3. Run in development mode
npm run dev
# 4. Generate a story in the app (http://localhost:3000)
# - Go to /create
# - Type or speak a story idea
# - Wait for generation to complete
# 5. View the cost logs
cat log/token-usage.jsonl
# 6. Run the cost report script for a formatted summary
npx tsx scripts/cost-report.tsLog Files (development only)
All logs are saved to the log/ directory (gitignored):
| File | Format | Content |
|---|---|---|
log/token-usage.jsonl | JSON Lines | One entry per agent call with tokens, cost, duration |
log/session-summaries.jsonl | JSON (pretty) | Aggregated summary per story/quiz session |
What Gets Logged
| Action | Agents Logged |
|---|---|
| Story generation | SafetyGuardian, StoryWriter |
| Image generation | Illustrator[page-1] through Illustrator[page-6] |
| Audio narration | Narrator[page-1] through Narrator[page-6] |
| Quiz generation | QuizMaster[0] through QuizMaster[4] |
| Learning recommendation | LearningAdvisor (skipped if cached) |
| Parent insights | ParentInsights (skipped if cached) |
| Story adaptation | StoryAdaptationAgent (skipped if cached) |
Log Entry Format
Each line in token-usage.jsonl:
{
"timestamp": "2026-04-28T08:40:32.920Z",
"sessionType": "story_generation",
"agent": "StoryWriter",
"model": "gemini-2.5-pro",
"inputTokens": 522,
"outputTokens": 983,
"thinkingTokens": 0,
"imageCount": 0,
"ttsCharacters": 0,
"durationMs": 16460,
"language": "en",
"cost": {
"input": 0.000653,
"output": 0.00983,
"thinking": 0,
"image": 0,
"tts": 0,
"total": 0.010482
},
"metadata": {
"pagesGenerated": 6,
"title": "Leo and the Sealyon's Singapore Adventure"
}
}Real Cost Example: One Full Story (6 pages, English)
Generated on 2026-04-28. Story: "Leo and the Sealyon's Singapore Adventure"
| Component | Tokens/Units | Cost |
|---|---|---|
| SafetyGuardian | 222 in + 30 out | $0.000578 |
| StoryWriter | 522 in + 983 out | $0.010482 |
| Narrator × 6 pages | 1,406 characters | $0.022496 |
| Illustrator × 6 pages | 6 images generated | $0.120000 |
| TOTAL | $0.153556 |
Cost Breakdown by Category
| Category | Cost | % of Total |
|---|---|---|
| Text generation (LLM) | $0.011060 | 7.2% |
| Image generation | $0.120000 | 78.1% |
| Audio narration (TTS) | $0.022496 | 14.7% |
Key insight: Image generation still dominates cost at ~78%. With Gemini 2.5 Pro, text generation now accounts for ~7% of total cost (up from <1% with Flash).
Quiz Cost Example (5 questions)
| Component | Tokens/Units | Cost |
|---|---|---|
| QuizMaster × 5 | ~4,600 in + ~150 out + ~1,500 thinking | ~$0.002 |
| TTS for questions × 5 | ~750 characters | ~$0.012 |
| TOTAL per quiz | ~$0.014 |
Pricing Reference (Gemini 2.5 Pro on Vertex AI)
| Resource | Price |
|---|---|
| Input tokens | $1.25 per 1M tokens |
| Output tokens | $10.00 per 1M tokens |
| Thinking tokens | $3.50 per 1M tokens |
| Image generation | ~$0.02 per image (gemini-2.5-flash-image) |
TTS (gemini-2.5-flash-preview-tts) | $0.000016 per character (estimate used in cost logger) |
Cost Report Script
Run anytime to see a formatted breakdown of all logged sessions:
npx tsx scripts/cost-report.tsOutput example:
╔══════════════════════════════════════════════════════════════╗
║ KIDSTORY COST REPORT ║
╚══════════════════════════════════════════════════════════════╝
┌─── STORY_GENERATION ───────────────────────────────────
│ Story: "Leo and the Sealyon's Singapore Adventure"
│ Language: en
│
│ ┌── Breakdown ──────────────────────────────────
│ │ SafetyGuardian in:222 out:30 $0.000051
│ │ StoryWriter in:522 out:983 $0.000668
│ │ Narrator[page-1] tts:244ch $0.003904
│ │ Narrator[page-2] tts:240ch $0.003840
│ │ ...
│ │ Illustrator[page-1] in:129 img:1 $0.020019
│ │ Illustrator[page-2] in:128 img:1 $0.020019
│ │ ...
│ └─────────────────────────────────────────────
│
│ TOTALS:
│ Input tokens: 1,595
│ Images: 6
│ TTS characters: 1,406
│ TOTAL COST: $0.143343
└──────────────────────────────────────────────────
═══════════════════════════════════════════════════
GRAND TOTAL (all sessions): $0.143343
═══════════════════════════════════════════════════Verification via Google Cloud Console
To cross-reference these local logs with actual billing:
Cloud Trace — GCP Console → Trace → filter by
agent/StoryWriter- Each span shows
gen_ai.usage.input_tokensandgen_ai.usage.output_tokens - These match the values in
token-usage.jsonl
- Each span shows
Vertex AI Metrics — GCP Console → Vertex AI → Model Monitoring
- Shows prediction count and token usage per model
Billing Reports — GCP Console → Billing → Reports
- Filter by Vertex AI API for overall cost validation
Production vs Development
Development (npm run dev) | Production (Cloud Run) | |
|---|---|---|
| Cost logging to file | ✅ Enabled | ❌ Disabled |
| Console output | ✅ Enabled | ❌ Disabled |
| OpenTelemetry spans | ✅ Enabled | ✅ Enabled |
| Cloud Trace export | ✅ (if configured) | ✅ Enabled |
The logTokenUsage() and logSessionSummary() functions check process.env.NODE_ENV === "production" and return immediately without any file I/O or console output.
Files
| File | Purpose |
|---|---|
lib/observability/costLogger.ts | Core logging functions |
scripts/cost-report.ts | CLI script to print formatted cost report |
log/token-usage.jsonl | Raw per-call log (dev only, gitignored) |
log/session-summaries.jsonl | Session aggregates (dev only, gitignored) |
