# AI Code Runner Sandbox (`automation-lab/ai-code-runner-sandbox`) Actor

Execute short JavaScript or Python snippets in a fresh bounded container process. Get structured status, stdout, stderr, parsed JSON, timing, and generated-file references for AI agents and automations.

- **URL**: https://apify.com/automation-lab/ai-code-runner-sandbox.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Developer tools, AI, Automation
- **Stats:** 23 total users, 19 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## AI Code Runner Sandbox

Run short **JavaScript or Python code in an Apify Actor** and receive one predictable execution record.

AI Code Runner Sandbox is made for AI agents, automation workflows, and data teams that need to execute generated transformations without maintaining a runner service. Every run starts in a fresh temporary directory, accepts optional JSON through standard input, captures stdout and stderr, and finishes with structured status data.

- 🧩 Choose Node.js 22 or Python 3
- 📥 Pass JSON to the snippet through stdin
- 📤 Parse JSON stdout into a ready-to-use `result`
- ⏱️ Enforce a 1–30 second wall-clock timeout
- 🛡️ Cap output, subprocess resources, and saved-file bytes
- 📁 Copy selected generated files to the run key-value store

> This is a bounded stateless process runner, not a persistent VM or interactive web shell. Version 1 does not install packages or retain a workspace between runs.

### What does AI Code Runner Sandbox do?

The Actor writes your source code to a new temporary directory and starts the selected runtime as a dedicated unprivileged user. It sends your input to stdin and captures the subprocess output.

When execution ends, the Actor writes exactly one row to the default dataset. A syntax error, exception, non-zero exit, timeout, or output overflow is represented as a terminal execution record rather than hidden behind an empty dataset.

A successful record can include parsed JSON and references to generated files. This makes the output easy to route into the next step of an agent, n8n scenario, Make workflow, webhook, or data pipeline.

### Who is it for?

#### AI agent builders

Use generated code as a small deterministic tool: calculate metrics, reshape JSON, validate an answer, or derive a decision before the next agent step.

#### n8n and Make users

Run a transformation that is awkward to express with visual mapping nodes. Consume the structured dataset row instead of parsing container logs.

#### Data and analytics teams

Apply a short Python calculation or JavaScript normalization to a JSON payload and save a compact CSV, JSON, or text artifact.

#### Developers and QA engineers

Reproduce a small algorithm, test a generated snippet, or validate output behavior with explicit exit codes and stderr.

### Why use this code execution Actor?

Running generated snippets inside a long-lived integration server creates operational work. You need runtime installation, process supervision, timeout handling, output capture, storage cleanup, and a stable API envelope.

This Actor packages those concerns into one call:

1. submit code and input;
2. wait for the Actor run;
3. read one dataset record;
4. optionally retrieve generated files from the run key-value store.

The stateless design is especially useful when jobs are independent and repeatable. There is no session to reset and no old workspace to contaminate a later result.

### Supported runtimes

| Language | Runtime | File used during execution | Notes |
|---|---|---|---|
| JavaScript | Node.js 22 | `main.mjs` | ES modules and built-in Node APIs |
| Python | Python 3 | `main.py` | Python standard library |

Version 1 intentionally provides the standard runtimes only. It does not run `npm install`, `pip install`, shell commands supplied as input, coding-agent CLIs, or persistent services.

Your snippet can create files inside its temporary working directory. List the relative paths in `saveFiles` if you want those files copied to the run key-value store before cleanup.

### Quick start: run JavaScript

Use this input in the Apify Console:

```json
{
  "language": "javascript",
  "code": "const chunks=[]; for await (const c of process.stdin) chunks.push(c); const input=JSON.parse(Buffer.concat(chunks).toString()); console.log(JSON.stringify({sum: input.values.reduce((a,b)=>a+b,0), count: input.values.length}));",
  "stdin": { "values": [3, 5, 8] },
  "parseJsonOutput": true,
  "timeoutSeconds": 5
}
```

