# Examples

End-to-end walkthroughs combining several commands. For per-command details see the [command reference](/carto-for-agents/cli/command-reference.md).

## Authentication workflow

```bash
# Interactive browser-based login using OAuth 2.0 + PKCE
carto auth login
# This will:
# 1. Display an authorization URL
# 2. Open your browser (you may need to copy/paste the URL)
# 3. Wait for you to complete the login process
# 4. Capture your access token and user information
# 5. Store credentials in ~/.carto_credentials.json
# 6. Configure the API URL based on your tenant

# Check authentication status
carto auth status

# Show current user information
carto auth whoami
# Returns: user_id, name, email, account info, roles

# Switch between profiles
carto auth use production
carto auth use staging
```

## Managing application credentials

```bash
# List all credentials
carto credentials list
carto credentials list tokens

# Create an API Access Token for your application
carto credentials create token \
  --connection carto_dw \
  --source "demo_tables.*" \
  --apis sql,maps

# Create SPA OAuth Client for web applications
carto credentials create spa \
  --title "My Dashboard" \
  --callback "https://mydash.com/callback"

# Create M2M OAuth Client for backend services
carto credentials create m2m \
  --title "ETL Service"

# Get token details
carto credentials get token <token-id>

# Delete a credential
carto credentials delete token <token-id>
```

## Browsing and managing resources

```bash
# List maps with filters (enhanced display shows owner, privacy, views, tags)
carto maps list --search sales --page-size 20

# List only your maps
carto maps list --mine

# Pagination
carto maps list --page 1 --page-size 10
carto maps list --page 2 --page-size 10

# Fetch all pages automatically with --all
carto maps list --all
carto maps list --mine --all
carto workflows list --all --search "project"

# Get detailed info for a specific map
carto maps get 69b0e7cc-026a-4feb-87bb-a82cc6ac5189
# Output shows:
# - Map metadata (title, owner, privacy, views, collaborative, agent enabled)
# - Datasets and their connections
# - Map URL

# JSON output for scripting (or AI agents)
carto maps list --json | jq '.data[].id'

# Delete a map
carto maps delete map_abc123
```

## Creating a Builder map from JSON

`carto maps create` accepts a round-trippable bundle from a positional JSON string, a filesystem path, or stdin. Pre-flight validation runs before any write, so broken bundles reject without creating an orphan map.

```bash
# Minimal bundle — title, connection, and one dataset rendered as a tileset layer
cat > stores.map.json <<'JSON'
{
  "title": "Retail stores",
  "connectionId": "12345678-1234-1234-1234-123456789abc",
  "privacy": "private",
  "datasets": [
    {
      "id": "stores-ds",
      "type": "table",
      "source": "carto-demo-data.demo_tables.retail_stores",
      "connectionId": "12345678-1234-1234-1234-123456789abc"
    }
  ],
  "keplerMapConfig": {
    "config": {
      "visState": {
        "layers": [
          {
            "id": "stores-layer",
            "type": "tileset",
            "config": {
              "dataId": "stores-ds",
              "label": "Stores",
              "color": [255, 100, 50],
              "visConfig": { "radius": 10 }
            }
          }
        ]
      },
      "mapStyle": { "styleType": "positron" }
    }
  }
}
JSON

# Validate locally (no network), then create
carto maps validate < stores.map.json
carto maps create < stores.map.json

# Or chain in one go
carto maps create ./stores.map.json --json | jq '.builderUrl'
```

