CrawlForge
HomePlaygroundUse CasesIntegrationsPricingDocumentationBlog
5 Ways to Use CrawlForge with LangChain: AI Web Scraping Tutorial
Tutorials
Back to Blog
Tutorials

5 Ways to Use CrawlForge with LangChain: AI Web Scraping Tutorial

C
CrawlForge Team
Engineering Team
January 8, 2026
12 min read
Updated April 14, 2026

On this page

LangChain is the go-to framework for building LLM applications. CrawlForge MCP provides the web data layer that LangChain apps often need. Together, they're a powerful combination for AI engineers.

This tutorial shows you 5 practical integration patterns with working code examples.

Prerequisites

Bash
npm install langchain @anthropic-ai/sdk dotenv
Bash
# .env
ANTHROPIC_API_KEY=sk-ant-xxxxx
CRAWLFORGE_API_KEY=cf_live_xxxxx

Get your CrawlForge API key at crawlforge.dev/signup - 1,000 free credits included.

1. Web-Augmented RAG Pipeline

The most common use case: enhance your RAG system with fresh web data.

The Problem

Static RAG systems can't answer questions about:

  • Current events
  • Updated documentation
  • Real-time pricing
  • Recent releases

The Solution

Use CrawlForge to fetch and index web content on-demand.

Typescript
import { ChatAnthropic } from "@langchain/anthropic";
import { RecursiveCharacterTextSplitter } from "langchain/text_splitter";
import { MemoryVectorStore } from "langchain/vectorstores/memory";
import { OpenAIEmbeddings } from "@langchain/openai";

// CrawlForge client helper
async function fetchWebContent(url: string): Promise<string> {
  const response = await fetch('https://crawlforge.dev/api/v1/tools/extract_content', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.CRAWLFORGE_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ url })
  });

  const data = await response.json();
  return data.content || '';
}

// Web-augmented RAG
async function webAugmentedRAG(query: string, urls: string[]) {
  // 1. Fetch web content (2 credits per URL)
  const contents = await Promise.all(urls.map(fetchWebContent));

  // 2. Split into chunks
  const splitter = new RecursiveCharacterTextSplitter({
    chunkSize: 1000,
    chunkOverlap: 200
  });

  const docs = await splitter.createDocuments(contents);

  // 3. Create vector store
  const vectorStore = await MemoryVectorStore.fromDocuments(
    docs,
    new OpenAIEmbeddings()
  );

  // 4. Retrieve relevant chunks
  const relevantDocs = await vectorStore.similaritySearch(query, 4);

  // 5. Generate answer with context
  const llm = new ChatAnthropic({
    modelName: "claude-3-5-sonnet-20241022"
  });

  const context = relevantDocs.map(d => d.pageContent).join("\n\n");

  const response = await llm.invoke([
    {
      role: "system",
      content: "Answer based on the provided context. Cite sources when possible."
    },
    {
      role: "user",
      content: `Context:\n${context}\n\nQuestion: ${query}`
    }
  ]);

  return response.content;
}

// Usage
const answer = await webAugmentedRAG(
  "What are the new features in Next.js 15?",
  [
    "https://nextjs.org/blog/next-15",
    "https://nextjs.org/docs/app/building-your-application/upgrading"
  ]
);

Credit Cost: 2 credits per URL fetched

2. Research Agent with Tool Calling

Build an agent that can search and research topics autonomously.

Typescript
import { ChatAnthropic } from "@langchain/anthropic";
import { DynamicStructuredTool } from "@langchain/core/tools";
import { AgentExecutor, createOpenAIFunctionsAgent } from "langchain/agents";
import { z } from "zod";

// Define CrawlForge tools for the agent
const searchTool = new DynamicStructuredTool({
  name: "search_web",
  description: "Search the web for information on a topic",
  schema: z.object({
    query: z.string().describe("The search query"),
    limit: z.number().optional().describe("Number of results (default 5)")
  }),
  func: async ({ query, limit = 5 }) => {
    const response = await fetch('https://crawlforge.dev/api/v1/tools/search_web', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.CRAWLFORGE_API_KEY}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ query, limit })
    });

    const data = await response.json();
    return JSON.stringify(data.results);
  }
});

const extractTool = new DynamicStructuredTool({
  name: "extract_content",
  description: "Extract the main content from a webpage URL",
  schema: z.object({
    url: z.string().describe("The URL to extract content from")
  }),
  func: async ({ url }) => {
    const response = await fetch('https://crawlforge.dev/api/v1/tools/extract_content', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.CRAWLFORGE_API_KEY}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ url })
    });

    const data = await response.json();
    return data.content || 'Failed to extract content';
  }
});

// Create the research agent
async function createResearchAgent() {
  const llm = new ChatAnthropic({
    modelName: "claude-3-5-sonnet-20241022"
  });

  const tools = [searchTool, extractTool];

  // Agent will autonomously decide when to search vs extract
  const agent = await createOpenAIFunctionsAgent({
    llm,
    tools,
    prompt: ChatPromptTemplate.fromMessages([
      ["system", "You are a research assistant. Use search_web to find sources, then extract_content to read them in detail."],
      ["human", "{input}"],
      ["placeholder", "{agent_scratchpad}"]
    ])
  });

  return new AgentExecutor({ agent, tools });
}

