A developer building a LangChain pipeline that reads Slack pages needs clean page text before ingesting it into a vector store. Slack pages mix message content with channel names, timestamps, reaction counts, member lists, and sidebar navigation, and scraping them by hand requires CSS selectors that break when Slack updates its layout. EnConvert Perceive renders up to 10 Slack pages in a single batch call and returns clean Markdown for each one, with navigation and sidebars stripped by default. The extracted Markdown is ready to load into LangChain Documents and index with no HTML parsing.
How to Scrape Slack with LangChain
Scrape Slack pages into a LangChain pipeline with EnConvert Perceive, returning clean Markdown with navigation and sidebars stripped in a single batch call
Get API keyExample
python
import os
import requests
from langchain_community.vectorstores import FAISS
from langchain_core.documents import Document
from langchain_openai import OpenAIEmbeddings
BASE_URL = "https://api.enconvert.com/v2"
headers = {"X-API-Key": os.environ["ENCONVERT_API_KEY"], "Content-Type": "application/json"}
page_urls = [url.strip() for url in os.environ["SLACK_PAGE_URLS"].split(",")] # public Slack page URLs
if len(page_urls) > 10:
raise ValueError("This example covers inline batches of 10 URLs or fewer")
response = requests.post(f"{BASE_URL}/perceive/batch", headers=headers,
json={"urls": page_urls, "options": {"outputs": ["markdown"]}}, timeout=300)
if response.status_code == 402:
raise RuntimeError("Monthly ops allowance exhausted")
response.raise_for_status()
documents = []
for result in response.json()["items"]:
page_url = result["url"]
if result.get("status") != "completed":
print(f"Skipped {page_url}: {result.get('status')}")
continue
if result.get("is_blocked"):
print(f"Skipped {page_url}: blocked page")
continue
render_quality = result.get("render_quality", 1.0)
if render_quality < 0.40:
print(f"Skipped {page_url}: low render quality ({render_quality:.2f})")
continue
markdown_url = result["outputs"]["markdown"]["url"]
markdown = requests.get(markdown_url, timeout=60)
markdown.raise_for_status()
documents.append(Document(
page_content=markdown.text,
metadata={"source_url": page_url, "render_quality": render_quality},
))
if not documents:
raise RuntimeError("No Slack pages passed the render checks")
embeddings = OpenAIEmbeddings(
model="text-embedding-3-small", api_key=os.environ["OPENAI_API_KEY"]
)
vectorstore = FAISS.from_documents(documents, embeddings)
results = vectorstore.similarity_search("What decisions and action items are discussed in these Slack pages?", k=3)
for doc in results:
print(doc.metadata["source_url"])
print(doc.page_content[:300])
What you get back
Perceive returns clean Markdown for each URL in the batch, with navigation and sidebars stripped by default, delivered as pre-signed URLs that you fetch once per page. Scraping Slack pages by hand needs CSS selectors that break when Slack updates its layout, and passing raw HTML into a LangChain Document fills the vector store index with navigation and boilerplate that degrades retrieval quality.