For the full schema and authoring patterns, see [`carto maps schema`](/carto-for-agents/cli/command-reference/maps.md#carto-maps-schema-section) and the [`carto-create-builder-maps`](https://github.com/CartoDB/agent-skills/tree/master/skills/carto-create-builder-maps) skill.

### Round-trip: edit an existing map

```bash
# Get the map as a round-trippable bundle, edit, and update
carto maps get abc123 --json > /tmp/map.json
jq '.title = "Q3 Dashboard"' /tmp/map.json | carto maps update abc123

# Update + publish in one call so shared/public viewers see the changes
carto maps update abc123 < /tmp/map.json --publish
```

### Screenshot a map

{% hint style="info" %}
`carto maps screenshot` is **experimental**. Its flags, render engines, and output may change in future releases.
{% endhint %}

```bash
# Default light engine — layers + basemap, no widgets
carto maps screenshot abc123 -o map.png

# Recenter and hide chrome
carto maps screenshot abc123 --lat 40.42 --lng -3.70 --zoom 12 --hide-overlays

# Full CARTO Builder viewer (widgets, legends, popups) — heavier
carto maps screenshot abc123 --render-engine full
```

## Creating a Workflow from a bundle

`carto workflows create --file <bundle.json>` takes a Workflows bundle and provisions the nodes, edges, and metadata in a single call.

```bash
# Minimal — pipeline that reads a table, filters it, and writes back
cat > cycle-pipeline.workflow.json <<'JSON'
{
  "title": "Cycle network — existing routes only",
  "connectionId": "12345678-1234-1234-1234-123456789abc",
  "config": {
    "schemaVersion": "1.0.0",
    "connectionProvider": "bigquery",
    "useCache": false,
    "nodes": [
      {
        "id": "src",
        "type": "source",
        "data": {
          "name": "ReadTable",
          "inputs": [
            { "name": "source", "value": "demo_tables.bristol_cycle_network" }
          ]
        },
        "position": { "x": 100, "y": 100 }
      },
      {
        "id": "filter",
        "type": "generic",
        "data": {
          "name": "native.where",
          "inputs": [
            { "name": "expression", "value": "r_status = 'Existing'" }
          ]
        },
        "position": { "x": 300, "y": 100 }
      }
    ],
    "edges": [
      {
        "id": "e1",
        "source": "src",
        "target": "filter",
        "sourceHandle": "out",
        "targetHandle": "source"
      }
    ]
  },
  "tags": ["analytics", "cycle-data"]
}
JSON

# Validate offline (Zod-only, no warehouse calls), then create
carto workflows validate --file cycle-pipeline.workflow.json
carto workflows create --file cycle-pipeline.workflow.json

# Full warehouse-side check before merging the bundle to a repo
carto workflows verify --file cycle-pipeline.workflow.json --connection carto_dw
```

### Browse the component catalog

Workflows are composed from components — `native.where`, `native.customsql`, `native.joinv2`, and many more. Browse the catalog for a connection (so extensions and stored procedures show up too):

```bash
# All Joins components for a BigQuery connection
carto workflows components list --connection carto_dw --group Joins

# Full input/output signatures for the components you'll use
carto workflows components get native.customsql,native.joinv2 --connection carto_dw --json
```

### Run + publish as an MCP tool

```bash
# Execute the workflow
carto workflows run abc123

# Make it callable from the CARTO MCP Server (agents will see it as a tool)
carto workflows mcp publish abc123
```

## Copying maps and workflows between organizations

A common pattern is promoting maps and workflows between environments — staging to production, customer A to customer B, or one region to another. The CLI handles connection mapping automatically and validates source accessibility before copying.

**Prerequisites:** authenticate to both organizations using [named profiles](/carto-for-agents/cli/authentication.md#multiple-profiles).

You'll need the **ID** of the map or workflow to copy. Get it from the CARTO Workspace (three-dot menu on the card, or from the URL), or search by name with `carto maps list --search "<name>"` / `carto workflows list --search "<name>"`.

```bash
# Auto-map connections by name (default, recommended)
carto maps copy <map-id> --dest-profile <profile-name>
carto workflows copy <workflow-id> --dest-profile <profile-name>
```

By default, CARTO will try to map each connection used by the source resource to a connection **with the same name** in the destination organization. If a Snowflake connection is called `production` in both orgs, the copy works without further configuration.

When connection names differ, supply an explicit mapping:

{% code overflow="wrap" %}

```bash
carto maps copy <map-id> --dest-profile <profile-name> \
  --connection-mapping "dev-bq=prod-bq,dev-postgres=prod-postgres"
```

{% endcode %}

{% code overflow="wrap" %}

```bash
carto workflows copy <workflow-id> --dest-profile <profile-name> \
  --connection <connection-name>
```

{% endcode %}

{% hint style="info" %}
The CLI assumes mapped connections **have the same data access permissions**. If they don't, the copied resources will fail to load.
{% endhint %}

{% hint style="info" %}
Copying does not delete the original resource.
{% endhint %}

### Smart connection mapping

The CLI handles connection mapping with three strategies, in priority order:

1. **Auto-mapping by name (default)** — match connections by name between source and destination.
2. **Manual mapping** — explicit pairs via `--connection-mapping`.
3. **Legacy single connection** — use one connection for all datasets via `--connection`.

```bash
# Auto-map (recommended)
carto maps copy abc123 --dest-profile production
# → Automatically maps: bigquery-dev → bigquery-dev, snowflake → snowflake

# Manual mapping for renamed connections
carto maps copy map456 \
  --source-profile staging \
  --dest-profile production \
  --connection-mapping "bigquery-dev=bigquery-prod,snowflake-staging=snowflake-prod"

# Legacy: single connection for all datasets
carto maps copy xyz789 --dest-profile prod --connection prod-bigquery

# Combine options
carto maps copy map456 \
  --dest-profile production \
  --connection-mapping "dev-bq=prod-bq" \
  --title "Production Sales Dashboard" \
  --keep-privacy
```

**How copy works:**

1. Fetches the source map configuration and all datasets.
2. Identifies all unique connections used by the map.
3. Resolves each connection in priority order: manual mapping → auto-map by name → legacy single connection.
4. Validates that all destination connections exist (fails fast if any are missing).
5. **Validates that dataset sources are accessible** in the destination using SQL dry-run queries (`WHERE 1=0`). Tests permissions and existence without transferring data. Fails if any source is inaccessible (unless `--skip-source-validation`).
6. Creates the new map and datasets with resolved connections.
7. Updates the map configuration with the new dataset IDs.
8. Preserves privacy settings if `--keep-privacy` is set.

**Connection resolution scenarios:**

*Scenario 1 — Perfect match (auto-mapping):*

```bash
carto maps copy abc123 --dest-profile prod
# Source has: bigquery-dev, snowflake-analytics
# Destination has: bigquery-dev, snowflake-analytics
# ✅ Success — both auto-mapped by name
```

*Scenario 2 — Renamed connections (manual mapping):*

```bash
carto maps copy abc123 --dest-profile prod \
  --connection-mapping "bigquery-dev=bigquery-prod,snowflake-analytics=snowflake-prod"
# ✅ Success — both manually mapped
```

*Scenario 3 — Mixed (manual + auto):*

```bash
carto maps copy abc123 --dest-profile prod --connection-mapping "old-conn=new-conn"
# Source has: old-conn, shared-connection
# Destination has: new-conn, shared-connection
# ✅ Success — old-conn mapped manually, shared-connection auto-mapped
```

*Scenario 4 — Missing connection:*

```bash
carto maps copy abc123 --dest-profile prod
# Source has: bigquery-dev, snowflake-analytics
# Destination has: bigquery-dev only
# ❌ Fails with clear error:
#    Missing connections in destination organization:
#      • "snowflake-analytics" (used by 3 datasets)
#    Solutions:
#      1. Create missing connections in destination
#      2. Use --connection-mapping to map to different names
```

*Scenario 5 — Source validation failure:*

```bash
carto maps copy abc123 --dest-profile prod --connection-mapping "dev-bq=prod-bq"
# Connections mapped successfully, but...
# ❌ Source validation failed - datasets cannot access their data sources:
#    • "NYC Traffic" → my-project.dataset.traffic_table
#      Error: Permission bigquery.tables.get denied on table (or it may not exist)
#    Solutions:
#      1. Grant access to these tables in the destination connection
#      2. Ensure tables/views exist in the destination data warehouse
#      3. Use --skip-source-validation to create the map anyway
```

*Scenario 6 — Skip source validation (intentional broken map):*

```bash
carto maps copy abc123 --dest-profile prod \
  --connection-mapping "dev-bq=prod-bq" \
  --skip-source-validation
# ✅ Success — map created but datasets won't load data until access is fixed
```

### Troubleshooting

**Error: "Connection 'X' not found in destination organization"**

* Run `carto connections list --profile <dest-profile>` to see available connections.
* Create the missing connection in the destination organization.
* Use `--connection-mapping` to map to a different name.

**Error: "Source validation failed - datasets cannot access their data sources"**

* The destination connection lacks permission to access the source tables/queries.
* Grant the necessary permissions in your data warehouse (BigQuery, Snowflake, …).
* Verify table names/paths are correct and exist in the destination.
* Use `--skip-source-validation` if you want to create the map anyway and fix access later.

**Map created but visualizations don't load**

* This shouldn't happen with validation enabled (the default).
* If you used `--skip-source-validation`, check dataset connections and permissions.

## Organization statistics

```bash
# View organization statistics and quotas
carto org stats

# Example output:
# === Organization Statistics ===
#
# Users
#   Total users:           184
#   Editor users:          179
#   Viewer users:          1
#   Superadmin users:      2
#   API Access Tokens:     2,374
#
# Resources
#   Maps:                  3,792 (2,897 public)
#   All users maps:        13,624
#   Workflows:             872
#   Connections:           569
#   Applications:          201
#
# Usage & Quotas
#   Usage quota:           7,702,490
#   LDS credits:           1,069,663 of 15,000,000 (7%)
#   Map loads:             53,194
#
# AI Quotas
#   Builder Gen AI:        0 of 250 threads
#   AI Agents tokens:      292,187 available

# JSON output for scripting
carto org stats --json
```

The displayed information depends on your permissions:

* **Regular users** — see resource counts and basic stats.
* **Admin users** — see full organization statistics including quotas.
* **Access denied** for some stats — partial data is shown with notes.

## User management

```bash
# List all users
carto users list

# Filter by role
carto users list --role Builder
carto users list --role Viewer --all

# Search for specific users
carto users list --search "john"
carto users list --search "@company.com"

# Get detailed info (by user ID or email)
carto users get google-oauth2|123456789
carto users get jatorre@carto.com

# Invite a single user
carto users invite newuser@company.com --role Builder

# Invite multiple users at once
carto users invite user1@company.com,user2@company.com --role Viewer

# Check pending invitations
carto users invitations

# JSON output for automation
carto users list --json | jq '.[] | {email, roles: .app_metadata.roles}'
```

## Activity data analysis

Query activity data with DuckDB SQL — no data warehouse needed. The first query with a given date range downloads data (\~10s); subsequent queries are instant from the local cache.

```bash
# Simple count
carto activity query --start-date 2025-10-01 --end-date 2025-10-07 \
  --sql "SELECT COUNT(*) as total_events FROM activity"

# Maps created per user, joined with userList for emails
carto activity query --start-date 2025-10-01 --end-date 2025-10-07 --sql "
  SELECT
    CAST(a.ts AS DATE) as date,
    u.email,
    COUNT(*) AS created_maps
  FROM activity a
  JOIN userList u ON json_extract_string(a.data, '$.userId') = u.user_id
  WHERE a.type = 'MapCreated'
  GROUP BY date, u.email
  ORDER BY created_maps DESC
  LIMIT 10
"

# User activity by role
carto activity query --start-date 2025-10-01 --end-date 2025-10-07 --sql "
  SELECT u.email, u.role, COUNT(*) as events
  FROM activity a
  JOIN userList u ON json_extract_string(a.data, '$.userId') = u.user_id
  GROUP BY u.email, u.role
  ORDER BY events DESC
"

# Export raw files for loading into your warehouse
carto activity export --start-date 2025-10-01 --end-date 2025-10-07 --format parquet
```

See [`activity` command reference](/carto-for-agents/cli/command-reference/activity.md) for the full schema and DuckDB syntax tips.

## Chatting with a map's AI agent

```bash
# Interactive multi-turn conversation
carto aifeature aiagent <map-id>

# One-shot
carto aifeature aiagent <map-id> "What are the traffic patterns?"

# Continue a previous conversation
carto aifeature aiagent <map-id> "Tell me more" --conversation-id abc123

# Pipe a message
echo "Analyze the collision data" | carto aifeature aiagent <map-id>

# JSON for automation / CI agent quality tests
carto aifeature aiagent <map-id> "Summarize the data" --json
```

Useful for testing agent instructions during development, debugging which workflows the agent invokes, and integrating agent validation into CI pipelines.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.carto.com/carto-for-agents/cli/examples.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