// Usage
const agent = await createResearchAgent();
const result = await agent.invoke({
  input: "Research the current state of WebAssembly for AI inference"
});

Credit Cost: 5 credits per search + 2 credits per extraction

3. Competitive Intelligence Pipeline

Monitor competitors and extract structured data.

Typescript
interface CompetitorData {
  name: string;
  pricing: string[];
  features: string[];
  lastUpdated: Date;
}

async function analyzeCompetitor(url: string): Promise<CompetitorData> {
  // Use structured scraping (2 credits)
  const scrapeResponse = await fetch('https://crawlforge.dev/api/v1/tools/scrape_structured', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.CRAWLFORGE_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      url,
      selectors: {
        name: 'h1, .company-name, [data-company]',
        pricing: '.pricing-tier, .plan-price',
        features: '.feature-list li, .features li'
      }
    })
  });

  const scraped = await scrapeResponse.json();

  // Use LLM to structure the data
  const llm = new ChatAnthropic({ modelName: "claude-3-5-sonnet-20241022" });

  const structured = await llm.invoke([
    {
      role: "system",
      content: "Extract competitor data into structured JSON format."
    },
    {
      role: "user",
      content: `Analyze this competitor data: ${JSON.stringify(scraped)}`
    }
  ]);

  return JSON.parse(structured.content as string);
}

// Monitor multiple competitors
async function competitiveIntelligence(competitors: string[]) {
  const results = await Promise.all(
    competitors.map(url => analyzeCompetitor(url))
  );

  // Compare and summarize
  const llm = new ChatAnthropic({ modelName: "claude-3-5-sonnet-20241022" });

  const comparison = await llm.invoke([
    {
      role: "user",
      content: `Compare these competitors and identify market gaps: ${JSON.stringify(results)}`
    }
  ]);

  return { competitors: results, analysis: comparison.content };
}

Credit Cost: 2 credits per competitor

4. Document Processing Chain

Process PDFs and documents from the web.

Typescript
async function processDocuments(documentUrls: string[]) {
  const documents = [];

  for (const url of documentUrls) {
    // Process document (2 credits)
    const response = await fetch('https://crawlforge.dev/api/v1/tools/process_document', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.CRAWLFORGE_API_KEY}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        source: url,
        sourceType: url.endsWith('.pdf') ? 'pdf_url' : 'url'
      })
    });

    const data = await response.json();
    documents.push({
      url,
      content: data.content,
      metadata: data.metadata
    });
  }

  // Split and index documents
  const splitter = new RecursiveCharacterTextSplitter({
    chunkSize: 1500,
    chunkOverlap: 300
  });

  const chunks = await splitter.createDocuments(
    documents.map(d => d.content),
    documents.map(d => ({ source: d.url, ...d.metadata }))
  );

  return chunks;
}

// Use with LangChain vector store
const chunks = await processDocuments([
  'https://example.com/whitepaper.pdf',
  'https://example.com/technical-spec.pdf'
]);

const vectorStore = await MemoryVectorStore.fromDocuments(
  chunks,
  new OpenAIEmbeddings()
);

Credit Cost: 2 credits per document

5. Real-Time Monitoring Chain

Track changes and react to updates.

Typescript
import { RunnableSequence } from "@langchain/core/runnables";

async function checkForChanges(url: string, lastHash: string) {
  const response = await fetch('https://crawlforge.dev/api/v1/tools/track_changes', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.CRAWLFORGE_API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      url,
      operation: 'compare'
    })
  });

  return response.json();
}

// Create a monitoring chain
const monitoringChain = RunnableSequence.from([
  // Check for changes
  async (input: { url: string }) => {
    const changes = await checkForChanges(input.url, '');
    return { ...input, changes };
  },
  // Analyze changes if found
  async (input) => {
    if (!input.changes.hasChanges) {
      return { ...input, analysis: "No changes detected" };
    }

    const llm = new ChatAnthropic({ modelName: "claude-3-5-sonnet-20241022" });
    const analysis = await llm.invoke([
      {
        role: "user",
        content: `Analyze these website changes: ${JSON.stringify(input.changes)}`
      }
    ]);

    return { ...input, analysis: analysis.content };
  },
  // Generate alert if significant
  async (input) => {
    if (input.analysis === "No changes detected") {
      return null;
    }

    return {
      url: input.url,
      timestamp: new Date(),
      analysis: input.analysis,
      raw: input.changes
    };
  }
]);

// Usage
const alert = await monitoringChain.invoke({
  url: "https://competitor.com/pricing"
});

if (alert) {
  console.log("Change detected:", alert);
}

Credit Cost: 2-5 credits per check

Best Practices

1. Cache Aggressively

Typescript
const cache = new Map<string, { content: string; timestamp: number }>();

async function cachedFetch(url: string, ttl = 3600000) {
  const cached = cache.get(url);
  if (cached && Date.now() - cached.timestamp < ttl) {
    return cached.content;
  }

  const content = await fetchWebContent(url);
  cache.set(url, { content, timestamp: Date.now() });
  return content;
}

