Launched:self-serve migrations intoSuperhuman Docs (Coda)
Try it now
01Agent-first
Runs where you already work
Plug it into Claude, ChatGPT or Cursor. Describe the move in plain English; the agent runs it.
02Engineer-led
Our production engine, unlocked
The pipeline our engineers use on managed enterprise migrations — the same code, now something you can drive yourself.
03Pricing
Try 10 pages free, then $1 a page
Credit-based, pay-as-you-go. No scoping call, no quote — sample it on your own docs before you spend anything.
04Sources
NotionSlabConfluenceSoonGoogle DocsSoon
Skip to content

Slab to Slack Canvas Migration Guide: API Limits & Data Mapping

Migrate Slab to Slack Canvas using Markdown export, not the API. Covers topic-to-channel mapping, one-canvas-per-channel limits, permissions, images, and what data doesn't survive.

Raajshekhar Rajan Raajshekhar Rajan · · 18 min read
Slab to Slack Canvas Migration Guide: API Limits & Data Mapping
TALK TO AN ENGINEER

Planning a migration?

Get a free 30-min call with our engineers. We'll review your setup and map out a custom migration plan — no obligation.

Schedule a free call
  • 1,500+ migrations completed
  • Zero downtime guaranteed
  • Transparent, fixed pricing
  • Project success responsibility
  • Post-migration support included

Slab to Slack Canvas Migration Guide: API Limits & Data Mapping

Slab to Slack Canvas migration has no native pathway — no connector, no import wizard, no plugin. The fastest starting point is Slab's built-in full workspace Markdown export from admin settings, not the API. From there, each Markdown file becomes the body of a Slack canvas created via the canvases.create or conversations.canvases.create API, which accepts document_content in Markdown format. The hard parts are structural: Slab's nested topic hierarchy has no equivalent in Canvas, each channel can have only one channel canvas via the legacy API, and several categories of Slab metadata — version history, reactions, comments, insights — cannot be written to Canvas at all.

This guide covers the export options, the structural mapping from Slab topics to Slack channels and canvases, the permissions gap between Slab groups and Slack channel membership, image re-hosting, and exactly what data survives, what degrades, and what is permanently lost.

Admin privileges do not guarantee full data access. Admins can export a copy of all published posts and topics in Slab, but cannot export secret topics they are not a member of, nor drafts. Before exporting, have an admin join every secret topic that needs to migrate. A full pre-migration access audit is required to ensure no orphaned documents are left behind.

Start with Slab's Markdown Export, Not the API

Slab's admin export is the single biggest time-saver in this migration. The export lives under Team Settings → Import & Export → Download next to Published Posts. Select Markdown as the file type.

Slack's Canvas API accepts document_content with {"type": "markdown"}, so Markdown files map directly to canvas bodies with minimal conversion. The export produces a ZIP organized by topic, giving you the folder structure you need to script the channel-to-canvas mapping.

Why the API is a worse starting point

Slab's API is GraphQL-only, available at https://api.slab.com/v1/graphql. There are no REST endpoints. API access requires the Business or Enterprise plan — Free and Startup plans cannot use it. All requests run as the Slab Bot user, so content visibility is limited to what that bot can access.

Three constraints make the API a poor first choice for bulk extraction:

  1. Content format. The API returns post bodies in Slab's internal Quill Delta JSON format, not Markdown. Converting Quill Delta to Markdown requires a dedicated converter library — quill-delta-to-markdown (npm) and quill-to-markdown are the most commonly used implementations. Known edge cases include nested ordered lists that produce incorrect indentation, tables that lose column alignment, and custom Slab embeds that have no Quill Delta representation and must be discarded.

  2. No bulk export query. There is no bulk export endpoint — you paginate through posts one query at a time using SearchPosts or GetOrganizationPosts with cursor-based pagination. For a workspace with 500 posts, that is 500 individual requests minimum. A representative pagination query:

query GetPosts($cursor: String) {
  organization {
    posts(first: 50, after: $cursor) {
      pageInfo {
        hasNextPage
        endCursor
      }
      edges {
        node {
          id
          title
          content
          updatedAt
          topics {
            id
            name
          }
        }
      }
    }
  }
}

