> For the complete documentation index, see llms.txt.
Skip to main content

Check out Port for yourself ➜ 

Ingest Slack data into Port

Implement with AI

Send this guide to your coding agent.

Prerequisite: Install Port MCP

Open plan mode. Implement this Port guide in my org via MCP:

https://docs.port.io/guides/all/ingest-slack-data-via-airbyte-s3-and-webhook/

Goal: get the guide's core flow working end-to-end in my org; adapting it to fit my existing setup takes priority over matching the guide 1:1.

Plan:
1. Confirm MCP is connected, in the right org, with sufficient permissions.
2. Diff the guide's data model (blueprints, properties, relations, actions, agents, automations, integrations, secrets) against mine.
3. Propose adaptations for gaps, reusing existing blueprints/relations over guide-named duplicates.
4. Flag what needs a UI click, credential, or secret from me, testing MCP capability empirically before ruling anything out.
5. Stop on any blocker and give me options. Approving this plan authorizes the writes it lists; pause only for writes beyond what's listed.

Build:
- Extend blueprint schema additively when upserting; don't remove or overwrite existing properties, and treat type conflicts as a blocker, not an auto-fix.
- List any mock data in the plan, minimal and labeled mock; once approved, seed it without re-asking, and tell me what you seeded.
- For anything the guide writes downstream (e.g. a webhook target), use a real entity, not a mock.
- For pages/widgets, use the real page identifier from the app URL, not a guessed slug.
- When you hit a UI step confirmed (not assumed) unsupported via MCP, pause, give exact clicks, then resume via MCP.
- Validate and give links after each meaningful step (only a tool-returned URL, no guessed paths); don't proceed if the last run wasn't a success.

Done:
- Confirm the guide's expected output exists and runs in Port.
- Summarize adaptations, seeded data, what was mocked or skipped, remaining UI steps, and how to verify.

This guide demonstrates how to ingest Slack channels, users, and channel membership data into Port using Airbyte or Fivetran, S3, and a webhook integration.

Native Slack integration available

For most use cases, prefer Port's native Slack integration, which ingests Slack data directly without an external ETL pipeline. Use this guide when you need a custom ETL flow through S3.

Common use cases

  • Ingest Slack channels and users through an existing Airbyte or Fivetran pipeline.
  • Map Slack users to Port user accounts by email.
  • Track Slack channel memberships in your context lake.

Because this guide uses Port's S3 integration, review the following limitation before continuing:

Disclaimer

S3 integrations lack some of the features (such as reconciliation) found in Ocean or other Port integration solutions.

As a result, if a record ingested during the initial sync is later deleted in the data source, there’s no automatic mechanism to remove it from Port. The record simply won’t appear in future syncs, but it will remain in Port indefinitely.

If the data includes a flag for deleted records (e.g., is_deleted: "true"), you can configure a webhook delete operation in your webhook’s mapping configuration to remove these records from Port automatically.

Prerequisites

  • Ensure you have a Port account and have completed the onboarding process.
  • This feature is part of Port's limited-access offering. To obtain the required S3 bucket, contact our team directly via chat, Slack, or the support site, and we will create and manage the bucket on your behalf.
  • Access to a Slack account with privileges to approve the Slack app installation for your ingestion provider.

Choose the ingestion provider you want to use:

  • Access to an available Airbyte app. You can use Airbyte Cloud or a self-hosted Airbyte deployment. For reference, follow Airbyte's quick start guide.
Very short Quickstart Guide for macOS
  1. Download and Install Docker Desktop

  2. Install abctl:

curl -LsfS https://get.airbyte.com | bash -
  1. Install Airbyte locally:
abctl local install

The application will be available by default in http://localhost:8000/

You can find your password by typing in a terminal (see screenshot):

abctl local credentials
Airbyte login page with terminal credentials output
Include email data

If you want to include email data, add the user.email:read permission to the Slack app in addition to the permissions listed in Airbyte's guide.

Set up data model

Create the Slack channel membership, Slack channel, and Slack user blueprints.

  1. Go to the Builder page.

  2. Click + Blueprint.

  3. Click Edit JSON.

  4. Copy and paste the following JSON configuration into the editor:

    Slack channel membership blueprint (Click to expand)
    {
    "identifier": "slack_channel_membership",
    "description": "Slack Channel Membership",
    "title": "Slack Channel Membership",
    "icon": "Slack",
    "schema": {
    "properties": {
    "member_id": {
    "type": "string",
    "description": "ID of the user who is a member of the channel."
    },
    "channel_id": {
    "type": "string",
    "description": "ID of the channel the user belongs to."
    }
    },
    "required": [
    "member_id",
    "channel_id"
    ]
    },
    "mirrorProperties": {},
    "calculationProperties": {},
    "aggregationProperties": {},
    "relations": {}
    }
  5. Click Save to create the blueprint.