The parsed `result` is:

```json
{
  "sum": 16,
  "count": 3
}
```

### Quick start: run Python

```json
{
  "language": "python",
  "code": "import json, sys\ndata = json.load(sys.stdin)\nvalues = data['values']\nprint(json.dumps({'sum': sum(values), 'count': len(values)}))",
  "stdin": { "values": [13, 21, 34] },
  "parseJsonOutput": true,
  "timeoutSeconds": 5
}
```

Python receives the serialized JSON on stdin. Write JSON and a trailing newline to stdout when `parseJsonOutput` is enabled.

### Input reference

| Field | Type | Default | Purpose |
|---|---|---:|---|
| `language` | `javascript` or `python` | `javascript` | Runtime for the snippet |
| `code` | string | required | Source code, up to 100 KB |
| `stdin` | JSON value or string | omitted | Data sent to standard input |
| `parseJsonOutput` | boolean | `true` | Parse complete stdout into `result` |
| `timeoutSeconds` | integer | `5` | Wall timeout from 1 to 30 seconds |
| `maxOutputBytes` | integer | `256000` | Combined stdout/stderr cap, maximum 1 MB |
| `saveFiles` | string array | `[]` | Up to 10 generated relative paths |
| `maxSavedFileBytes` | integer | `5000000` | Combined saved-file cap, maximum 10 MB |

Keep first runs small. A five-second timeout and no generated files are enough for most transformations.

### Output data

Each run produces one execution record with these fields:

| Field | Meaning |
|---|---|
| `status` | `succeeded`, `failed`, or `timed_out` |
| `language` | Runtime selected by the input |
| `exitCode` | Numeric subprocess exit code, or `null` after signal termination |
| `signal` | Terminating signal when applicable |
| `stdout` | Captured standard output |
| `stderr` | Captured standard error and spawn diagnostics |
| `durationMs` | Wall-clock execution duration |
| `timedOut` | Whether the wall timer stopped execution |
| `outputTruncated` | Whether the combined output cap was reached |
| `terminationReason` | `timeout`, `output_limit`, or `spawn_error` when applicable |
| `result` | Optional JSON value parsed from stdout |
| `resultParseError` | Parsing error when stdout is not valid JSON |
| `files` | Generated-file KVS references |
| `executedAt` | ISO 8601 terminal-record timestamp |

### Example execution record

```json
{
  "status": "succeeded",
  "language": "javascript",
  "exitCode": 0,
  "signal": null,
  "stdout": "{\"sum\":16,\"count\":3}\n",
  "stderr": "",
  "durationMs": 48,
  "timedOut": false,
  "outputTruncated": false,
  "result": { "sum": 16, "count": 3 },
  "files": [],
  "executedAt": "2026-07-24T12:00:00.000Z"
}
```

User-code failures still produce a record. Check `status` and `exitCode` before trusting `result`.

### Save generated files

A snippet may generate a CSV, JSON, HTML, or binary file in its working directory. Ask the Actor to preserve specific paths:

```json
{
  "language": "python",
  "code": "from pathlib import Path\nPath('summary.txt').write_text('validated: 42\\n')\nprint('done')",
  "saveFiles": ["summary.txt"],
  "maxSavedFileBytes": 100000
}
```

The `files` array contains the original relative path, key-value-store key, byte size, content type, and store ID. Missing files are skipped with a warning. Directories, paths outside the working directory, and files beyond the aggregate cap are not copied.

### Timeouts and output limits

`timeoutSeconds` is a wall-clock limit. When it expires, the Actor signals the whole detached subprocess group and follows with a forced kill if needed. This also stops child processes created by the snippet.

`maxOutputBytes` applies to stdout and stderr combined. Once reached, the Actor stops the process group, keeps the bytes already captured, sets `outputTruncated: true`, and reports `terminationReason: "output_limit"`.

Python also receives an address-space limit. JavaScript receives a V8 heap limit. The Actor container memory allocation is the final boundary for the complete run.