Pass the returned endCursor as $cursor on the next request until hasNextPage is false.

  1. Rate limits. Slab does not publish exact rate limit ceilings. In observed migration runs against Business-tier workspaces, sustained request rates above approximately 60 requests/minute consistently trigger 429 responses. Implement exponential backoff starting at 2 seconds, doubling on each retry, capped at 60 seconds. Without this, extraction for a 500-post workspace can stall repeatedly and extend from hours to days.

The API helps in two specific cases: filling in secret topics the admin couldn't export (after adding the Slab Bot user to those topics), and pulling structured metadata like topic hierarchy and membership that the ZIP export doesn't include. For everything else, start with the export.

Practical split:

  • Use the admin export for body content and broad extraction. It is the closest thing Slab offers to a workspace dump.
  • Use the API for enrichment and delta passes. Useful for looking up specific records, pulling topic hierarchy metadata, or automating small re-runs.
  • Do not build your schedule around undocumented throughput. Slack publishes its Canvas rate tiers. Slab does not publish equivalent API tiers — test reads in your own workspace early and record your observed ceiling.

Required OAuth scopes for the Slack Canvas API

Before writing any migration code, configure your Slack app with the following scopes. Missing scopes produce cryptic missing_scope errors mid-run.

Operation Required scope
canvases.create canvases:write
conversations.canvases.create canvases:write
canvases.edit canvases:write
canvases.access.set canvases:write
canvases.getContent canvases:read
files.getUploadURLExternal files:write
files.completeUploadExternal files:write
files.info files:read
conversations.create channels:manage (public), groups:write (private)

Use a bot token (xoxb-) for all API calls. User tokens (xoxp-) work for some endpoints but create ownership attribution problems — canvases created with a user token are owned by that user, not the bot, which complicates later permission management.

How Slab Topics Map to Slack Channels and Canvases

Slab organizes content as Posts inside Topics. Topics can be nested — a top-level topic like "Engineering" might contain subtopics for "Backend," "Frontend," and "Infrastructure," each with their own posts. Subtopics can themselves contain subtopics, creating deep hierarchies. A single post can also belong to multiple topics, acting more like labels than rigid folders.

Slack Canvas has no folder concept. A canvas is either a standalone document or a channel canvas pinned to a channel's tab. There is no way to nest canvases inside each other or organize them into topic-level groupings natively.

Why you can't map one topic to one channel canvas

The natural instinct is to create a Slack channel per Slab topic and dump that topic's posts into channel canvases. This breaks immediately: calling conversations.canvases.create when a channel canvas already exists returns a channel_canvas_already_exists error. A single topic with 30 posts cannot become 30 channel canvases — only one channel canvas exists per channel via the legacy API.

The April 9, 2025 product change: Slack began converting legacy channel and DM canvases into canvases added as tabs. Channels and DMs can now have up to 15 tabs. However, the conversations.canvases.create endpoint still treats the first canvas as the designated "channel canvas" and returns channel_canvas_already_exists on subsequent calls to the same endpoint for the same channel — the API has not fully caught up to the multi-tab UI model. To add canvases beyond the first to a channel, create them as standalone canvases via canvases.create and share them to the channel via canvases.access.set. Do not rely on conversations.canvases.create for the second through fifteenth tabs. Verify this behavior against your Slack workspace's API version before finalizing your migration script.

The working pattern: index canvas + standalone canvases

The proven approach for multi-post topics:

  1. Create one channel per Slab topic (or per top-level topic, flattening subtopics).
  2. Use the channel canvas as an index — a table of contents with links to standalone canvases.
  3. Create each Slab post as a standalone canvas via canvases.create, passing the Markdown body in document_content.
  4. Grant access to the appropriate channels using canvases.access.set.

A standalone canvas is a Slack canvas created outside a single channel-owned surface and then shared independently to channels or people. That is the unit you want for most migrated Slab posts because it can be reused across channels and permission contexts. Standalone canvases require a paid Slack plan — they are not available on the free tier. If your workspace is on the free plan, the index + standalone pattern breaks entirely and you are limited to one canvas per channel.

# Create a standalone canvas and share it to a channel
result = client.canvases_create(
    title="Backend: Database Runbook",
    document_content={
        "type": "markdown",
        "markdown": markdown_body  # from Slab export, with rewritten image URLs
    }
)
canvas_id = result["canvas_id"]
 
# Grant write access to the #engineering-backend channel
client.canvases_access_set(
    canvas_id=canvas_id,
    access_level="write",
    channel_ids=["C0BACKEND01"]
)