Repeat the same process for the Slack channel blueprint.

  1. Go to the Builder page.

  2. Click + Blueprint.

  3. Click Edit JSON.

  4. Copy and paste the JSON configuration for your ingestion provider into the editor:

    Slack channel blueprint for Airbyte (Click to expand)
    {
    "identifier": "slack_channel",
    "description": "Slack Channel",
    "title": "Slack Channel",
    "icon": "Slack",
    "schema": {
    "properties": {
    "is_private": {
    "type": "boolean",
    "description": "Indicates if the channel is private."
    },
    "context_team_id": {
    "type": "string",
    "description": "ID of the team the channel belongs to."
    },
    "is_channel": {
    "type": "boolean",
    "description": "Indicates if this is a channel (true) or a direct message (false)."
    },
    "is_shared": {
    "type": "boolean",
    "description": "Indicates if the channel is shared across teams."
    },
    "previous_names": {
    "type": "array",
    "description": "List of previous names of the channel."
    },
    "creator": {
    "type": "string",
    "description": "ID of the user who created the channel."
    },
    "createdAt": {
    "type": "number",
    "description": "Timestamp of when the channel was created."
    },
    "is_ext_shared": {
    "type": "boolean",
    "description": "Indicates if the channel is externally shared."
    },
    "is_group": {
    "type": "boolean",
    "description": "Indicates if this is a group DM."
    },
    "is_archived": {
    "type": "boolean",
    "description": "Indicates if the channel is archived."
    },
    "shared_team_ids": {
    "type": "array",
    "description": "List of teams the channel is shared with."
    },
    "is_org_shared": {
    "type": "boolean",
    "description": "Indicates if the channel is shared across the entire organization."
    },
    "num_members": {
    "type": "number",
    "title": "num_members"
    },
    "purpose": {
    "type": "string",
    "description": "Information about the channel's purpose."
    },
    "topic": {
    "type": "string",
    "description": "Information about the channel's topic."
    }
    },
    "required": []
    },
    "mirrorProperties": {
    "member_id": {
    "title": "member_id",
    "path": "users.member_id"
    }
    },
    "calculationProperties": {},
    "aggregationProperties": {},
    "relations": {
    "users": {
    "title": "Users",
    "target": "slack_channel_membership",
    "required": false,
    "many": true
    }
    }
    }
  5. Click Save to create the blueprint.

Repeat the same process for the Slack user blueprint.

  1. Go to the Builder page.

  2. Click + Blueprint.

  3. Click Edit JSON.

  4. Copy and paste the following JSON configuration into the editor:

    Slack user blueprint (Click to expand)
    {
    "identifier": "slack_user",
    "description": "Slack User",
    "title": "Slack User",
    "icon": "Slack",
    "schema": {
    "properties": {
    "tz": {
    "type": "string",
    "description": "The user's time zone."
    },
    "is_restricted": {
    "type": "boolean",
    "description": "Indicates if the user is restricted."
    },
    "is_primary_owner": {
    "type": "boolean",
    "description": "Indicates if the user is the primary owner."
    },
    "real_name": {
    "type": "string",
    "description": "The user's real name."
    },
    "team_id": {
    "type": "string",
    "description": "The user's team ID."
    },
    "is_admin": {
    "type": "boolean",
    "description": "Indicates if the user is an admin."
    },
    "is_app_user": {
    "type": "boolean",
    "description": "Indicates if the user is an app user."
    },
    "deleted": {
    "type": "boolean",
    "description": "Indicates if the user is deleted."
    },
    "is_bot": {
    "type": "boolean",
    "description": "Indicates if the user is a bot."
    },
    "email": {
    "type": "string",
    "title": "email"
    }
    },
    "required": []
    },
    "mirrorProperties": {
    "channel_id": {
    "title": "channel_id",
    "path": "membership.channel_id"
    }
    },
    "calculationProperties": {},
    "aggregationProperties": {},
    "relations": {
    "user": {
    "title": "User",
    "target": "_user",
    "required": false,
    "many": false
    },
    "membership": {
    "title": "membership",
    "target": "slack_channel_membership",
    "required": false,
    "many": true
    }
    }
    }
  5. Click Save to create the blueprint.

Configure webhook mapping

Set up the webhook integration mapping that reads Slack objects from your S3 bucket and creates matching Port entities.

Create Webhook Integration

Create a webhook integration to ingest the data into Port:

  1. Go to the Data sources page of your portal.

  2. Click on "+ Data source".

  3. In the top selection bar, click on Webhook, then select Custom Integration.

  4. Enter a name for your Integration (for example: "Hibob Integration"), enter a description (optional), then click on Next.

  5. Copy the Webhook URL that was generated and include set up the airbyte connection (see Below).

  6. Scroll down to the section titled "Map the data from the external system into Port" and paste the following mapping:

Port custom integration JQ mapping editor

Copy the mapping for your ingestion provider into the webhook integration:

Airbyte writes Slack data under the channels, users, and channel_members object paths. Use this mapping for the Airbyte sync:

Slack webhook mapping for Airbyte (Click to expand)
[
{
"blueprint": "slack_channel",
"operation": "create",
"filter": "(.body | has(\"_PORT_SOURCE_OBJECT_KEY\")) and (.body._PORT_SOURCE_OBJECT_KEY | split(\"/\") | .[2] | IN(\"channels\"))",
"entity": {
"identifier": ".body.id | tostring",
"title": ".body.name_normalized | tostring",
"properties": {
"is_private": ".body.is_private",
"purpose": ".body.purpose.value",
"context_team_id": ".body.context_team_id",
"is_shared": ".body.is_shared",
"previous_names": ".body.previous_names",
"creator": ".body.creator",
"createdAt": ".body.created",
"is_ext_shared": ".body.is_ext_shared",
"is_group": ".body.is_group",
"is_archived": ".body.is_archived",
"num_members": ".body.num_members | tonumber? // .",
"topic": ".body.topic.value",
"shared_team_ids": ".body.shared_team_ids",
"is_org_shared": ".body.is_org_shared"
},
"relations": {
"users": {
"combinator": "'and'",
"rules": [
{
"property": "'channel_id'",
"operator": "'='",
"value": ".body.id | tostring"
}
]
}
}
}
},
{
"blueprint": "slack_user",
"operation": "create",
"filter": "(.body | has(\"_PORT_SOURCE_OBJECT_KEY\")) and (.body._PORT_SOURCE_OBJECT_KEY | split(\"/\") | .[2] | IN(\"users\"))",
"entity": {
"identifier": ".body.id | tostring",
"title": ".body.name | tostring",
"properties": {
"tz": ".body.tz",
"is_restricted": ".body.is_restricted",
"is_primary_owner": ".body.is_primary_owner",
"real_name": ".body.real_name",
"team_id": ".body.team_id",
"is_admin": ".body.is_admin",
"is_app_user": ".body.is_app_user",
"deleted": ".body.deleted",
"is_bot": ".body.is_bot",
"email": ".body.profile.email"
},
"relations": {
"user": ".body.profile.email"
}
}
},
{
"blueprint": "slack_channel_membership",
"operation": "create",
"filter": "(.body | has(\"_PORT_SOURCE_OBJECT_KEY\")) and (.body._PORT_SOURCE_OBJECT_KEY | split(\"/\") | .[2] | IN(\"channel_members\"))",
"entity": {
"identifier": ".body.channel_id + \"_\" + .body.member_id | tostring",
"title": ".body.channel_id + \"_\" + .body.member_id | tostring",
"properties": {
"member_id": ".body.member_id",
"channel_id": ".body.channel_id"
}
}
}
]

Set up ingestion pipeline

Choose the provider you want to use to export Slack data into the S3 bucket.

Set up S3 destination

If you have not already set up an S3 destination for Port's S3 integration, follow these steps:

  1. Login to your Airbyte application (cloud or self-hosted).

  2. In the left-side pane, click on Destinations.

  3. Click on + New Destination.

  4. Input the S3 Credentials provided to you by Port:

    • Under S3 Key ID enter your S3 Access Key ID.
    • Under S3 Access Key enter your S3 Access Key Secret.
    • Under S3 Bucket Name enter the bucket name (example: "org-xxx").
    • Under S3 Bucket Path enter "data/".
    • Under S3 Bucket Region enter the appropriate region.
    • For output format, choose "JSON Lines: Newline-delimited JSON".
    • For compression, choose "GZIP".
    • Under Optional Fields, enter the following in S3 Path Format: ${NAMESPACE}/${STREAM_NAME}/year=${YEAR}/month=${MONTH}/${DAY}_${EPOCH}_
  5. Click Test and save and wait for Airbyte to confirm the Destination is set up correctly.

Airbyte S3 destination settings form

Set up Slack connection

  1. Follow Airbyte's Slack connector guide to set up the Slack source.

    Private channels

    Airbyte does not read information from private channels by default. To include private channels, enable Include private channels and manually add the Slack export app to each private channel you want to sync.

    For more information, see set up data source.

  2. After the source is set up, create a + New Connection.

  3. For Source, choose the Slack source you created.

  4. For Destination, choose the S3 destination you created.

  5. In the Select Streams step, select only channel_members, channels, and users.

  6. In the Configuration step, under Destination Namespace, choose Custom Format and enter the webhook URL you copied when setting up the webhook. For example, enter wSLvwtI1LFwQzXXX.

  7. Click Finish & Sync to apply the connection and start the sync.

Important

If you entered different values than the ones specified in this guide, inform Port so we can help ensure the integration runs smoothly.

Test the flow

After the Airbyte sync finishes, go to your Port context lake and confirm that Slack channels, users, and channel memberships were created.

More relevant guides