### Security model and limitations

The child process runs under dedicated UID/GID `10001`, with `no_new_privs`, a minimal environment, limited CPU time, file descriptors, and process count. The child does not receive `APIFY_TOKEN` or other parent environment variables.

The temporary directory is deleted after the terminal record and requested files are stored. State never carries into another run.

However, this Actor is not a hardware VM and does not claim protection equivalent to a specialized microVM sandbox. Submitted code can use the runtime's networking APIs. Do not place passwords, API keys, private records, or untrusted third-party secrets in code or stdin. Use it for bounded transformations where you control or have reviewed the snippet.

### Error handling

There are two error classes:

- **User-code outcomes** — syntax errors, exceptions, non-zero exits, timeouts, and output overflows produce a dataset record.
- **Actor contract failures** — missing language/code, invalid limits, oversized source, or unavailable runtime fail the Actor run.

This distinction prevents an invalid request from looking like successful code execution while preserving diagnostics for normal snippet failures.

If JSON parsing fails, the execution can still be `succeeded`. Read `stdout` and `resultParseError` to decide whether the data contract was met.

### How much does it cost to run JavaScript or Python code?

The Actor uses pay-per-event pricing:

- **Sandbox start:** $0.005 once per run
- **Code execution:** BRONZE price of $0.00087345 per terminal record
- higher subscription tiers receive automatic volume discounts

You pay for one execution event whether user code succeeds, exits non-zero, or times out, because the bounded runtime and diagnostic record are still produced. Apify Console shows the exact charge before and after each run. The execution tier was calibrated from measured cloud runtime cost and checked against equivalent PPE code-runner workflows.

### Integration with n8n and Make

A practical n8n workflow is:

1. HTTP Request node starts the Actor with JSON input.
2. Wait/poll node waits for the run to finish.
3. HTTP Request node reads the default dataset item.
4. IF node checks `status === "succeeded"`.
5. The next node consumes `result` or retrieves a generated file.

In Make, use an HTTP module to call the Actor API and map `result` fields into later modules. Keep code static in the scenario when possible and pass changing values through `stdin`.

### Apify API with cURL

```bash
curl "https://api.apify.com/v2/acts/automation-lab~ai-code-runner-sandbox/runs?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"language":"javascript","code":"console.log(JSON.stringify({ok:true}))","parseJsonOutput":true}'
```

Store tokens in secret variables. Never embed an Apify token inside the snippet itself.

### Apify API with JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/ai-code-runner-sandbox').call({
    language: 'javascript',
    code: 'const input = JSON.parse(await new Response(process.stdin).text());',
    stdin: { values: [1, 2, 3] },
    parseJsonOutput: true,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0]);
```

For production code, use a complete stdin reader like the Quick start example rather than the abbreviated line above.

### Apify API with Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/ai-code-runner-sandbox').call(run_input={
    'language': 'python',
    'code': "import json; print(json.dumps({'ok': True}))",
    'parseJsonOutput': True,
})
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items[0])
```

Use the returned `defaultKeyValueStoreId` when retrieving generated-file keys.

### Use through Apify MCP

Connect an MCP-compatible agent to:

`https://mcp.apify.com/?tools=automation-lab/ai-code-runner-sandbox`

#### Claude Code setup

```bash
claude mcp add --transport http apify-ai-code-runner "https://mcp.apify.com/?tools=automation-lab/ai-code-runner-sandbox"
```

#### Claude Desktop, Cursor, and VS Code setup

Add this HTTP server to the MCP JSON settings in Claude Desktop, Cursor, or VS Code:

```json
{
  "mcpServers": {
    "apify-ai-code-runner": {
      "url": "https://mcp.apify.com/?tools=automation-lab/ai-code-runner-sandbox"
    }
  }
}
```

Restart the client after saving the configuration. Claude Desktop users can then select the Actor tool; Cursor and VS Code users can enable it for the active agent session.

