# Google Sheets Import and Export for Apify (`bepolabs/google-sheets`) Actor

Import tabs from a shared workbook, or export a dataset: append below the last entry, replace a tab, or merge by ID. Needs a service account for writing; public links read freely.

- **URL**: https://apify.com/bepolabs/google-sheets.md
- **Developed by:** [BEPO Labs](https://apify.com/bepolabs) (community)
- **Categories:** Integrations, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$5.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

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

### 📊 What is Google Sheets Import and Export?

Move data between Apify and Google Sheets in both directions. Export pushes a dataset into your document; import returns each row as an item, named by the header. It talks to the official API, so nothing passes via a third party, and AI agents can call it using the Apify MCP server.

- **Scraper results delivered**: send the dataset of any Actor run to the sheet your team already uses, after every scheduled run
- **Keep a sheet up to date**: upsert by a key such as URL or product ID: changed rows are updated in place, new ones are appended, nothing is duplicated
- **Sheets as input**: read a list of URLs, keywords or products from a sheet and feed it into another Actor
- **Reports and dashboards**: keep a Looker Studio or Sheets dashboard fed with fresh rows without copy and paste

![Google Sheets Import and Export: Send any Apify dataset or JSON to a Google Sheet (append, replace or upsert by key), or read a sheet back as clean rows.](https://api.apify.com/v2/key-value-stores/wdeAWGooHdIhvFgSY/records/google-sheets-hero.png)

#### ✨ Why use this Actor?

- ✅ **Upsert by key**: rows with the same `keyColumn` value are updated in place, cells of columns the row lacks stay, new keys are appended
- ✅ **New columns join by themselves**: the existing header is kept and new fields are added to the right, so a scraper that adds a field does not break your sheet
- ✅ **Dry run first**: `dryRun` plans the write and shows a preview in the run summary; nothing is written and only the run is charged
- ✅ **Runs that finish**: chunked writes and retries with exponential backoff on Google's quota (429) and server errors; a wrong share or range stops at once with a message that says what to fix
- ✅ **Your own Google setup**: a service account key you control, no OAuth pop-up and no token stored by a third party; public sheets import without one

### 📦 What data can you get with Google Sheets Import and Export?

| | | |
|---|---|---|
| 🔤 Every column of the sheet, named by the header row | 🔠 Column letters (`A`, `B`, ...) when `headerRow` is off | 🧩 Empty header cells as `column_C`, duplicates as `name_2` |
| 🧾 Export summary: rows written, appended, updated, skipped | 🔗 Link to the sheet that was written |  |

> Import fills the dataset. Export writes to your sheet and puts its run summary into the key-value store (`OUTPUT`).

### 🚀 How to use Google Sheets Import and Export

Google Sheets Import and Export works in a few clicks, no coding needed:

1. [Create a free Apify account](https://console.apify.com/sign-up) (the free plan includes 5 USD of monthly credit).
2. Open [Google Sheets Import and Export](https://apify.com/bepolabs/google-sheets) and click **Try for free**.
3. Pick `export` or `import`, paste the sheet's URL and, for export, the dataset ID and your service account key.
4. Click **Start** and wait for the run to finish (most runs take seconds).
5. Download your data as JSON, CSV, Excel, XML or HTML, or send it straight to Google Sheets, Make, Zapier or your AI agent.

![How Google Sheets Import and Export works](https://api.apify.com/v2/key-value-stores/wdeAWGooHdIhvFgSY/records/google-sheets-workflow.png)

### ⬇️ Input

Only `mode` and `spreadsheetId` are required. Export also needs `serviceAccountJson` and either `datasetId` or `rows`; import reads link-shared sheets without a key.

##### Setup in 3 minutes

Google Cloud console > IAM > Service accounts > Create (no roles needed); Keys > Add key > JSON and paste the file into `serviceAccountJson`; APIs > Library > Google Sheets API > Enable; then share the sheet with the `client_email` inside as Editor (export) or Viewer (import).

##### Write modes

`append` adds below the last row, `replace` clears the target first, `upsert` matches rows by `keyColumn`. `sheetName` picks the tab (default `Sheet1`, created if missing unless `createSheet` is off).

##### Ranges

Import takes any A1 range such as `A1:F500` or `'My tab'!A:D`; empty selects the whole first tab. `maxRows` caps the rows (0 for all).

| Field | Type | What it does | Default |
|---|---|---|---|
| **Mode** (`mode`) | string | Export writes rows into the sheet; import reads a range into this run's dataset. | `"export"` |
| **Spreadsheet URL or id** (`spreadsheetId`) | string | The sheet's URL from the browser (https://docs.google.com/spreadsheets/d//edit) or just the id. | `"https://docs.google.com/spreadsheets/d/` |
| **Tab name** (`sheetName`) | string | The tab to write to or read from. |  |
| **Service-account key (JSON)** (`serviceAccountJson`) | string | The JSON key of a Google Cloud service account; share the sheet with its client_email (Editor for export, Viewer for import). |  |
| **Dataset id (export)** (`datasetId`) | string | The Apify dataset to export, e.g. |  |
| **Rows (export)** (`rows`) | array | Instead of a dataset: a JSON array of objects. |  |
| **Write mode (export)** (`writeMode`) | string | New columns are always added to the right of the header row. | `"append"` |
| **Key column (upsert)** (`keyColumn`) | string | Column whose value identifies a row, e.g. |  |
| **Create the tab if missing (export)** (`createSheet`) | boolean | Otherwise a missing tab stops the run with the list of tabs. | `true` |
| **Range (import)** (`range`) | string | A1 range such as A1:F500 or 'My tab'!A:D. |  |
| **First row is a header (import)** (`headerRow`) | boolean | Use the first row as field names; otherwise fields are column letters (A, B, ...). | `true` |
| **Rows per write call** (`chunkSize`) | integer | Large exports are written in chunks of this many rows. | `1000` |
| **Maximum rows** (`maxRows`) | integer | Maximum number of rows to read from the sheet in import mode; 0 reads every row. | `0` |
| **Dry run (export)** (`dryRun`) | boolean | Plan the export and show a preview in OUTPUT without writing or charging rows. | `false` |
| **Maximum retries** (`maxRetries`) | integer | Retries per call on Google quota (429) and server errors, with exponential backoff. | `5` |

![Google Sheets Import and Export input form](https://api.apify.com/v2/key-value-stores/wdeAWGooHdIhvFgSY/records/google-sheets-input.png)

#### Input example

```json
{
    "mode": "import",
    "spreadsheetId": "https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit",
    "range": "'Class Data'!A1:F"
}
```

### ⬆️ Output

Import gives one dataset item per sheet row, keyed by the header. Export fills your tab; its run summary shows what happened.

![Google Sheets Import and Export output table](https://api.apify.com/v2/key-value-stores/wdeAWGooHdIhvFgSY/records/google-sheets-output.png)

#### Output example

One row from an import of Google's public sample sheet (`'Class Data'!A1:F`):

```json
{
    "Student Name": "Alexandra",
    "Gender": "Female",
    "Class Level": "4. Senior",
    "Home State": "CA",
    "Major": "English",
    "Extracurricular Activity": "Drama Club"
}
```

#### Export run summary

After an export the key-value store record `OUTPUT` holds the counts and the sheet link (example numbers):

```json
{
    "rowsIn": 120,
    "planRows": 120,
    "rowsWritten": 120,
    "appended": 95,
    "updated": 25,
    "skipped": 0,
    "columns": 8,
    "writeCalls": 2,
    "dryRun": false,
    "sheetUrl": "https://docs.google.com/spreadsheets/d/<id>/edit"
}
```

View the results as a table or JSON in the Output tab and download them as JSON, CSV, Excel, XML, HTML or RSS, all fields or only those you pick.

### 💰 How much does Google Sheets Import and Export cost?

Google Sheets Import and Export is priced **per event**: **5 USD per 1,000 rows** (0.005 USD per row), with no monthly rental. Plus 0.005 USD once per run. Dry runs charge only the run.

| You get | You pay |
|---|---|
| 100 rows | 0.5 USD |
| 1,000 rows | 5 USD |
| 10,000 rows | 50 USD |
| 100,000 rows | 500 USD |

Optional extras are charged only when you switch them on:

- **Row**: 0.2 USD per 1,000

💡 Apify's free plan gives you 5 USD of credit every month, enough for about **1,000 rows** at no cost. Set a spending limit per run and the Actor stops there.

### ⚖️ Google Sheets Import and Export vs. the alternatives

| | Google Sheets Import and Export | Copy and paste | Other Sheets Actors |
|---|---|---|---|
| **Upsert by key (update, no duplicates)** | ✅ | ❌ | varies |
| **New columns added to the header** | ✅ | by hand | varies |
| **Dry run with preview** | ✅ | ❌ | rare |
| **Retries on Google's quota** | ✅ | ❌ | varies |
| **Your own service account, no OAuth pop-up** | ✅ | n/a | often OAuth |

### 🔌 Integrations, API and MCP

#### Connect Google Sheets Import and Export to your AI agent (MCP)

Give Claude, ChatGPT, Cursor or any MCP client direct access to Google Sheets Import and Export through the [Apify MCP server](https://mcp.apify.com). Add this URL to its settings:

```text
https://mcp.apify.com/?actors=bepolabs/google-sheets
```

For Claude Desktop, add it under `mcpServers` in `claude_desktop_config.json`:

```json
{
    "mcpServers": {
        "google-sheets": {
            "command": "npx",
            "args": [
                "-y",
                "@apify/actors-mcp-server",
                "--actors",
                "bepolabs/google-sheets"
            ],
            "env": {
                "APIFY_TOKEN": "<your Apify API token>"
            }
        }
    }
}
```

Then ask: *"Read the sheet https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms and tell me how many students major in English."*

#### Run it from your code

Python (`pip install apify-client`):

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("bepolabs/google-sheets").call(run_input={"mode":"import","spreadsheetId":"https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit","range":"'Class Data'!A1:F"})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

JavaScript (`npm install apify-client`):

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('bepolabs/google-sheets').call({"mode":"import","spreadsheetId":"https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit","range":"'Class Data'!A1:F"});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### No-code integrations

Send results to **Google Sheets, Slack, Airtable, HubSpot, Make, Zapier, n8n** and more from the Integrations tab, start runs on a **schedule**, or trigger your own endpoint with a **webhook** when a run finishes. The [Apify API](https://docs.apify.com/api/v2) gives you full control over runs and datasets.

### ❓ FAQ

##### Do I need a Google Cloud account?

For export, yes: a free service account key (see the input tips, about 3 minutes). Import of a sheet shared as "Anyone with the link" needs none at all.

##### Will an export overwrite my data?

Only with `writeMode: replace`. `append` adds below the last row and `upsert` only changes rows whose key matches; run with `dryRun` first to see the plan.

##### How large can an export be?

Rows are written in chunks (`chunkSize`, default 1000) within Google's limit of 10 million cells per spreadsheet.

##### Can I run it after every scraper run?

Yes: add it as an integration or webhook on the task of your scraper, or schedule it; set `datasetId` to that dataset.

##### My spreadsheet ID is not 44 characters long. Does it work?

Yes. Paste the sheet's URL from the browser or just the id; any length from 20 characters is accepted, older 33-character ids too.

##### Is it legal to use Google Sheets Import and Export?

The Actor reads and writes only sheets that you share with your own service account, or that are already public by link, through Google's official API. You stay responsible for the data you move and for Google's terms.

##### What if something is missing or does not work?

Open an issue on the **Issues** tab; we read each one and reply. Feature requests are welcome too.

### 💬 Your feedback

Tell us what Google Sheets Import and Export should add on the **Issues** tab or leave a review; your notes decide what we work on next.

### 🔗 Related Actors

| Actor | What it does |
|---|---|
| 📞 [Phone Number Validator](https://apify.com/bepolabs/phone-validator) | Bulk phone number validation offline: valid or not, E.164 format, country and line type (mobile, fixed line, VoIP) for every number. |
| 💼 [ATS Jobs](https://apify.com/bepolabs/ats-jobs) | Every open job from company career boards on Greenhouse, Lever, Ashby, Workable, SmartRecruiters and Recruitee in one deduped feed. |
| 🌍 [Remote Jobs](https://apify.com/bepolabs/remote-jobs) | Remote jobs from Remote OK, Himalayas, Jobicy and Arbeitnow in one deduped feed, with salary, posted date and apply link. |
| 📇 [Website Contacts](https://apify.com/bepolabs/website-contacts) | Company websites to emails, phone numbers and social profiles, one row per site, with a status that says why nothing was found. |
| 🏛️ [SAM.gov Contract Opportunities](https://apify.com/bepolabs/sam-gov) | US federal contract opportunities by keyword, NAICS, set-aside or agency, with deadlines, contacts and attachments. |
| 🇬🇧 [UK Tenders](https://apify.com/bepolabs/uk-tenders) | UK public contracts from Contracts Finder and Find a Tender by keyword, CPV, value, region and deadline, with daily alerts. |
| ⭐ [App Store Reviews](https://apify.com/bepolabs/app-store-reviews) | iOS App Store reviews with stars, text, app version and date, plus the app's rating and details, for any store country. |
| 🧩 [Chrome Web Store Scraper](https://apify.com/bepolabs/chrome-web-store) | Users, rating, version, last update, developer, category and permissions of any Chrome extension. |

# Changelog

This Actor's version history is a separate document: https://apify.com/bepolabs/google-sheets/changelog.md

# Actor input Schema

## `mode` (type: `string`):

Export writes rows into the sheet; import reads a range into this run's dataset.

## `spreadsheetId` (type: `string`):

The sheet's URL from the browser (https://docs.google.com/spreadsheets/d/<id>/edit) or just the id.

## `sheetName` (type: `string`):

The tab to write to or read from. Export default: Sheet1 (created if missing). Import default: the first tab.

## `serviceAccountJson` (type: `string`):

The JSON key of a Google Cloud service account; share the sheet with its client_email (Editor for export, Viewer for import). Needed for export; import also reads sheets shared as Anyone with the link without it.

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

The Apify dataset to export, e.g. the defaultDatasetId of another Actor's run.

## `rows` (type: `array`):

Instead of a dataset: a JSON array of objects. Keys become columns.

## `writeMode` (type: `string`):

New columns are always added to the right of the header row.

## `keyColumn` (type: `string`):

Column whose value identifies a row, e.g. id or url. Required for upsert.

## `createSheet` (type: `boolean`):

Otherwise a missing tab stops the run with the list of tabs.

## `range` (type: `string`):

A1 range such as A1:F500 or 'My tab'!A:D. Empty: the whole tab.

## `headerRow` (type: `boolean`):

Use the first row as field names; otherwise fields are column letters (A, B, ...).

## `chunkSize` (type: `integer`):

Large exports are written in chunks of this many rows.

## `maxRows` (type: `integer`):

Maximum number of rows to read from the sheet in import mode; 0 reads every row.

## `dryRun` (type: `boolean`):

Plan the export and show a preview in OUTPUT without writing or charging rows.

## `maxRetries` (type: `integer`):

Retries per call on Google quota (429) and server errors, with exponential backoff.

## Actor input object example

```json
{
  "mode": "import",
  "spreadsheetId": "https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit",
  "writeMode": "append",
  "createSheet": true,
  "headerRow": true,
  "chunkSize": 1000,
  "maxRows": 0,
  "dryRun": false,
  "maxRetries": 5
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset items, one row per result, in the overview table view.

# 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 = {
    "mode": "import",
    "spreadsheetId": "https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit"
};

// Run the Actor and wait for it to finish
const run = await client.actor("bepolabs/google-sheets").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 = {
    "mode": "import",
    "spreadsheetId": "https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit",
}

# Run the Actor and wait for it to finish
run = client.actor("bepolabs/google-sheets").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 '{
  "mode": "import",
  "spreadsheetId": "https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit"
}' |
apify call bepolabs/google-sheets --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,bepolabs/google-sheets"
        }
    }
}
```

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/oWJzgLfplgv0euEVp/builds/uRrzgGDpZqp9QeAuV/openapi.json
