# Bubble Sync (`hpix/bubble-sync`)

Seamlessly sync data from Apify datasets to Bubble.io databases with flexible field mapping and upsert/append modes.

- **URL**: https://apify.com/hpix/bubble-sync.md
- **Developed by:** [Hpix](https://apify.com/hpix) (community)
- **Categories:** Integrations, Automation
- **Stats:** 1 total users, 1 monthly users, 0.0% runs succeeded, NaN 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.

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

# README

### ℹ️ About

An integration Actor for seamlessly syncing data from Apify runs to Bubble.io databases. Perfect for integrating web scraping results directly into your Bubble applications with flexible field mapping and two different sync modes.

### ✨ Features

- **Two sync modes**: Append new records or upsert (update/insert) existing ones
- **Field mapping**: Transform field names from your Apify dataset to match Bubble table schema
- **Batch processing**: Efficiently handles large datasets
- **Flexible matching**: Configure custom ID fields for record matching during upserts

### ⚙️ Inputs

#### Required Parameters

- **bubble\_api\_token**: Your private API token from Bubble app settings ([see the tutorial here](https://manual.bubble.io/core-resources/api/the-bubble-api/the-data-api/authentication#authenticating-as-an-admin))
- **bubble\_base\_url**: Base URL to your Bubble Data API (e.g., `https://myapp.bubbleapps.io`)
- **bubble\_table**: Name of the table in your Bubble app to sync to (e.g. `Products`)
- **sync\_mode**: Choose between `append` (add new records) or `upsert` (update existing/create new)
- **datasetId**: Apify dataset ID to sync from (set automatically when running as an integration)

#### Optional Parameters

- **dataset\_id\_field**: Field name in your Apify dataset used for matching records (required for upsert mode)
- **bubble\_id\_field**: Field name in your Bubble table to match against (required for upsert mode)
- **field\_mappings**: Array of key-value pairs to map field names from dataset to Bubble table

#### Example Input

```json
{
  "bubble_api_token": "your_secret_token_here",
  "bubble_base_url": "https://myapp.bubbleapps.io",
  "bubble_table": "Products",
  "sync_mode": "upsert",
  "dataset_id_field": "product_id",
  "bubble_id_field": "external_id",
  "field_mappings": [
    {
      "key": "name",
      "value": "product_name"
    },
    {
      "key": "price",
      "value": "product_price"
    }
  ],
  "datasetId": "your_dataset_id_here"
}
```

### 🔄 Sync Modes

#### Append Mode

- **Purpose**: Add new records to your Bubble table
- **Use case**: When you want to continuously add new data without checking for duplicates
- **Requirements**: Only basic connection parameters needed

#### Upsert Mode

- **Purpose**: Update existing records or create new ones based on matching criteria
- **Use case**: When you want to keep your Bubble data in sync and avoid duplicates
- **Requirements**: Must specify both `dataset_id_field` and `bubble_id_field` for record matching

### 🗺️ Field Mapping

Field mapping allows you to transform field names from your Apify dataset to match your Bubble table structure:

**Dataset field** → **Bubble field**

- `name` → `product_name`
- `price` → `product_price`
- `description` → `product_desc`

If no mapping is provided for a field, it will be sent with its original name.

### 📝 Use Cases

- **Social Media Analytics**: Import scraped social media posts, engagement metrics, and user data for analytics and
- **Lead Generation**: Import scraped contact information to your CRM
- **E-commerce**: Sync scraped product data to your Bubble store
- **Content Management**: Sync scraped articles or posts to your content database
- **Market Research**: Import competitor data or market analysis results
- **Real Estate**: Sync property listings from various sources

#### 💡 Tips

- Use **append mode** for time-series data or when duplicates are acceptable
- Use **upsert mode** for maintaining clean, deduplicated datasets
- Test with a small dataset first to verify field mappings work correctly

### ⚠️ Important Notes

- **API Limits**: Bubble.io has rate limits on their API. The Actor includes batching to help manage this
- **Field Types**: Ensure your Apify dataset field types match your Bubble table schema
- **Required Fields**: Make sure all required fields in your Bubble table are present in the dataset or mapped correctly

### 📃 Changelog

Got a feature suggestion? Create an [issue](https://console.apify.com/actors/zqh97rvwoH4ygumyq/issues) and let me know!

#### v0.0.1

- Initial release

### ❓ FAQ

#### Can I sync multiple datasets to the same Bubble table?

Yes! You can run the Actor multiple times with different dataset IDs. Use upsert mode to avoid duplicates.

#### What happens if a field mapping is incorrect?

The Actor will attempt to send the data to Bubble. If Bubble rejects it due to field name issues, you'll see an error in the logs.

#### Can I sync to multiple Bubble tables at once?

Currently, each run syncs to one table. To sync to multiple tables, run the Actor multiple times with different `bubble_table` values.

### 🔗 Integration Examples

#### Scraping Reels from Instagram

1. Use the [Instagram Reels Scraper](https://apify.com/hpix/ig-reels-scraper), or any other social media scraper
2. Open the **Integrations** tab and add a new integration
3. Search for the **Bubble Sync** Actor and provide the required parameters
4. Run the scraper Actor, and you'll see the results in your Bubble table!

You can check out **Apify's official documentation** [here](https://docs.apify.com/platform/integrations/actors).

### 🛠️ Troubleshooting

#### Common Issues

- **"dataset\_id\_field must be provided when sync\_mode is upsert"**: Make sure to specify the ID field when using upsert mode
- **"bubble\_id\_field must be provided when sync\_mode is upsert"**: Specify the matching field in your Bubble table
- **Authentication errors**: Verify your API token and ensure it has the correct permissions
- **Field not found**: Check that your field mappings match your Bubble table structure

### 👀 See Also

- [Bubble.io API Documentation](https://manual.bubble.io/core-resources/api)
- [TikTok Scraper](https://apify.com/hpix/tiktok-scraper): An efficient crawler for scraping TikTok Profiles and their videos.
- [Instagram Reels Scraper](https://apify.com/hpix/ig-reels-scraper): An efficient crawler for scraping Instagram Reels and Posts.

# Actor input Schema

## `bubble_api_token` (type: `string`):

Private token from your Bubble app settings (API section).

## `bubble_base_url` (type: `string`):

Base URL to your Bubble Data API.

## `bubble_table` (type: `string`):

Name of the table in your Bubble app to sync to.

## `sync_mode` (type: `string`):

Choose whether to append or upsert records.

## `dataset_id_field` (type: `string`):

Name of the field in your Apify dataset to match records for updating in Bubble.

## `bubble_id_field` (type: `string`):

Name of the field in your Bubble table to match against the Apify Dataset ID Field.

## `field_mappings` (type: `array`):

Map fields from your Apify dataset to specific fields in your Bubble table. If a field is not mapped, it will be sent with its original name.

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

Apify dataset to sync.

## Actor input object example

```json
{
  "sync_mode": "append",
  "datasetId": "{{resource.defaultDatasetId}}"
}
```

# 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 = {
    "datasetId": "{{resource.defaultDatasetId}}"
};

// Run the Actor and wait for it to finish
const run = await client.actor("hpix/bubble-sync").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 = { "datasetId": "{{resource.defaultDatasetId}}" }

# Run the Actor and wait for it to finish
run = client.actor("hpix/bubble-sync").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 '{
  "datasetId": "{{resource.defaultDatasetId}}"
}' |
apify call hpix/bubble-sync --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=hpix/bubble-sync",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Bubble Sync",
        "description": "Seamlessly sync data from Apify datasets to Bubble.io databases with flexible field mapping and upsert/append modes.",
        "version": "0.1",
        "x-build-id": "IsjJ10Jlr0MP0OxOi"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/hpix~bubble-sync/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-hpix-bubble-sync",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/hpix~bubble-sync/runs": {
            "post": {
                "operationId": "runs-sync-hpix-bubble-sync",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/hpix~bubble-sync/run-sync": {
            "post": {
                "operationId": "run-sync-hpix-bubble-sync",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "bubble_api_token",
                    "bubble_base_url",
                    "bubble_table",
                    "sync_mode",
                    "datasetId"
                ],
                "properties": {
                    "bubble_api_token": {
                        "title": "Bubble API Token",
                        "type": "string",
                        "description": "Private token from your Bubble app settings (API section)."
                    },
                    "bubble_base_url": {
                        "title": "Bubble Base URL",
                        "type": "string",
                        "description": "Base URL to your Bubble Data API."
                    },
                    "bubble_table": {
                        "title": "Bubble Table Name",
                        "type": "string",
                        "description": "Name of the table in your Bubble app to sync to."
                    },
                    "sync_mode": {
                        "title": "Sync Mode",
                        "enum": [
                            "append",
                            "upsert"
                        ],
                        "type": "string",
                        "description": "Choose whether to append or upsert records.",
                        "default": "append"
                    },
                    "dataset_id_field": {
                        "title": "Dataset ID Field",
                        "type": "string",
                        "description": "Name of the field in your Apify dataset to match records for updating in Bubble."
                    },
                    "bubble_id_field": {
                        "title": "Bubble ID Field",
                        "type": "string",
                        "description": "Name of the field in your Bubble table to match against the Apify Dataset ID Field."
                    },
                    "field_mappings": {
                        "title": "Field Mappings (Optional)",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Map fields from your Apify dataset to specific fields in your Bubble table. If a field is not mapped, it will be sent with its original name.",
                        "items": {
                            "type": "object",
                            "required": [
                                "key",
                                "value"
                            ],
                            "properties": {
                                "key": {
                                    "type": "string",
                                    "title": "Key"
                                },
                                "value": {
                                    "type": "string",
                                    "title": "Value"
                                }
                            }
                        }
                    },
                    "datasetId": {
                        "title": "Dataset",
                        "type": "string",
                        "description": "Apify dataset to sync."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