2. Batch When Possible

Typescript
// Instead of multiple extract_content calls
const urls = ['url1', 'url2', 'url3'];

// Use batch_scrape (1 credit per URL vs 2 per URL)
const response = await fetch('https://crawlforge.dev/api/v1/tools/batch_scrape', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.CRAWLFORGE_API_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ urls })
});

3. Handle Rate Limits Gracefully

Typescript
async function fetchWithRetry(url: string, retries = 3) {
  for (let i = 0; i < retries; i++) {
    const response = await fetch(url);

    if (response.status === 429) {
      const retryAfter = response.headers.get('Retry-After') || 60;
      await new Promise(r => setTimeout(r, Number(retryAfter) * 1000));
      continue;
    }

    return response;
  }
  throw new Error('Max retries exceeded');
}

Get Started

  1. Sign up at crawlforge.dev/signup
  2. Get your API key (1,000 free credits)
  3. Install LangChain JS and start building

Need help? Check our API documentation or reach out on GitHub.

Try this yourself — no signup needed

Run any of CrawlForge's 27 scraping and extraction tools in the playground, then start free with 1,000 credits.

1,000 free credits • Refills monthly • No credit card required

Tags

LangChainTutorialAI EngineeringRAGPython

About the Author

C

CrawlForge Team

Engineering Team

Building the most comprehensive web scraping MCP server. We create tools that help developers extract, analyze, and transform web data for AI applications.

Stay updated with the latest insights

Get tutorials, product updates, and web scraping tips delivered to your inbox.

No spam. Unsubscribe anytime.

Put this into practice

Test CrawlForge's tools on any URL — free, no signup.

On this page

Frequently Asked Questions

How do I use CrawlForge with LangChain?+

Install LangChain and the Anthropic SDK, set your CRAWLFORGE_API_KEY environment variable, and call CrawlForge tools (extract_content, deep_research, search_web) from inside LangChain chains or agents. The post walks through five integration patterns including web-augmented RAG, research agents with tool calling, and real-time monitoring chains.

Can I build a web-augmented RAG pipeline with CrawlForge and LangChain?+

Yes. Use CrawlForge's extract_content tool to fetch URLs (2 credits each), split the content with LangChain's RecursiveCharacterTextSplitter, embed the chunks into a vector store like MemoryVectorStore, and retrieve the relevant chunks at query time. This keeps your RAG system answering questions about current events, updated docs, and live pricing instead of relying on stale training data.

How do I expose CrawlForge as a LangChain tool for agents?+

Wrap each CrawlForge endpoint as a LangChain `DynamicStructuredTool` with a Zod schema for the input. The agent picks the right tool (search_web, extract_content, deep_research) based on the user query and runs them through CrawlForge's API. The post shows full code for a research agent that chains search and content extraction.

What does CrawlForge cost when used inside LangChain workflows?+

Pricing is per-tool: extract_content is 2 credits, search_web is 5 credits, deep_research is 10 credits. The free tier includes 1,000 credits, enough to fetch ~500 pages or run ~100 search-and-extract workflows. Paid plans start at $19/month for 5,000 credits.

Related Articles

LlamaIndex Web Scraping Guide with CrawlForge MCP
Tutorials

LlamaIndex Web Scraping Guide with CrawlForge MCP

Feed LlamaIndex with live web data. Use CrawlForge as a LlamaIndex reader for RAG pipelines, agent tools, and real-time LLM knowledge bases.

C
CrawlForge Team
|
Apr 14
|
11m
How to Install CrawlForge MCP and Use It in Claude Code: A Beginner's Guide
Tutorials

How to Install CrawlForge MCP and Use It in Claude Code: A Beginner's Guide

Step-by-step tutorial for installing CrawlForge MCP via npm and configuring it in Claude Code. A beginner-friendly guide to adding web scraping tools.

C
CrawlForge Team
|
Jan 10
|
10m
How to Build a Web-Scraping MCP Server in TypeScript (2026)
Tutorials

How to Build a Web-Scraping MCP Server in TypeScript (2026)

Build a working web-scraping MCP server in TypeScript with the official SDK: a minimal server, a real cheerio scraping tool, testing, and Claude Desktop setup.

C
CrawlForge Team
|
Jun 16
|
12m

Footer

CrawlForge

Enterprise web scraping for AI Agents. 27 specialized MCP tools designed for modern developers building intelligent systems.

Product

  • Features
  • Playground
  • Pricing
  • Use Cases
  • Integrations
  • Alternatives
  • Changelog

Resources

  • Getting Started
  • API Reference
  • Templates
  • Guides
  • Blog
  • Glossary
  • FAQ
  • Sitemap

Developers

  • MCP Protocol
  • Claude Desktop
  • Cursor IDE
  • LangChain
  • LlamaIndex

Company

  • About
  • Contact
  • Privacy
  • Terms
  • Acceptable Use
  • Cookies

Stay updated

Get the latest updates on new tools and features.

Built with Next.js and MCP protocol

© 2025-2026 CrawlForge. All rights reserved.