The canvases.access.set method accepts a channel_ids array to share a standalone canvas with channels. The array has a hard maximum of 20 channel IDs per call. You cannot pass channel_ids and user_ids in the same call — they are mutually exclusive. If a canvas needs to be visible in more than 20 channels, batch the calls. If your target audience is DMs or MPDMs, use user_ids instead of channel_ids.

canvases.create is rate-limited at Tier 2 (20+ requests per minute). canvases.access.set is Tier 3 (50+ per minute). For a workspace with 500 posts, expect the canvas creation step alone to take at least 25 minutes of API time — plan for longer with image uploads and access grants.

Slab post URLs follow the pattern https://your-org.slab.com/posts/post-title-{post-id} where post-id is a short alphanumeric identifier (e.g., ab12cd34). The Slab Markdown export preserves internal links in this format. After migration, these URLs are broken.

The rewriting process:

  1. During the Slab API enrichment pass, build a lookup table mapping each Slab post ID to its title and topic.
  2. After creating each Slack canvas, record the returned canvas_id. Slack canvas URLs follow the pattern https://your-org.slack.com/docs/{canvas_id}.
  3. Before creating canvases, replace Slab internal URLs in each Markdown file using your post-ID-to-canvas-ID map. Use a regex like https?://[^/]+\.slab\.com/posts/[^/]+-([a-z0-9]+) to extract the post ID for lookup.
  4. If a referenced post has not yet been created as a canvas (due to ordering), use a placeholder (e.g., [PENDING:{post_id}]) and run a second pass after all canvases exist.

Handling Markdown tables

Slab uses standard GitHub Flavored Markdown (GFM) tables. Slack Canvas Markdown support for tables is limited and inconsistent: simple two-column tables with short cell content generally render correctly, but tables with more than four or five columns, cells containing line breaks, or merged cells do not render — they display as raw pipe-delimited text. For complex tables, convert them to a numbered list with bold labels, or capture a screenshot and upload as an image. Flag any Slab post containing tables for manual review before canvas creation.

Handling nested topic hierarchies

Slab allows deep nesting: Engineering → Backend → Databases → PostgreSQL. Slack channels are flat. Two strategies:

Strategy How it works Trade-off
Flatten to top-level Map "Engineering" to #eng, all subtopic posts become standalone canvases linked from the channel canvas index Loses subtopic grouping; index canvas can get long
Create channels per leaf topic Map "PostgreSQL" to #eng-backend-postgresql Preserves granularity but can create dozens of low-activity channels

Most teams choose a hybrid: channels for the first two levels, and headings within the index canvas for anything deeper.

Here is how common Slab source types map to Slack targets:

Slab source Best Slack target Why
Top-level topic One primary channel + index canvas Gives users a landing page
Subtopic Standalone canvas linked from the index Replaces missing folder/tree behavior
Short post Section inside a larger topic canvas Reduces canvas sprawl
Long or permission-sensitive post Dedicated standalone canvas Easier to share, audit, and update
Multi-topic post One standalone canvas shared to multiple channels Slab's additive access rarely maps cleanly to a single channel

How Slab Permissions Map to Slack Channel Membership

