# Export Notion, HubSpot & Airtable Records to a Dataset (`deadwood_data_solutions/connector-record-puller`) Actor

Pull records out of Notion, HubSpot, Airtable, Supabase or any MCP-connected app into an Apify dataset — with pagination, field selection, flattening for CSV, and incremental runs that only return what's new.

- **URL**: https://apify.com/deadwood\_data\_solutions/connector-record-puller.md
- **Developed by:** [K O](https://apify.com/deadwood_data_solutions) (community)
- **Categories:** Automation, Developer tools, Integrations
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.50 / 1,000 record exported to your datasets

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

## Export Notion, HubSpot & Airtable Records to a Dataset

Your records are stuck inside an app. This Actor pulls them out into an Apify dataset, where the rest of your pipeline can reach them — enrich them, scrape against them, analyse them, or just download a clean CSV.

Point it at a connected app, name the tool that lists records, and run.

### What it handles that a manual export doesn't

- **Pagination.** Give it the cursor argument and where the next cursor appears, and it walks every page. A repeated cursor stops paging immediately, so a misbehaving server can't loop.
- **Incremental exports.** With `onlyNew`, a scheduled run returns only records that appeared since last time — not the whole table again.
- **Flattening.** Nested objects become dot-notation columns (`props.name`), so the export opens cleanly as a spreadsheet instead of a wall of JSON. Arrays stay intact.
- **Field selection.** Export the six columns you need, not all forty.

### How it works

1. Connect your app under **Integrations** in Apify Console.
2. Run in **`list-tools`** mode to learn the connector's tool names.
3. Run in **`pull`** mode.

```json
{
  "source": "<your connector>",
  "mode": "pull",
  "readTool": "query_database",
  "readToolArgs": { "database_id": "abc123" },
  "cursorArgName": "start_cursor",
  "cursorPath": "next_cursor",
  "idField": "id",
  "onlyNew": true,
  "flatten": true
}
```

Credentials never reach this Actor. It talks to your app through Apify's MCP proxy, which holds the real tokens.

### Examples

**Notion database → CSV** — `readTool: "query_database"`, `flatten: true`. Download the dataset as CSV when it finishes.

**HubSpot contacts → enrichment pipeline** — pull contacts, then feed the dataset into an enrichment Actor and write the results back with the Field Filler.

**Nightly incremental Supabase export** — `readTool: "select"`, `idField: "id"`, `onlyNew: true`, on a schedule. Each run returns only rows added since the last one.

### Input

| Field | Required | Description |
|---|---|---|
| `source` | yes | MCP connector to export from |
| `mode` | | `pull` (default) or `list-tools` |
| `readTool` | for pull | Tool that lists records |
| `readToolArgs` | | JSON args for the read tool |
| `cursorArgName` | | Paging argument the tool accepts, e.g. `start_cursor` |
| `cursorPath` | | Where the next cursor appears in the response. Dot paths work |
| `maxPages` | | Hard stop on pagination. Default 10 |
| `idField` | | Field uniquely identifying a record |
| `onlyNew` | | Only export records unseen in previous runs. Needs `idField` |
| `fields` | | Allow-list of fields to keep. Empty means all |
| `flatten` | | Nested objects → dot-notation columns |
| `maxItems` | | Cap on records exported. Default 5000 |

### Output

Records land in the dataset in their own shape — exactly the fields the source returned, optionally flattened and filtered. Export as JSON, CSV, Excel or XML, or read it from the API.

### Pricing

**$5 per 1,000 records exported.** With `onlyNew` on, a scheduled run over an unchanged source exports nothing and costs nothing.

### FAQ

**Does this see my Notion/HubSpot token?** No. Apify's MCP proxy holds credentials and attaches them to outbound calls.

**Which apps work?** Any service exposed as an MCP connector in your Apify account.

**How do I find `cursorPath`?** Run once without pagination and look at the raw result, or use `list-tools` to read the tool's own schema.

**Does it modify anything in the source app?** No. This Actor only reads.

**Can an AI agent call this?** Yes — it's exposed through the Apify MCP server, and it's designed to return a bounded number of records rather than an unbounded dump.

# Actor input Schema

## `source` (type: `string`):

The MCP connector to export from. Connect the app under Integrations in Apify Console first. Credentials stay in Apify's proxy — this Actor never sees your tokens.

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

Use 'list-tools' first to discover the connector's tool names, then 'pull'.

## `readTool` (type: `string`):

MCP tool that lists records, e.g. 'query\_database' for Notion, 'select' for Supabase, 'search\_contacts' for a CRM. Required when mode is 'pull'.

## `readToolArgs` (type: `object`):

JSON arguments the read tool needs, e.g. {"database\_id": "abc123"} or {"table": "leads"}.

## `cursorArgName` (type: `string`):

The argument the read tool accepts for paging, e.g. 'start\_cursor' or 'after'. Leave blank to fetch a single page.

## `cursorPath` (type: `string`):

Path to the next cursor in the tool's response, e.g. 'next\_cursor' or 'paging.next'. Dot paths supported. Needed together with the argument name above.

## `maxPages` (type: `integer`):

Hard stop on pagination. A repeated cursor also ends paging early, so a misbehaving server cannot loop.

## `idField` (type: `string`):

Field uniquely identifying a record, e.g. 'id' or 'page\_id'. Used to drop duplicates and to power incremental exports.

## `onlyNew` (type: `boolean`):

Recommended for scheduled exports: a run only returns records that appeared since last time. Requires an ID field.

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

Optional allow-list of fields to export. Dot paths work. Leave empty to export every field.

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

Turn nested objects into dot-notation columns (props.name) so the export opens cleanly as CSV or a spreadsheet. Arrays are left intact.

## `maxItems` (type: `integer`):

Stop after this many records have been collected.

## Actor input object example

```json
{
  "mode": "pull",
  "readToolArgs": {},
  "maxPages": 10,
  "onlyNew": false,
  "fields": [],
  "flatten": false,
  "maxItems": 5000
}
```

# 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 = {
    "readToolArgs": {},
    "fields": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("deadwood_data_solutions/connector-record-puller").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 = {
    "readToolArgs": {},
    "fields": [],
}

# Run the Actor and wait for it to finish
run = client.actor("deadwood_data_solutions/connector-record-puller").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 '{
  "readToolArgs": {},
  "fields": []
}' |
apify call deadwood_data_solutions/connector-record-puller --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,deadwood_data_solutions/connector-record-puller"
        }
    }
}

```

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/0VEcSEmFmyrE4IT4E/builds/05x9aCuXz1C9MAvwH/openapi.json