Example prompts for Claude Desktop or Claude Code:

- “Run this JavaScript reducer with the supplied JSON and return the parsed result.”
- “Execute this Python validation for five seconds and show stderr if it fails.”
- “Generate `summary.csv`, preserve it, and return the key-value-store reference.”

The MCP client still starts an ordinary Actor run. The same timeout, output, and file limits apply.

### Tips for reliable snippets

- ✅ Print only JSON to stdout when `parseJsonOutput` is enabled.
- ✅ Send progress or diagnostics to stderr.
- ✅ Keep source deterministic and pass changing data through stdin.
- ✅ Request only generated files that downstream steps need.
- ✅ Check `status`, `timedOut`, and `outputTruncated` before using results.
- ✅ Use integer and finite-loop boundaries in generated code.
- ❌ Do not start servers or background daemons.
- ❌ Do not depend on files from a previous run.
- ❌ Do not print secrets.

### Common workflows

#### Validate generated JSON

Run a Python schema check and return a compact list of violations.

#### Transform webhook payloads

Normalize inconsistent keys, dates, and nested arrays before writing to a CRM.

#### Calculate metrics

Compute weighted scores, aggregates, or statistical summaries that a prompt should not estimate.

#### Produce a small export

Create a CSV or text report and preserve it through `saveFiles`.

#### Test an AI-generated function

Call the function with fixed cases, emit assertions to stderr, and use the exit code as a gate.

### Troubleshooting

#### Why is `result` missing?

Enable `parseJsonOutput` and ensure stdout contains one complete valid JSON value. Extra debug lines make the combined text invalid; write those lines to stderr instead.

#### Why was my generated file not saved?

The path must be relative to the working directory, identify a regular file, exist when the snippet exits, and fit within `maxSavedFileBytes`. Check the Actor log for a skip warning.

#### Why did a successful process have a parse error?

Process success and JSON validity are separate. Exit code 0 means the runtime completed; `resultParseError` means its stdout did not satisfy the requested JSON contract.

#### Can I install a package?

No. Version 1 intentionally supports built-in Node.js and Python standard-library modules only. Bundle small logic directly in the snippet.

### Responsible and legal use

Only execute code you are authorized to run. Do not use the Actor to attack systems, evade access controls, mine cryptocurrency, distribute malware, or process data in violation of privacy and contractual obligations.

You are responsible for the behavior of networking calls made by submitted code and for the data passed through stdin. Review generated code before production use and avoid secrets.

### Related automation tools

Combine this runner with other automation-lab Actors when a workflow needs collection before transformation:

- [Tech Stack Detector](https://apify.com/automation-lab/tech-stack-detector) for technology data that a snippet can score or group
- [GitHub Scraper](https://apify.com/automation-lab/github-scraper) for repository data that a snippet can normalize
- [WHOIS Lookup](https://apify.com/automation-lab/whois-lookup) for domain records that a snippet can validate

Always verify that a related Actor fits your data source and compliance requirements.

### FAQ

#### Is every run stateless?

Yes. The Actor creates and removes a fresh working directory during each run. Only dataset output and explicitly saved KVS records remain in Apify storage.

#### Does a code exception fail the Actor run?

No. A normal user-code exception produces `status: "failed"`, the exit code, and stderr. Invalid Actor input or an internal runner failure fails the Actor itself.

#### Can code access my Apify token?

The child environment is explicitly scrubbed and does not contain `APIFY_TOKEN`. Do not paste tokens into code or stdin.

#### Is outbound networking disabled?

No. Runtime networking APIs remain available. Do not execute unknown hostile code or provide secrets.

#### Can I run several snippets in one Actor run?

Version 1 executes one snippet per run. Start separate runs for independent jobs so each has its own limits and execution record.

#### What happens after 30 seconds?

Thirty seconds is the maximum input timeout. The Actor terminates the subprocess group and returns a `timed_out` record.

#### Where are generated files stored?

Requested files are copied to the run's default key-value store. Their keys and store ID appear in the `files` array.

# Actor input Schema

## `language` (type: `string`):

Choose the runtime used for this execution.

## `code` (type: `string`):

JavaScript or Python source code. Read optional input from standard input and write output to standard output.

## `stdin` (type: `string,object,array,number,boolean`):

A string or JSON value sent to the snippet through stdin. JSON values are serialized automatically.

## `parseJsonOutput` (type: `boolean`):

When enabled, parse complete stdout and expose it in the result field. Parse failures remain visible in resultParseError.

## `timeoutSeconds` (type: `integer`):

Stop the full subprocess group after this many seconds.

## `maxOutputBytes` (type: `integer`):

Maximum combined stdout and stderr bytes captured before the subprocess is stopped.

## `saveFiles` (type: `array`):

Relative file paths created by the snippet to copy to the run key-value store. Up to 10 files.

## `maxSavedFileBytes` (type: `integer`):

Maximum combined size of generated files copied to the key-value store.

## Actor input object example

```json
{
  "language": "javascript",
  "code": "const chunks = [];\nfor await (const chunk of process.stdin) chunks.push(chunk);\nconst input = JSON.parse(Buffer.concat(chunks).toString() || '{}');\nconsole.log(JSON.stringify({ sum: input.values.reduce((a, b) => a + b, 0), count: input.values.length }));",
  "stdin": {
    "values": [
      3,
      5,
      8
    ]
  },
  "parseJsonOutput": true,
  "timeoutSeconds": 5,
  "maxOutputBytes": 256000,
  "saveFiles": [],
  "maxSavedFileBytes": 5000000
}
```

# Actor output Schema

## `overview` (type: `string`):

Default dataset view with status, runtime, exit details, captured output, parsed result, and generated-file references.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "language": "javascript",
    "code": `const chunks = [];
for await (const chunk of process.stdin) chunks.push(chunk);
const input = JSON.parse(Buffer.concat(chunks).toString() || '{}');
console.log(JSON.stringify({ sum: input.values.reduce((a, b) => a + b, 0), count: input.values.length }));`,
    "stdin": {
        "values": [
            3,
            5,
            8
        ]
    },
    "parseJsonOutput": true,
    "timeoutSeconds": 5,
    "maxOutputBytes": 256000,
    "saveFiles": [],
    "maxSavedFileBytes": 5000000
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/ai-code-runner-sandbox").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "language": "javascript",
    "code": """const chunks = [];
for await (const chunk of process.stdin) chunks.push(chunk);
const input = JSON.parse(Buffer.concat(chunks).toString() || '{}');
console.log(JSON.stringify({ sum: input.values.reduce((a, b) => a + b, 0), count: input.values.length }));""",
    "stdin": { "values": [
            3,
            5,
            8,
        ] },
    "parseJsonOutput": True,
    "timeoutSeconds": 5,
    "maxOutputBytes": 256000,
    "saveFiles": [],
    "maxSavedFileBytes": 5000000,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/ai-code-runner-sandbox").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "language": "javascript",
  "code": "const chunks = [];\\nfor await (const chunk of process.stdin) chunks.push(chunk);\\nconst input = JSON.parse(Buffer.concat(chunks).toString() || '\''{}'\'');\\nconsole.log(JSON.stringify({ sum: input.values.reduce((a, b) => a + b, 0), count: input.values.length }));",
  "stdin": {
    "values": [
      3,
      5,
      8
    ]
  },
  "parseJsonOutput": true,
  "timeoutSeconds": 5,
  "maxOutputBytes": 256000,
  "saveFiles": [],
  "maxSavedFileBytes": 5000000
}' |
apify call automation-lab/ai-code-runner-sandbox --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=automation-lab/ai-code-runner-sandbox",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/O7Zb9CDtc9ICDuElD/builds/dZB6zzg2wrG8GaVgQ/openapi.json
