# Google Sheets Export (Dataset to Sheet) (`ucchiii/google-sheets-export`) Actor

Write any Apify dataset to a Google Sheet: replace or append, auto columns, nested fields flattened, dedup on append. Uses your own service account. $0.05 per 1,000 rows.

- **URL**: https://apify.com/ucchiii/google-sheets-export.md
- **Developed by:** [Actor Factory](https://apify.com/ucchiii) (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

from $35.00 / 1,000 1,000 rows writtens

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

## Google Sheets Export — send any Apify dataset to a Google Sheet, reliably

Writes one or more Apify datasets into a Google Sheet. **Built to just work**: retries on Google rate limits (429) and server errors, clear error messages, and no surprises with nested data.

- **Replace** the tab, or **append** below existing rows (columns are matched to your existing header; new columns are added on the right)
- **Auto columns**: nested objects become `address.city`, arrays become `a; b` (or JSON text)
- **Dedup on append**: skip rows whose key already exists in the sheet
- Creates the tab if it does not exist; cells are capped at Google's 50,000 characters; stops with a clear reason before hitting the 10-million-cell limit
- Your own Google service account; **the key is used only in memory and never logged or stored**
- **$0.05 per 1,000 rows written** (rounded up). Set a max charge per run to cap spend.
- Leave `datasetIds` and `spreadsheetId` empty for a **free demo** on sample data (nothing is sent to Google)

### Use cases

- Share Google Maps leads or job listings with a sales or recruiting team in a Google Sheet
- Append the results of a scheduled scraper to one sheet every day, skipping rows already there
- Hand cleaned data to non-technical colleagues without CSV downloads

### One-time setup (about 5 minutes)

1. In [Google Cloud Console](https://console.cloud.google.com/), create or pick a project and enable the **Google Sheets API**.
2. Go to **IAM & Admin > Service Accounts > Create service account** (no roles needed).
3. Open the account > **Keys > Add key > Create new key > JSON**. A JSON file is downloaded.
4. Open your Google Sheet > **Share**, paste the service account's **`client_email`** (looks like `name@project.iam.gserviceaccount.com`, found in the JSON) and give it **Editor** access.
5. Paste the whole JSON file into **Service account key** in this Actor's input.

### Input example

```json
{
  "datasetIds": ["aBcDeF123"],
  "spreadsheetId": "https://docs.google.com/spreadsheets/d/1AbC.../edit",
  "serviceAccountKey": "{ ...paste the JSON key... }",
  "sheetName": "Leads",
  "mode": "append",
  "dedupKey": "url"
}
```

### Output

The default dataset gets one summary item per run; details are in the key-value store record `RESULT`:

```json
{ "spreadsheetUrl": "https://docs.google.com/spreadsheets/d/.../edit#gid=0", "sheetName": "Leads", "mode": "append",
  "rowsWritten": 1200, "columns": ["name", "url", "address.city"], "skippedDuplicates": 35 }
```

### Common problems

- **403 / "share the spreadsheet"**: share the sheet with the `client_email` as Editor (step 4), and check the Sheets API is enabled.
- **"service account key is not valid"**: paste the complete JSON file, including `client_email` and `private_key`.
- **"Key creation is disabled" / no "Add key" option**: many Google Workspace (company) organizations block service account keys by default
  (policy `iam.disableServiceAccountKeyCreation`). Either ask your Google Cloud admin to turn that policy off for one project only,
  or create the project with a personal Google account and share the sheet with its `client_email`.
- **Stopped at the cell limit**: Google allows 10,000,000 cells per spreadsheet. Use `fields` to write fewer columns, or another spreadsheet.

### Billing

You are charged only after rows are written successfully. If Google rejects a write, nothing is charged for those rows.

### Privacy

Your key is kept in memory for the duration of the run only. It is never written to logs, the dataset or the key-value store. Use a dedicated service account with access only to the sheets you need.

### Pricing

Pay per event: **$0.05 per 1,000 rows** written (partial thousands round up). Reading datasets is free.

### More tools from the same developer

- [Google Maps Leads Cleaner](https://apify.com/ucchiii/maps-leads-cleaner) — dedupe Google Maps scraper results, format phones (E.164), CRM-ready leads
- [Dataset Merge & Dedup](https://apify.com/ucchiii/dataset-dedup-merge) — merge Apify datasets and remove duplicates by the fields you choose
- [Google Maps Reviews Analyzer](https://apify.com/ucchiii/reviews-insights) — per-place ratings, trends, owner response rate and top terms from Google Maps reviews
- [Job Postings Normalizer](https://apify.com/ucchiii/job-postings-normalizer) — unify fields, salaries and dates from any job scraper and remove duplicates
- [SERP Analyzer](https://apify.com/ucchiii/serp-dataset-analyzer) — rankings, share of voice and People Also Ask from Google Search scraper datasets

# Actor input Schema

## `datasetIds` (type: `array`):

Dataset IDs (the 'defaultDatasetId' of a finished run of the source Actor, e.g. 'WkzbQMuFYuamGv3YF'). Datasets to export, in order. Leave datasetIds and spreadsheetId empty to see a free demo on sample data (nothing is sent to Google).

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

The Google Sheet to write to: paste its URL or the ID. The sheet must be shared (Editor) with the client_email of your service account. Required for real results; leave empty for a free demo (not charged).

## `serviceAccountKey` (type: `string`):

Paste the full JSON key of your Google service account. It is used only in memory during the run and is never logged or stored by this Actor. Required for real results; leave empty for a free demo (not charged).

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

Name of the tab to write to. It is created if it does not exist.

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

'replace' (default) clears the tab first. 'append' adds rows at the end, matches columns to the existing header and adds new columns on the right.

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

Columns to output, in order. Use dots for nested fields (e.g. 'address.city'). Empty = all fields, flattened automatically.

## `flatten` (type: `boolean`):

Nested objects become columns like 'a.b'; arrays of simple values are joined with '; ', other arrays become JSON text. If off, nested values are written as JSON text.

## `dedupKey` (type: `string`):

In append mode, rows whose value in this column already exists in the sheet (or earlier in this run) are skipped. Optional.

## `batchSize` (type: `integer`):

How many rows are sent to Google in one request. Default 1000.

## Actor input object example

```json
{
  "sheetName": "Sheet1",
  "mode": "replace",
  "flatten": true,
  "batchSize": 1000
}
```

# Actor output Schema

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

One item with spreadsheetUrl, sheetName, mode, rowsWritten, columns and skippedDuplicates.

## `result` (type: `string`):

Record RESULT: details of the write (or the demo preview).

# 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 = {
    "sheetName": "Sheet1"
};

// Run the Actor and wait for it to finish
const run = await client.actor("ucchiii/google-sheets-export").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 = { "sheetName": "Sheet1" }

# Run the Actor and wait for it to finish
run = client.actor("ucchiii/google-sheets-export").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 '{
  "sheetName": "Sheet1"
}' |
apify call ucchiii/google-sheets-export --silent --output-dataset

```

## MCP server setup

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

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/jMA2eTCbxX4cjI7Yg/builds/Jp6ab5tzX08OWc0Hz/openapi.json
