# Save to Box (`petroshong1/save-to-box`) Actor

Send the results of any Apify Actor to a Box folder as Excel, CSV or JSON, plus screenshots, PDFs and other files. Attach as an integration and every run lands in Box automatically.

- **URL**: https://apify.com/petroshong1/save-to-box.md
- **Developed by:** [Petros Hong](https://apify.com/petroshong1) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Save to Box

**Send web data from any Apify Actor straight into Box.** Attach Save to Box as an integration and every run lands in a Box folder as an Excel, CSV or JSON file, together with any screenshots, PDFs or reports the run produced. Your team picks it up where they already work, with Box permissions, retention, search, workflows and Box AI.

### Why use it

- **Web data where your company already works.** No exports, downloads or re-uploads. Results land in a Box folder automatically after every run.
- **Works with thousands of Actors.** Google Maps, Amazon, LinkedIn, Instagram, Google Search, any website crawler. If it runs on Apify, its results can go to Box.
- **Version history built in.** Give the file a fixed name (e.g. `{actor} results`) and each run becomes a new version of the same Box file, so you get one file to share and a full history.
- **Box does the rest.** Use Box Automate to route new files for approval, Box AI to ask questions about them, metadata and retention policies to govern them, and shared links to send them to people.

### What gets saved

| From the run | Saved to Box as |
|---|---|
| Dataset (the scraped results) | One file per format you pick: Excel, CSV, JSON, JSON Lines, XML or HTML table |
| Files in the run's key-value store (optional) | The original files: screenshots, PDFs, HTML snapshots, reports. Internal records like `INPUT` are skipped |

Each file gets a Box description saying which Actor and run produced it, so it's easy to find in Box search.

### Use cases

- **Competitor and pricing intelligence:** daily product, price and review scrapes in a shared Box folder for sales and product teams.
- **Lead lists:** Google Maps or LinkedIn results delivered as Excel straight to the sales team's folder.
- **Brand and reputation monitoring:** reviews and social mentions archived in Box, ready for Box AI ("What are customers complaining about this month?").
- **Compliance and regulatory monitoring:** snapshots of regulator and policy pages archived with your Box retention policies.
- **Vendor and supplier research:** company data and news per vendor, filed where procurement keeps everything else.
- **A knowledge base for Box AI:** turn websites into documents Box AI can answer questions about, alongside your internal files.

### Quick start

#### 1. Create a Box app (once, about 5 minutes)

1. Go to the [Box Developer Console](https://app.box.com/developers/console) > **Create Platform App** > **Custom App** > **Server Authentication (Client Credentials Grant)**.
2. On the **Configuration** tab:
   - App access level: **App Access Only** is enough. Choose **App + Enterprise Access** only if you want to connect as a specific Box user (see step 2 below).
   - Application scopes: **Read and write all files and folders stored in Box**.
   - Click **Save**.
3. Get the app authorized: your Box admin approves it under **Admin Console > Integrations > Platform Apps Manager**. If you are the admin, approve it yourself.
4. Collect three values:
   - **Client ID** and **Client Secret:** on your app's page, click the **App Details** panel icon at the top right (next to the **⋯** button). Click **Copy** next to Client ID, and **Fetch Secret** next to Client Secret (Box may ask you to confirm with two-factor authentication).
   - **Enterprise ID:** **Admin Console > Account & Billing**.

> **Just want to try it?** Generate a **Developer Token** for your app in the Box Developer Console and paste it into the *Developer token* field. It works for 60 minutes and connects as you, with no admin approval needed.

#### 2. Give the app access to your folder

The app has its own Box account, called a service account. Share your target folder with it:

1. Run Save to Box once. If it can't see the folder, the error message tells you the exact service account email, e.g. `AutomationUser_1234_abc@boxdevedition.com`.
2. In Box, open the folder > **Share** > **Invite people**, add that email as **Editor**.

Alternatively, choose **Connect as > A specific Box user**, enter your Box user ID, and enable **Generate user access tokens** in the app's advanced features. Files are then owned by that user, and any folder that user can edit works without extra sharing.

#### 3. Attach it to an Actor

1. Open the Actor whose results you want in Box (e.g. Google Maps Scraper) > **Integrations** tab > **Add integration** > search **Save to Box**.
2. Fill in the **Box folder ID** (the number at the end of the folder URL, `app.box.com/folder/123456789`) and your Box connection details.
3. Save. From now on every successful run is uploaded automatically, including runs started by schedules and the API.

> **Tip: set it up once, reuse it everywhere.** Fill in your Box settings on Save to Box, click **Save as a new task**, and attach that task instead of the Actor. In the integration's **Input JSON overrides**, add `{"datasetId": "{{resource.defaultDatasetId}}"}` so each run uploads its own results. Attach integrations to a **saved task** (e.g. "Weekly leads: dentists in Austin") rather than the Actor itself if you only want some runs to go to Box.

You can also run Save to Box on its own: pick any dataset under **Source** and click Start.

### Options

| Option | What it does |
|---|---|
| **Dataset formats** | Excel (default), CSV, JSON, JSON Lines, XML, HTML table. Pick several to get one file each |
| **Only these fields** | Keep only the columns you need, e.g. `title`, `url`, `price` |
| **Also save files from the run** | Upload screenshots, PDFs and other files the Actor stored. Filter by key prefix and cap the count |
| **File name** | Template with `{actor}`, `{date}`, `{time}`, `{runId}`. A fixed name means new versions of one file |
| **Subfolder** | e.g. `{actor}`, `{date}` or `{actor}/{date}`. Created automatically |
| **Create shared link** | No / people in the folder / anyone in your company |
| **Upload when the dataset is empty** | Off by default, so empty runs don't create empty files |

Large exports are handled automatically: files over 40 MB use Box's chunked upload API.

### Output

The Actor's own dataset lists every uploaded file with its Box file ID, Box URL, size, whether it was a new version, and the shared link if you created one. The `OUTPUT` record holds the destination folder URL.

### Security

- The client secret and developer token are **secret inputs**: stored encrypted and never written to logs.
- The Actor runs with **limited permissions**. It can only read the dataset and key-value store of the run it's attached to, nothing else in your Apify account.
- Box access is whatever you grant the app. Use a dedicated folder, and give the service account Editor access only to that folder.

### Troubleshooting

| Message | Fix |
|---|---|
| `Box sign-in failed (invalid_client)` | Client ID or secret is wrong. Copy them again from the Developer Console |
| `Box sign-in failed (unauthorized_client)` | The app isn't approved in your enterprise yet. Ask your Box admin to approve it in Platform Apps Manager |
| `Box sign-in failed (invalid_grant)` | The Enterprise ID or user ID doesn't match the app |
| `Box folder … is not visible to …` | Invite the service account email shown in the message to the folder as Editor |
| `can see folder … but cannot upload` | Raise that account's role on the folder to Editor or Uploader |

### Pricing

No Actor fee. You pay only Apify platform usage, which is tiny: a typical upload runs for about 5 seconds at 512 MB, around **0.0007 compute units**, so thousands of uploads cost less than a dollar. The scraping run that produces the data costs far more than saving it to Box.

Exporting a very large dataset (100,000+ rows to Excel)? Raise **Memory** to 1–2 GB under Run options.

### Feedback

Ideas for what should happen in Box next, like metadata, Box AI or Automate triggers? Open an issue on the Actor's **Issues** tab.

***

*Save to Box is an independent integration built on Apify. It is not made, endorsed or supported by Box, Inc. "Box" is a trademark of Box, Inc.*

# Actor input Schema

## `folderId` (type: `string`):

Required to upload. Where files go. Open the folder in Box: the ID is the number at the end of the URL (app.box.com/folder/<b>123456789</b>). The Box app must have access to this folder (see README).

## `boxClientId` (type: `string`):

On your app's page in the Box Developer Console, open the App Details panel (icon at the top right, next to ⋯) and click Copy next to Client ID.

## `boxClientSecret` (type: `string`):

Same panel: click Fetch Secret next to Client Secret. Stored encrypted, never shown in logs.

## `boxSubjectType` (type: `string`):

Service account: files are owned by the app; share the target folder with the app's service account. Specific user: files are owned by that user (the app needs 'Generate user access tokens').

## `boxSubjectId` (type: `string`):

Enterprise ID (Box Admin Console > Account & Billing), or the Box user ID if 'Connect as' is a specific user.

## `boxDeveloperToken` (type: `string`):

Optional, for a quick test only: a 60-minute developer token from the Box Developer Console. It connects as you. Use client ID + secret for anything automatic.

## `formats` (type: `array`):

One file per format with all dataset items. Leave empty to skip the dataset.

## `fields` (type: `array`):

Optional. Keep only these columns (e.g. title, url, price). Empty = all fields.

## `saveFiles` (type: `boolean`):

Upload records from the run's key-value store, e.g. screenshots, PDFs, HTML snapshots or reports. INPUT and internal state records are skipped.

## `fileKeyPrefix` (type: `string`):

Optional. Only upload key-value store records whose key starts with this (e.g. 'screenshot').

## `maxFiles` (type: `integer`):

Safety cap on how many key-value store files are uploaded per run.

## `fileName` (type: `string`):

Variables: {actor}, {date}, {time}, {runId}. Extension is added. Tip: use a fixed name like '{actor} results' to keep ONE file whose Box version history holds every run.

## `subfolder` (type: `string`):

Optional. Create/use a subfolder, e.g. '{actor}' or '{date}' or '{actor}/{date}'. Empty = save straight into the folder.

## `sharedLink` (type: `string`):

Optionally create a Box shared link on each uploaded file (returned in the output).

## `uploadEmpty` (type: `boolean`):

Off by default, so runs that found nothing do not create empty files in Box.

## `datasetId` (type: `string`):

When attached as an integration this is the triggering run's dataset ({{resource.defaultDatasetId}}).

## `keyValueStoreId` (type: `string`):

When attached as an integration this is the triggering run's store ({{resource.defaultKeyValueStoreId}}).

## Actor input object example

```json
{
  "boxSubjectType": "enterprise",
  "formats": [
    "xlsx"
  ],
  "saveFiles": false,
  "maxFiles": 200,
  "fileName": "{actor} {date} {time}",
  "sharedLink": "none",
  "uploadEmpty": false
}
```

# Actor output Schema

## `uploadedFiles` (type: `string`):

No description

## `summary` (type: `string`):

No description

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("petroshong1/save-to-box").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("petroshong1/save-to-box").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{}' |
apify call petroshong1/save-to-box --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,petroshong1/save-to-box"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

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