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, new Uint8Array(await csvFile.arrayBuffer()));
      // Analyze CSV structure      const structure = await sandbox.exec(        `python -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');}npx wrangler secret put ANTHROPIC_API_KEYDownload 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..."}npx wrangler deployAn 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