Analyze data with AI

Last updated Sep 30, 2026 Note

This page documents Sandbox SDK 0.x for existing applications. For new applications, refer to Build an AI code interpreter. To move an existing application to @cloudflare/sandbox 1.0, refer to Migrate from Sandbox SDK 0.x.

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

Prerequisites

  1. Sign up for a Cloudflare account ↗︎.
  2. Install Node.js ↗︎.

<details>

<summary>

Node.js version manager

</summary>

Use <a href="https://viteplus.dev/guide/env">Vite+ (<code>vp env</code>) ↗︎</a> to install and manage Node.js versions.

For supported Node.js versions, refer to the <a href="https://developers.cloudflare.com/workers/wrangler/install-and-update/#install-wrangler">Wrangler system requirements</a>.

</details>

You'll also need:

1. Create your project

Create a new Sandbox SDK project:

npmyarnpnpm

npm create cloudflare@latest -- analyze-data --template=cloudflare/sandbox-sdk/examples/minimal#v0
yarn create cloudflare analyze-data --template=cloudflare/sandbox-sdk/examples/minimal#v0
pnpm create cloudflare@latest analyze-data --template=cloudflare/sandbox-sdk/examples/minimal#v0
cd analyze-data

2. Install dependencies

npmyarnpnpmbun

npm i @anthropic-ai/sdk
yarn add @anthropic-ai/sdk
pnpm add @anthropic-ai/sdk
bun add @anthropic-ai/sdk

3. Build the analysis handler

Replace 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 },
                );
            }

            async function streamToBase64(stream) {
              const blob = await new Response(stream).blob();
              const buffer = await blob.arrayBuffer();
              const bytes = new Uint8Array(buffer);

              // Convert to base64
              let binary = '';
              for (let i = 0; i < bytes.length; i++) {
                binary += String.fromCharCode(bytes[i]);
              }
              return btoa(binary);
            }

            // Check for generated chart
            let chart = null;
            try {
                const { content, mimeType } = await sandbox.readFile("/workspace/chart.png", {
                    encoding: "none"
                });
                chart = `data:${mimeType};base64,${await streamToBase64(content)}`;
            } 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");
}

4. Set up local environment variables

Create a .dev.vars file in your project root for local development:

echo "ANTHROPIC_API_KEY=your_api_key_here\nSANDBOX_TRANSPORT=rpc" > .dev.vars

Replace your_api_key_here with your actual API key from the Anthropic Console ↗︎.

The SANDBOX_TRANSPORT is required to use the new file streaming APIs.

Note

The .dev.vars file is automatically gitignored and only used during local development with npm run dev.

5. Test locally

Download a sample CSV:

# Create a test CSV
echo "year,rating,title
2020,8.5,Movie A
2021,7.2,Movie B
2022,9.1,Movie C" > test.csv

Start the dev server:

npm run dev

Test 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..."
}

6. Deploy

Deploy your Worker:

npx wrangler deploy

Then set your Anthropic API key as a production secret:

npx wrangler secret put ANTHROPIC_API_KEY

Paste your API key from the Anthropic Console ↗︎ when prompted.

Caution

Wait 2-3 minutes after first deployment for container provisioning.

What you built

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

Next steps

Was this helpful?

YesNo

On this page

Analyze data with AI - 图1Docs

{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/sandbox/sdk/tutorials/analyze-data-with-ai/#page","headline":"Analyze data with AI","description":"Upload CSV files, generate analysis code with Claude, and return visualizations with the Sandbox SDK 0.x.","url":"https://developers.cloudflare.com/sandbox/sdk/tutorials/analyze-data-with-ai/","inLanguage":"en","image":"https://developers.cloudflare.com/sandbox/sdk/tutorials/analyze-data-with-ai/og.png?v=e08aad56cdaa5931","dateModified":"2026-09-30","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}


description: Build a Sandbox SDK 0.x testing pipeline that clones Git repositories, installs dependencies, runs tests, and reports results. title: Automated testing pipeline image: https://developers.cloudflare.com/sandbox/sdk/tutorials/automated-testing-pipeline/og.png?v=8bc6b418e93deff4


Skip to content

Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/sandbox/llms.txt
Use this file to discover all available pages before exploring further.