Slab's permission model is finer-grained than Slack's. Slab topics support two member roles: topic owner (can edit freely regardless of per-topic permission settings) and topic member (subject to the topic's edit permission rules). Groups can be added to topics with either role, and all group members inherit that role. A subtopic inherits its parent topic's membership by default unless explicitly overridden.

Slack channel membership is coarser. A channel member can either post or not; canvas editing is controlled per-canvas via canvases.access.set with read, write, or owner access levels. There is no equivalent of Slab's "members can edit the topic but not its posts" granularity, and there is no inheritance model — each canvas requires explicit access grants.

Practical mapping:

Slab permission type Slack equivalent Notes
Public topic Public channel All workspace members can discover and join
Private topic Private channel Invite Slab group members explicitly
Secret topic Private channel (closest approximation) Slack has no true secret channel — any workspace admin can see a private channel exists
Topic owner Canvas owner access via canvases.access.set Single owner only; co-ownership is not supported
Topic member with edit rights Canvas write access
Topic member read-only Canvas read access
Subtopic permission inheritance Must be set explicitly per canvas No automatic inheritance in Slack
Post in multiple private topics One standalone canvas shared to multiple audiences if access levels match; duplicate canvases if they differ

Do not use public channels as a shortcut for restricted content. If you share a restricted standalone canvas in a public channel, it becomes discoverable by everyone in the workspace or Enterprise organization, silently widening access compared with a Slab private or secret topic.

Comment-only access: Slack's Canvas UI supports a comment-only permission level, but canvases.access.set documents only read, write, and owner. If your Slab model depends on reviewer-only access, budget for manual permission cleanup or accept a simpler read/write split in the automated phase.

External collaborators: Slab's post-level guest access cannot map directly to Slack Canvas without inviting guests to the corresponding channels. Contractors who had access to a single Slab post must be either added to a shared channel (Slack Connect) or provisioned as single-channel guests via the Slack SCIM API. For more than 10–15 external collaborators, build a dedicated sub-routine in the migration script to audit and recreate guest access.

How to Handle Images, Embeds, and Large Posts

Re-uploading images from Slab's CDN

Slab hosts images on its own CDN. When you export to Markdown, image references point to Slab-hosted URLs that are authenticated against your active workspace. These URLs break after you decommission Slab.

You must re-upload images to Slack before creating the canvas that references them. The Slack Canvas API supports images in two ways:

  1. Publicly-hosted image URL. Pass a public URL directly in the Markdown. This works but creates a dependency on an external host — if that host changes or requires auth, images break again.
  2. Slack-hosted image permalink. Upload the image to Slack first, then use the returned permalink in the canvas Markdown. This is the durable approach.

The Slack file upload flow for images:

  1. Call files.getUploadURLExternal with the filename and file size in bytes. This returns an upload_url and a file_id. Slack supports file uploads up to 1 GB via this endpoint, though per-workspace storage limits apply.
  2. POST the binary image data to the upload_url.
  3. Call files.completeUploadExternal with the file_id and the channel ID where it will be used.
  4. Call files.info with the file_id to retrieve the permalink field.
  5. Replace the Slab CDN URL in the Markdown with the permalink.

Order matters. Create the canvas only after rewriting image URLs. Re-uploading after canvas creation means editing every canvas to swap URLs — doable but wasteful.

Slack file visibility is tied to sharing. An uploaded file is initially private to the uploading user or bot. Ensure the file is explicitly shared to the relevant channel during the files.completeUploadExternal call, or users will see a broken image icon even though the URL is technically correct.

Batch image uploads as a separate first pass. Image uploads are not subject to the same rate tier as canvas creation. Run the full image pipeline first, build a URL mapping table (Slab CDN URL → Slack permalink), then use that table during canvas creation. This also ensures that if canvas creation fails mid-run, you don't re-upload images on retry.

Handling embeds

Treat embeds as graceful degradation, not literal preservation. Slack Canvas Markdown accepts only a defined subset of Markdown — Block Kit is not supported inside canvases. Slab content that depends on iframes, rich embeds (Loom, Figma, Airtable), or editor-specific widgets should be converted to one of:

  • A plain hyperlink to the original embed source
  • A screenshot uploaded as a static image
  • A short italicized note: [Embedded Loom video — original: https://...]

Flag all embeds during your pre-migration parse and route them to manual review if fidelity matters.

Canvas content limits

  • Content type: Only Markdown is accepted in document_content. No HTML, no rich text JSON.
  • Size limit: Markdown content is limited to 1 MiB (1,048,576 bytes) per document_content object. This limit also applies to each change object in canvases.edit calls. Most Slab posts fall well under this limit individually, but merged documents (combining a subtopic's posts into one canvas) can approach it.
  • Heading levels: Canvas supports h1–h3 only. Slab Markdown exports may produce h4–h6 headings, which render as plain bold text in Canvas — functional but semantically degraded. During the Markdown rewrite step, downgrade all h4 to h3 and h5/h6 to bold (**text**).
  • Edit operations: canvases.edit allows only one operation per API call. For large posts assembled from multiple sections, create the canvas shell first, then insert sections sequentially.

Use canvases.getContent after each write to compare Slack's stored Markdown with your transformed source. It is the most reliable QA tool for catching broken links, missing sections, and image rewrite failures.

What Data Does Not Survive the Migration

Post version history — permanently lost

Slab tracks full revision history on every post, allowing reversion to previous states. The Slack Canvas API has no method to write version history. canvases.create and canvases.edit create or modify the current state only. Slack does maintain version history for canvases going forward, but you cannot backfill historical revisions.

Mitigation: Archive the Slab export ZIP (Markdown files carry timestamps) alongside the migration log as an offline audit record.

Contributors and authorship — permanently lost

Slab tracks who authored and edited each post. Canvas ownership is set to the bot or user token that created the canvas. You can transfer ownership with canvases.access.set using access_level: "owner", but only to a single user. Co-authorship metadata does not transfer.

Mitigation: Stamp the original author list into each migrated canvas header: *Originally authored by: [names] in Slab*.

Reactions — permanently lost

Slab supports emoji reactions on posts. The Slack Canvas API has no method to add reactions to a canvas. Slack's reactions.add method works on messages only, not canvases.

Insights and analytics — permanently lost

Slab Team Insights (post views, read time, search analytics) are platform-specific. No write endpoint exists on the Slack side. Preserve this data in your migration workbook — it is useful for deciding which posts deserve standalone canvases versus archival during the mapping phase.

Comments — structurally incompatible

Slab supports threaded comments anchored to highlighted text. Slack Canvas also supports anchored comments in the UI — comments on a canvas behave like messages in threads, appearing in both Threads view and the Activity tab. However, there is no API method to create a comment on a canvas, let alone anchor it to a specific section. Canvas comments are a UI-only feature with no write API as of mid-2025.

Mitigation: Append Slab comments as a "Legacy Comments" section at the bottom of each canvas, formatted as a Markdown list. You lose positional anchoring but preserve the text content.

Survival summary

Slab data Migrates to Canvas? Recovery option
Post body (text, formatting) ✅ Yes — via Markdown Direct mapping
Post title ✅ Yes — canvas title Direct mapping
Topic structure ⚠️ Partial — channels + index canvas Manual hierarchy flattening
Images and files ⚠️ Requires re-upload Download from Slab CDN; re-host via Slack files API
Markdown tables ⚠️ Simple tables only Complex tables → list format or screenshot
Internal links between posts ⚠️ Requires URL rewriting Extract Slab post IDs; map to Slack canvas URLs
Topic permissions ⚠️ Coarser model Channel membership + explicit canvas access levels
External collaborator access ⚠️ Requires SCIM/Slack Connect Per-guest manual provisioning
Comments ❌ No API write support Append as text block at bottom of canvas
Version history ❌ No backfill API Archive Slab export ZIP offline
Reactions ❌ No canvas reactions API None
Contributors ❌ Single owner only Stamp original authors in canvas header
Insights / analytics ❌ Platform-specific Preserve in migration workbook
H4–H6 headings ⚠️ Render as bold text Downgrade to H3 or bold during rewrite
Embeds (Loom, Figma, etc.) ❌ No iframe support Convert to link, screenshot, or note

Step-by-Step Migration Workflow

Step 1: Audit and freeze. Have an admin join all secret topics. Add the Slab Bot user to any private topics you need API access to. Freeze edits in Slab to prevent content drift during migration.

Step 2: Export from Slab. Download the full Markdown export from Team Settings → Import & Export. Unzip and verify the folder structure matches expected topics. Note any topics that appear missing — these are likely secret topics the admin wasn't a member of.

Step 3: Enrich with the Slab API. Run the GraphQL GetOrganizationPosts pagination query to build a metadata table: post ID → title, topic IDs, topic hierarchy, member groups, access level. This is the mapping source for steps 5 and 8.

Step 4: Download and re-upload images. Parse all Markdown files for image URLs using !\[.*?\]\((https?://[^\)]+)\). Download from Slab CDN while the workspace is still active. Upload to Slack via files.getUploadURLExternal → POST binary → files.completeUploadExternal. Call files.info for each uploaded file. Build a URL mapping table: Slab CDN URL → Slack permalink.

Step 5: Rewrite Markdown. Replace Slab image URLs with Slack permalinks from your mapping table. Rewrite internal Slab post links using the post-ID-to-canvas-ID map (use placeholders for posts not yet created). Downgrade h4–h6 headings to h3 or bold. Convert or flag complex Markdown tables. Convert unsupported embeds to links or notes.

Step 6: Create Slack channels. Create a channel for each Slab topic according to your mapping (public for public topics, private for private and secret topics). Set channel membership based on Slab group membership from step 3.

Step 7: Create the channel canvas index. For each channel, call conversations.canvases.create to create the channel canvas with a table of contents. Use placeholder links initially; update after step 8.

Step 8: Create standalone canvases. For each Slab post, call canvases.create with the rewritten Markdown body. Record the returned canvas_id and the resulting canvas URL (https://your-org.slack.com/docs/{canvas_id}). Respect the Tier 2 rate limit (20+ req/min) with appropriate backoff.

Step 9: Resolve placeholder links. Run a second Markdown rewrite pass to replace [PENDING:{post_id}] placeholders with actual Slack canvas URLs. Edit the affected canvases via canvases.edit.

Step 10: Grant access. Call canvases.access.set for each standalone canvas with the relevant channel_ids (max 20 per call) or user_ids. Set access_level to write, read, or owner based on original Slab permissions.

Step 11: Update index canvases. Edit each channel canvas to insert actual canvas links and finalize the table of contents.

Step 12: Validate. Spot-check a representative sample of canvases for formatting, images, internal links, and access levels. Call canvases.getContent and diff against your transformed source files. Verify that users in the correct channels can see and edit the right canvases. Confirm external collaborators have been provisioned.

When This Migration Makes Sense (and When It Doesn't)

Slab to Slack Canvas is a reasonable move when your team already lives in Slack and wants to eliminate a separate knowledge base tool. The content stays where conversations happen.

Poor fit conditions:

  • Deep topic hierarchies — Canvas's flat structure loses real organizational fidelity beyond two levels.
  • Version history or compliance auditing — Canvas has no backfill for historical revisions; the offline ZIP archive is the only fallback.
  • Heavy commenting workflows — Canvas comments cannot be migrated programmatically; you lose anchor positions and threading context.
  • Free Slack plan — Standalone canvases require a paid plan; the index + standalone pattern is unavailable.
  • Large numbers of external collaborators — Post-level guest access in Slab requires per-guest SCIM provisioning in Slack, which is operationally expensive above ~15 external users.
  • Complex table-heavy content — Slack Canvas's limited table rendering degrades multi-column, formatted tables to raw text.

Good fit conditions:

  • Reference documentation — runbooks, onboarding guides, API docs, decision records — where rich revision history and anchored comments are not critical.
  • Teams that already use Slack channels as the primary collaboration surface and want to reduce context switching.
  • Workspaces with relatively flat topic structures (two levels or fewer) and straightforward public/private permission splits.

For teams where the above conditions don't hold, compare this path with Slab to Notion, Slab to Confluence, Slab to Guru, and the Quip to Slack Canvases route.

Planning a Slab to Slack Canvas Migration?

A clean Slab-to-Slack Canvas migration is not a file conversion project. It is a controlled flattening of hierarchy, a permission redesign, and a clear decision about what becomes living Slack-native content versus archived Slab history. The structural incompatibilities — flat vs. nested, coarse vs. fine permissions, no comment write API — are not edge cases. They are the core of the problem.

Get the export order right (images before canvases, canvases before access grants, access grants before index updates), implement exponential backoff for both the Slab and Slack APIs, and validate with canvases.getContent before treating any batch as complete.

Frequently Asked Questions

Is there a native Slab to Slack Canvas migration tool?
No. Slack documents an official conversion flow for Quip, not Slab, so Slab-to-Canvas migrations are custom export-and-transform projects. The fastest method is exporting Markdown from Slab's admin settings, then scripting canvas creation via Slack's canvases.create API, which accepts Markdown directly.
Should I use Slab's export or the API for migration?
Start with Slab's admin Markdown export for body content. The API is GraphQL-only, returns content in Quill Delta JSON (not Markdown), has no bulk export endpoint, and enforces undocumented rate limits. Use the API only for enrichment — filling in secret topics or pulling topic hierarchy metadata the export doesn't include.
How do I map Slab's nested topics to Slack Canvas?
Slack Canvas has no folder concept, and only one channel canvas exists per channel. The working pattern is to create a channel per top-level topic, use the channel canvas as an index (table of contents), and create each Slab post as a standalone canvas linked from that index.
What Slab data is lost when migrating to Slack Canvas?
Post version history, contributor metadata, emoji reactions, team insights, and comments are permanently lost or have no API write support on the Slack Canvas side. Post body content, titles, and images survive with proper re-uploading and Markdown conversion.
Do Slab images work in Slack Canvas after migration?
Not directly. Slab hosts images on its own CDN with authenticated URLs that break when you decommission Slab. You must download images and re-upload them to Slack via files.getUploadURLExternal before creating the canvas, then replace the old URLs with Slack permalinks in your Markdown.

More from our Blog