Analyze data with AI
Build an AI-powered data analysis system that accepts CSV uploads, uses Claude to generate Python analysis code, executes it in sandboxes, and returns visualizations.
Time to complete: 25 minutes
- Sign up for a Cloudflare account ↗.
- Install
Node.js↗.
Node.js version manager
Use a Node version manager like Volta ↗ or nvm ↗ to avoid permission issues and change Node.js versions. Wrangler, discussed later in this guide, requires a Node version of 16.17.0 or later.
You'll also need:
- An Anthropic API key ↗ for Claude
- Docker ↗ running locally
Create a new Sandbox SDK project:
npm create cloudflare@latest -- analyze-data --template=cloudflare/sandbox-sdk/examples/minimalyarn create cloudflare analyze-data --template=cloudflare/sandbox-sdk/examples/minimalpnpm create cloudflare@latest analyze-data --template=cloudflare/sandbox-sdk/examples/minimalcd analyze-datanpm i @anthropic-ai/sdkyarn add @anthropic-ai/sdkpnpm add @anthropic-ai/sdkReplace src/index.ts:
import { getSandbox, proxyToSandbox, type Sandbox } from "@cloudflare/sandbox";import Anthropic from "@anthropic-ai/sdk";
export { Sandbox } from "@cloudflare/sandbox";
interface Env { Sandbox: DurableObjectNamespace<Sandbox>; ANTHROPIC_API_KEY: string;}
export default { async fetch(request: Request, env: Env): Promise<Response> { const proxyResponse = await proxyToSandbox(request, env); if (proxyResponse) return proxyResponse;
if (request.method !== "POST") { return Response.json( { error: "POST CSV file and question" }, { status: 405 }, ); }
try { const formData = await request.formData(); const csvFile = formData.get("file") as File; const question = formData.get("question") as string;
if (!csvFile || !question) { return Response.json( { error: "Missing file or question" }, { status: 400 }, ); }
// Upload CSV to sandbox const sandbox = getSandbox(env.Sandbox, `analysis-${Date.now()}`); const csvPath = "/workspace/data.csv"; await sandbox.writeFile(csvPath, await csvFile.text());
// Analyze CSV structure const structure = await sandbox.exec( `python3 -c "import pandas as pd; df = pd.read_csv('${csvPath}'); print(f'Rows: {len(df)}'); print(f'Columns: {list(df.columns)[:5]}')"`, );
if (!structure.success) { return Response.json( { error: "Failed to read CSV", details: structure.stderr }, { status: 400 }, ); }
// Generate analysis code with Claude const code = await generateAnalysisCode( env.ANTHROPIC_API_KEY, csvPath, question, structure.stdout, );
// Write and execute the analysis code await sandbox.writeFile("/workspace/analyze.py", code); const result = await sandbox.exec("python /workspace/analyze.py");
if (!result.success) { return Response.json( { error: "Analysis failed", details: result.stderr }, { status: 500 }, ); }
// Check for generated chart let chart = null; try { const chartFile = await sandbox.readFile("/workspace/chart.png"); const buffer = new Uint8Array(chartFile.content); chart = `data:image/png;base64,${btoa(String.fromCharCode(...buffer))}`; } catch { // No chart generated }
await sandbox.destroy();
return Response.json({ success: true, output: result.stdout, chart, code, }); } catch (error: any) { return Response.json({ error: error.message }, { status: 500 }); } },};
async function generateAnalysisCode( apiKey: string, csvPath: string, question: string, csvStructure: string,): Promise<string> { const anthropic = new Anthropic({ apiKey });
const response = await anthropic.messages.create({ model: "claude-sonnet-4-5", max_tokens: 2048, messages: [ { role: "user", content: `CSV at ${csvPath}:${csvStructure}
Question: "${question}"
Generate Python code that:- Reads CSV with pandas- Answers the question- Saves charts to /workspace/chart.png if helpful- Prints findings to stdout
Use pandas, numpy, matplotlib.`, }, ], tools: [ { name: "generate_python_code", description: "Generate Python code for data analysis", input_schema: { type: "object", properties: { code: { type: "string", description: "Complete Python code" }, }, required: ["code"], }, }, ], });
for (const block of response.content) { if (block.type === "tool_use" && block.name === "generate_python_code") { return (block.input as { code: string }).code; } }
throw new Error("Failed to generate code");}Create a .dev.vars file in your project root for local development:
echo "ANTHROPIC_API_KEY=your_api_key_here" > .dev.varsReplace your_api_key_here with your actual API key from the Anthropic Console ↗.
Download a sample CSV:
# Create a test CSVecho "year,rating,title2020,8.5,Movie A2021,7.2,Movie B2022,9.1,Movie C" > test.csvStart the dev server:
npm run devTest with curl:
curl -X POST http://localhost:8787 \ -F "file=@test.csv" \ -F "question=What is the average rating by year?"Response:
{ "success": true, "output": "Average ratings by year:\n2020: 8.5\n2021: 7.2\n2022: 9.1", "chart": "data:image/png;base64,...", "code": "import pandas as pd\nimport matplotlib.pyplot as plt\n..."}Deploy your Worker:
npx wrangler deployThen set your Anthropic API key as a production secret:
npx wrangler secret put ANTHROPIC_API_KEYPaste your API key from the Anthropic Console ↗ when prompted.
An AI data analysis system that:
- Uploads CSV files to sandboxes
- Uses Claude's tool calling to generate analysis code
- Executes Python with pandas and matplotlib
- Returns text output and visualizations
- Code Interpreter API - Use the built-in code interpreter
- File operations - Advanced file handling
- Streaming output - Real-time progress updates
Was this helpful?
- Resources
- API
- New to Cloudflare?
- Directory
- Sponsorships
- Open Source
- Support
- Help Center
- System Status
- Compliance
- GDPR
- Company
- cloudflare.com
- Our team
- Careers
- © 2025 Cloudflare, Inc.
- Privacy Policy
- Terms of Use
- Report Security Issues
- Trademark