
Company News
Socket Joins New OpenJS Program to Fund Node.js Security Work
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.
TypeScript SDK for the Deepcrawl API - Web scraping and crawling with comprehensive error handling.
npm install deepcrawl
# or
yarn add deepcrawl
# or
pnpm add deepcrawl
Zod v4 ships with the SDK as a runtime dependency and is mirrored as a peer dependency. If your app already provides Zod ≥4.1, your package manager will dedupe it; otherwise, the bundled copy means no extra install step.
import { DeepcrawlApp } from 'deepcrawl';
const deepcrawl = new DeepcrawlApp({
apiKey: process.env.DEEPCRAWL_API_KEY
});
const result = await deepcrawl.readUrl('https://example.com');
console.log(result.markdown);
The SDK uses dedicated export paths for better tree-shaking and organization:
import { DeepcrawlApp } from 'deepcrawl';
import type {
// Configuration
DeepcrawlConfig,
// API Types
ReadUrlOptions,
ReadUrlResponse,
GetMarkdownOptions,
GetMarkdownResponse,
ExtractLinksOptions,
ExtractLinksResponse,
GetLinksOptions,
GetLinksResponse,
// Activity Logs
ActivityLogEntry,
ListLogsOptions,
ListLogsResponse,
GetOneLogOptions,
// Metadata & Metrics
Metadata,
MetricsOptions,
Metrics,
// Links
LinksTree,
LinkItem,
SocialMediaLink,
// Errors
DeepcrawlError,
DeepcrawlReadError,
DeepcrawlLinksError,
DeepcrawlRateLimitError,
DeepcrawlAuthError,
DeepcrawlValidationError,
DeepcrawlNotFoundError,
DeepcrawlServerError,
DeepcrawlNetworkError,
} from 'deepcrawl/types';
import {
z,
// Request Schemas
ReadUrlOptionsSchema,
GetMarkdownOptionsSchema,
ExtractLinksOptionsSchema,
GetLinksOptionsSchema,
ListLogsOptionsSchema,
GetOneLogOptionsSchema,
// Response Schemas
ReadUrlResponseSchema,
GetMarkdownResponseSchema,
ExtractLinksResponseSchema,
GetLinksResponseSchema,
ListLogsResponseSchema,
// Metadata & Metrics
MetadataSchema,
MetricsOptionsSchema,
MetricsSchema,
// Links
LinksTreeSchema,
// services
CacheOptionsSchema
} from 'deepcrawl/schemas';
Importing
zfromdeepcrawl/zod/v4(or fromdeepcrawl/schemas) reuses the SDK's Zod runtime so schema composition works even if your app already has its own Zod installation.
import { z } from 'deepcrawl/zod/v4';
import { ReadUrlOptionsSchema } from 'deepcrawl/schemas';
const CustomSchema = ReadUrlOptionsSchema.extend({
customFlag: z.boolean().default(false),
});
Use this helper when you want to compose Zod schemas with the SDK’s public schemas or utils to avoid instance mismatch issues in projects that install multiple copies of Zod.
import {
// Zod schema helper
OptionalBoolWithDefault,
// Pagination normalization
normalizeListLogsPagination
} from 'deepcrawl/types/utils';
// Example: Create optional boolean schema with default
const schema = OptionalBoolWithDefault(true);
// Example: Normalize pagination input
const normalized = normalizeListLogsPagination({ limit: 150, offset: -5 });
// Returns: { limit: 100, offset: 0 } (clamped to valid ranges)
Extract clean content and metadata from any URL.
import { DeepcrawlApp } from 'deepcrawl';
import type { ReadUrlOptions } from 'deepcrawl/types';
const deepcrawl = new DeepcrawlApp({ apiKey: process.env.DEEPCRAWL_API_KEY });
const result = await deepcrawl.readUrl('https://example.com', {
metadata: true,
markdown: true,
cleanedHtml: true,
metricsOptions: { enabled: true }
});
console.log(result.markdown);
console.log(result.metadata?.title);
console.log(result.metrics?.readableDuration);
Simplified method to get just markdown content.
import { DeepcrawlApp } from 'deepcrawl';
const deepcrawl = new DeepcrawlApp({ apiKey: process.env.DEEPCRAWL_API_KEY });
const result = await deepcrawl.getMarkdown('https://example.com', {
metricsOptions: { enable: true }
});
console.log(result.markdown);
Extract all links from a page with powerful filtering options.
import { DeepcrawlApp } from 'deepcrawl';
import type { ExtractLinksOptions } from 'deepcrawl/types';
const deepcrawl = new DeepcrawlApp({ apiKey: process.env.DEEPCRAWL_API_KEY });
const result = await deepcrawl.extractLinks('https://example.com', {
includeInternal: true,
includeExternal: false,
includeEmails: false,
includePhoneNumbers: false,
includeSocialMedia: false,
metricsOptions: { enable: true }
});
console.log(result.tree.internal);
console.log(result.tree.socialMedia);
Retrieve activity logs with paginated results and filtering.
import { DeepcrawlApp } from 'deepcrawl';
import type { ListLogsOptions } from 'deepcrawl/types';
const deepcrawl = new DeepcrawlApp({ apiKey: process.env.DEEPCRAWL_API_KEY });
const result = await deepcrawl.listLogs({
limit: 50,
offset: 0,
path: 'read-getMarkdown',
success: true,
startDate: '2025-01-01T00:00:00Z',
endDate: '2025-12-31T23:59:59Z',
orderBy: 'requestTimestamp',
orderDir: 'desc'
});
console.log(result.logs);
console.log(result.meta.hasMore);
Get a single activity log entry by ID.
import { DeepcrawlApp } from 'deepcrawl';
import type { GetOneLogOptions } from 'deepcrawl/types';
const deepcrawl = new DeepcrawlApp({ apiKey: process.env.DEEPCRAWL_API_KEY });
const log = await deepcrawl.getOneLog({ id: 'request-id-123' });
console.log(log.path);
console.log(log.response);
import { DeepcrawlApp } from 'deepcrawl';
import type { ReadUrlOptions } from 'deepcrawl/types';
const deepcrawl = new DeepcrawlApp({ apiKey: process.env.DEEPCRAWL_API_KEY });
async function monitorProduct(productUrl: string) {
try {
const result = await deepcrawl.readUrl(productUrl, {
metadata: true,
cleanedHtml: true
});
return {
title: result.metadata?.title,
lastChecked: new Date().toISOString()
};
} catch (error) {
if (error.isRateLimit?.()) {
console.log(`Rate limited. Retry after ${error.retryAfter}s`);
await new Promise(r => setTimeout(r, error.retryAfter * 1000));
return monitorProduct(productUrl);
}
throw error;
}
}
import { DeepcrawlApp } from 'deepcrawl';
import type { ReadUrlResponse } from 'deepcrawl/types';
const deepcrawl = new DeepcrawlApp({ apiKey: process.env.DEEPCRAWL_API_KEY });
async function aggregateArticles(urls: string[]) {
const results = await Promise.allSettled(
urls.map(url => deepcrawl.readUrl(url, {
metadata: true,
markdown: true
}))
);
return results.map((result, index) => ({
url: urls[index],
success: result.status === 'fulfilled',
data: result.status === 'fulfilled' ? result.value : null,
error: result.status === 'rejected' ? result.reason.message : null
}));
}
// app/actions/scrape.ts
'use server'
import { DeepcrawlApp } from 'deepcrawl';
import { headers } from 'next/headers';
import { revalidatePath } from 'next/cache';
export async function scrapeUrlAction(url: string) {
const deepcrawl = new DeepcrawlApp({
apiKey: process.env.DEEPCRAWL_API_KEY,
headers: await headers(),
});
try {
const result = await deepcrawl.readUrl(url, {
metadata: true,
markdown: true,
});
revalidatePath('/dashboard');
return {
success: true,
data: {
title: result.metadata?.title,
content: result.markdown,
}
};
} catch (error) {
return {
success: false,
error: {
message: error.message,
retryable: error.isRateLimit?.() || error.isNetwork?.(),
}
};
}
}
import { useState, useCallback } from 'react';
import { DeepcrawlApp } from 'deepcrawl';
import type { ReadUrlResponse } from 'deepcrawl/types';
export function useScraping(apiKey: string) {
const [data, setData] = useState<ReadUrlResponse | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const deepcrawl = new DeepcrawlApp({ apiKey });
const scrape = useCallback(async (url: string) => {
setLoading(true);
setError(null);
try {
const result = await deepcrawl.readUrl(url, { metadata: true });
setData(result);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}, [deepcrawl]);
return { data, loading, error, scrape };
}
// app/actions/logs.ts
'use server';
import { DeepcrawlApp } from 'deepcrawl';
import type { ListLogsResponse } from 'deepcrawl/types';
const deepcrawl = new DeepcrawlApp({ apiKey: process.env.DEEPCRAWL_API_KEY });
export async function getActivityLogs() {
try {
const logs = await deepcrawl.listLogs({
limit: 50,
offset: 0
});
return { success: true, data: logs };
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to fetch logs'
};
}
}
import type {
DeepcrawlError,
DeepcrawlReadError,
DeepcrawlLinksError,
DeepcrawlRateLimitError,
DeepcrawlAuthError,
DeepcrawlValidationError,
DeepcrawlNotFoundError,
DeepcrawlServerError,
DeepcrawlNetworkError,
} from 'deepcrawl/types';
import { DeepcrawlApp } from 'deepcrawl';
const deepcrawl = new DeepcrawlApp({ apiKey: process.env.DEEPCRAWL_API_KEY });
try {
const result = await deepcrawl.readUrl(url);
} catch (error) {
if (error.isRateLimit?.()) {
console.log(`Retry after ${error.retryAfter}s`);
} else if (error.isRead?.()) {
console.log(`Failed to read: ${error.message}`);
}
}
import { DeepcrawlApp } from 'deepcrawl';
const deepcrawl = new DeepcrawlApp({ apiKey: process.env.DEEPCRAWL_API_KEY });
try {
const result = await deepcrawl.readUrl(url);
} catch (error) {
// Check error type using instance methods
if (error.isAuth?.()) {
console.log('Authentication failed');
} else if (error.isValidation?.()) {
console.log('Invalid request parameters');
}
}
All errors include:
code: string - oRPC error codestatus: number - HTTP statusmessage: string - User-friendly error messagedata: any - Raw error data from APIRate limit errors include:
retryAfter: number - Seconds to waitoperation: string - What operation was rate limitedRead/Links errors include:
targetUrl: string - URL that failedsuccess: false - Always false for errorsimport { DeepcrawlApp } from 'deepcrawl';
import type { DeepcrawlConfig } from 'deepcrawl/types';
const deepcrawl = new DeepcrawlApp({
apiKey: process.env.DEEPCRAWL_API_KEY,
baseUrl: "https://api.deepcrawl.dev",
headers: {
'User-Agent': 'MyApp/1.0'
},
fetch: customFetch,
fetchOptions: {
timeout: 30000
}
});
Automatic HTTP connection pooling in Node.js:
// Automatic configuration
{
keepAlive: true,
maxSockets: 10,
maxFreeSockets: 5,
timeout: 60000,
keepAliveMsecs: 30000
}
Benefits:
// ✅ SECURE: lib/deepcrawl.ts
'use server';
import { DeepcrawlApp } from 'deepcrawl';
export const deepcrawlClient = new DeepcrawlApp({
apiKey: process.env.DEEPCRAWL_API_KEY
});
// ✅ SECURE: app/actions/scrape.ts
'use server';
import { deepcrawlClient } from '@/lib/deepcrawl';
export async function scrapeAction(url: string) {
return deepcrawlClient.readUrl(url);
}
// ✅ SECURE: Client component
'use client';
import { scrapeAction } from '@/app/actions/scrape';
export function ScrapeButton() {
const handleClick = async () => {
const result = await scrapeAction('https://example.com');
console.log(result);
};
return <button onClick={handleClick}>Scrape</button>;
}
// ❌ INSECURE: Direct SDK usage in client components
'use client';
import { DeepcrawlApp } from 'deepcrawl';
export function BadComponent() {
const deepcrawl = new DeepcrawlApp({
apiKey: process.env.DEEPCRAWL_API_KEY // ❌ Exposes API key!
});
}
⚠️ Server-Side Only: The Deepcrawl SDK is designed for server-side use:
MIT - see LICENSE for details.
Built with ❤️ by the @felixLu
FAQs
JavaScript/TypeScript SDK for Deepcrawl API
The npm package deepcrawl receives a total of 98 weekly downloads. As such, deepcrawl popularity was classified as not popular.
We found that deepcrawl demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Company News
Socket is joining the OpenJS Security Stewardship Program to fund Node.js vulnerability research, maintainer remediation, and security releases.

Security News
Two compromised GitHub Actions were re-enabled with malicious tags intact, exposing thousands of downstream repositories to Mini Shai-Hulud.

Research
/Security News
A malicious Firefox extension fetches its payload after installation to evade detection, steal Google session cookies, and automate account takeover.