or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

batch.mdcrawling.mdextraction.mdindex.mdmapping.mdmonitoring.mdscraping.mdsearch.mdusage.mdv1-api.md

v1-api.mddocs/

0

# Legacy V1 API

1

2

Feature-frozen v1 API with additional capabilities including deep research, LLMs.txt generation, and WebSocket monitoring.

3

4

## Accessing V1 API

5

6

```typescript

7

// Access v1 client through unified client

8

const app = new Firecrawl({ apiKey: 'your-api-key' });

9

const v1Client = app.v1;

10

11

// Or instantiate v1 client directly

12

import { FirecrawlAppV1 } from '@mendable/firecrawl-js';

13

const v1Client = new FirecrawlAppV1({ apiKey: 'your-api-key' });

14

```

15

16

## V1 Client Configuration

17

18

```typescript { .api }

19

interface FirecrawlAppConfig {

20

apiKey?: string | null;

21

apiUrl?: string | null;

22

}

23

24

class FirecrawlApp {

25

constructor(config: FirecrawlAppConfig);

26

}

27

```

28

29

## Core V1 Methods

30

31

### Scraping

32

33

```typescript { .api }

34

/**

35

* Scrape a single URL with v1 API

36

* @param url - URL to scrape

37

* @param params - V1 scraping parameters

38

* @returns Promise resolving to scrape response

39

*/

40

scrapeUrl<T extends ZodSchema, ActionsSchema extends Action[] | undefined>(

41

url: string,

42

params?: ScrapeParams<T, ActionsSchema>

43

): Promise<ScrapeResponse<infer<T>, ActionsSchema extends Action[] ? ActionsResult : never> | ErrorResponse>;

44

```

45

46

### Search

47

48

```typescript { .api }

49

/**

50

* Search using v1 API

51

* @param query - Search query

52

* @param params - V1 search parameters

53

* @returns Promise resolving to search results

54

*/

55

search(query: string, params?: SearchParams): Promise<SearchResponse>;

56

```

57

58

### Crawling

59

60

```typescript { .api }

61

/**

62

* Crawl URL with v1 API (with polling)

63

* @param url - URL to crawl

64

* @param params - V1 crawl parameters

65

* @param pollInterval - Polling interval in seconds

66

* @param idempotencyKey - Optional idempotency key

67

* @returns Promise resolving to crawl status

68

*/

69

crawlUrl(

70

url: string,

71

params?: CrawlParams,

72

pollInterval?: number,

73

idempotencyKey?: string

74

): Promise<CrawlStatusResponse | ErrorResponse>;

75

76

/**

77

* Start async crawl without polling

78

* @param url - URL to crawl

79

* @param params - V1 crawl parameters

80

* @param idempotencyKey - Optional idempotency key

81

* @returns Promise resolving to crawl initiation response

82

*/

83

asyncCrawlUrl(

84

url: string,

85

params?: CrawlParams,

86

idempotencyKey?: string

87

): Promise<CrawlResponse | ErrorResponse>;

88

89

/**

90

* Check crawl status

91

* @param id - Crawl job ID

92

* @param getAllData - Get all pages of data

93

* @param nextURL - Next URL for pagination

94

* @param skip - Skip entries for pagination

95

* @param limit - Limit entries returned

96

* @returns Promise resolving to crawl status

97

*/

98

checkCrawlStatus(

99

id?: string,

100

getAllData?: boolean,

101

nextURL?: string,

102

skip?: number,

103

limit?: number

104

): Promise<CrawlStatusResponse | ErrorResponse>;

105

106

/**

107

* Cancel crawl job

108

* @param id - Crawl job ID

109

* @returns Promise resolving to cancellation response

110

*/

111

cancelCrawl(id: string): Promise<ErrorResponse>;

112

113

/**

114

* Get crawl errors

115

* @param id - Crawl job ID

116

* @returns Promise resolving to error information

117

*/

118

checkCrawlErrors(id: string): Promise<CrawlErrorsResponse | ErrorResponse>;

119

120

/**

121

* Crawl with WebSocket monitoring

122

* @param url - URL to crawl

123

* @param params - V1 crawl parameters

124

* @param idempotencyKey - Optional idempotency key

125

* @returns Promise resolving to CrawlWatcher instance

126

*/

127

crawlUrlAndWatch(

128

url: string,

129

params?: CrawlParams,

130

idempotencyKey?: string

131

): Promise<CrawlWatcher>;

132

```

133

134

### Batch Operations

135

136

```typescript { .api }

137

/**

138

* Batch scrape URLs with v1 API (with polling)

139

* @param urls - URLs to scrape

140

* @param params - V1 scrape parameters

141

* @param pollInterval - Polling interval in seconds

142

* @param idempotencyKey - Optional idempotency key

143

* @param webhook - Optional webhook configuration

144

* @param ignoreInvalidURLs - Ignore invalid URLs

145

* @param maxConcurrency - Maximum concurrent requests

146

* @returns Promise resolving to batch status

147

*/

148

batchScrapeUrls(

149

urls: string[],

150

params?: ScrapeParams,

151

pollInterval?: number,

152

idempotencyKey?: string,

153

webhook?: CrawlParams["webhook"],

154

ignoreInvalidURLs?: boolean,

155

maxConcurrency?: number

156

): Promise<BatchScrapeStatusResponse | ErrorResponse>;

157

158

/**

159

* Start async batch scrape without polling

160

* @param urls - URLs to scrape

161

* @param params - V1 scrape parameters

162

* @param idempotencyKey - Optional idempotency key

163

* @param webhook - Optional webhook configuration

164

* @param ignoreInvalidURLs - Ignore invalid URLs

165

* @returns Promise resolving to batch initiation response

166

*/

167

asyncBatchScrapeUrls(

168

urls: string[],

169

params?: ScrapeParams,

170

idempotencyKey?: string,

171

webhook?: CrawlParams["webhook"],

172

ignoreInvalidURLs?: boolean

173

): Promise<BatchScrapeResponse | ErrorResponse>;

174

175

/**

176

* Check batch scrape status

177

* @param id - Batch job ID

178

* @param getAllData - Get all pages of data

179

* @param nextURL - Next URL for pagination

180

* @param skip - Skip entries for pagination

181

* @param limit - Limit entries returned

182

* @returns Promise resolving to batch status

183

*/

184

checkBatchScrapeStatus(

185

id?: string,

186

getAllData?: boolean,

187

nextURL?: string,

188

skip?: number,

189

limit?: number

190

): Promise<BatchScrapeStatusResponse | ErrorResponse>;

191

192

/**

193

* Get batch scrape errors

194

* @param id - Batch job ID

195

* @returns Promise resolving to error information

196

*/

197

checkBatchScrapeErrors(id: string): Promise<CrawlErrorsResponse | ErrorResponse>;

198

199

/**

200

* Batch scrape with WebSocket monitoring

201

* @param urls - URLs to scrape

202

* @param params - V1 scrape parameters

203

* @param idempotencyKey - Optional idempotency key

204

* @param webhook - Optional webhook configuration

205

* @param ignoreInvalidURLs - Ignore invalid URLs

206

* @returns Promise resolving to CrawlWatcher instance

207

*/

208

batchScrapeUrlsAndWatch(

209

urls: string[],

210

params?: ScrapeParams,

211

idempotencyKey?: string,

212

webhook?: CrawlParams["webhook"],

213

ignoreInvalidURLs?: boolean

214

): Promise<CrawlWatcher>;

215

```

216

217

### Data Extraction

218

219

```typescript { .api }

220

/**

221

* Extract data with v1 API (with polling)

222

* @param urls - URLs to extract from

223

* @param params - V1 extraction parameters

224

* @returns Promise resolving to extraction results

225

*/

226

extract<T extends ZodSchema>(

227

urls?: string[],

228

params?: ExtractParams<T>

229

): Promise<ExtractResponse<infer<T>> | ErrorResponse>;

230

231

/**

232

* Start async extraction without polling

233

* @param urls - URLs to extract from

234

* @param params - V1 extraction parameters

235

* @param idempotencyKey - Optional idempotency key

236

* @returns Promise resolving to extraction initiation response

237

*/

238

asyncExtract(

239

urls: string[],

240

params?: ExtractParams,

241

idempotencyKey?: string

242

): Promise<ExtractResponse | ErrorResponse>;

243

244

/**

245

* Get extraction status

246

* @param jobId - Extraction job ID

247

* @returns Promise resolving to extraction status

248

*/

249

getExtractStatus(jobId: string): Promise<any>;

250

```

251

252

### Site Mapping

253

254

```typescript { .api }

255

/**

256

* Map URLs with v1 API

257

* @param url - URL to map

258

* @param params - V1 mapping parameters

259

* @returns Promise resolving to mapping results

260

*/

261

mapUrl(url: string, params?: MapParams): Promise<MapResponse | ErrorResponse>;

262

```

263

264

## V1 Exclusive Features

265

266

### Deep Research

267

268

```typescript { .api }

269

/**

270

* Perform deep research with v1 API (with polling)

271

* @param query - Research query

272

* @param params - Deep research parameters

273

* @param onActivity - Activity callback

274

* @param onSource - Source callback

275

* @returns Promise resolving to research results

276

*/

277

deepResearch(

278

query: string,

279

params: DeepResearchParams<ZodSchema>,

280

onActivity?: (activity: {

281

type: string;

282

status: string;

283

message: string;

284

timestamp: string;

285

depth: number;

286

}) => void,

287

onSource?: (source: {

288

url: string;

289

title?: string;

290

description?: string;

291

icon?: string;

292

}) => void

293

): Promise<DeepResearchStatusResponse | ErrorResponse>;

294

295

/**

296

* Start async deep research without polling

297

* @param query - Research query

298

* @param params - Deep research parameters

299

* @returns Promise resolving to research initiation response

300

*/

301

asyncDeepResearch(

302

query: string,

303

params: DeepResearchParams<ZodSchema>

304

): Promise<DeepResearchResponse | ErrorResponse>;

305

306

/**

307

* Check deep research status

308

* @param id - Research job ID

309

* @returns Promise resolving to research status

310

*/

311

checkDeepResearchStatus(id: string): Promise<DeepResearchStatusResponse | ErrorResponse>;

312

```

313

314

### LLMs.txt Generation

315

316

```typescript { .api }

317

/**

318

* Generate LLMs.txt with v1 API (with polling)

319

* @param url - URL to generate LLMs.txt from

320

* @param params - Generation parameters

321

* @returns Promise resolving to generation results

322

*/

323

generateLLMsText(

324

url: string,

325

params?: GenerateLLMsTextParams

326

): Promise<GenerateLLMsTextStatusResponse | ErrorResponse>;

327

328

/**

329

* Start async LLMs.txt generation without polling

330

* @param url - URL to generate LLMs.txt from

331

* @param params - Generation parameters

332

* @returns Promise resolving to generation initiation response

333

*/

334

asyncGenerateLLMsText(

335

url: string,

336

params?: GenerateLLMsTextParams

337

): Promise<GenerateLLMsTextResponse | ErrorResponse>;

338

339

/**

340

* Check LLMs.txt generation status

341

* @param id - Generation job ID

342

* @returns Promise resolving to generation status

343

*/

344

checkGenerateLLMsTextStatus(id: string): Promise<GenerateLLMsTextStatusResponse | ErrorResponse>;

345

```

346

347

## V1 Configuration Types

348

349

```typescript { .api }

350

// V1 scrape parameters

351

interface ScrapeParams<LLMSchema extends ZodSchema, ActionsSchema extends Action[] | undefined> {

352

formats?: string[];

353

headers?: Record<string, string>;

354

includeTags?: string[];

355

excludeTags?: string[];

356

onlyMainContent?: boolean;

357

waitFor?: number;

358

timeout?: number;

359

location?: LocationConfig;

360

mobile?: boolean;

361

skipTlsVerification?: boolean;

362

removeBase64Images?: boolean;

363

blockAds?: boolean;

364

proxy?: "basic" | "stealth" | "auto";

365

storeInCache?: boolean;

366

maxAge?: number;

367

parsePDF?: boolean;

368

extract?: {

369

prompt?: string;

370

schema?: LLMSchema;

371

systemPrompt?: string;

372

};

373

jsonOptions?: {

374

prompt?: string;

375

schema?: LLMSchema;

376

systemPrompt?: string;

377

};

378

changeTrackingOptions?: {

379

prompt?: string;

380

schema?: any;

381

modes?: ("json" | "git-diff")[];

382

tag?: string | null;

383

};

384

actions?: ActionsSchema;

385

agent?: AgentOptions;

386

zeroDataRetention?: boolean;

387

}

388

389

// V1 crawl parameters

390

interface CrawlParams {

391

includePaths?: string[];

392

excludePaths?: string[];

393

maxDepth?: number;

394

maxDiscoveryDepth?: number;

395

limit?: number;

396

allowBackwardLinks?: boolean;

397

crawlEntireDomain?: boolean;

398

allowExternalLinks?: boolean;

399

ignoreSitemap?: boolean;

400

scrapeOptions?: CrawlScrapeOptions;

401

webhook?: string | {

402

url: string;

403

headers?: Record<string, string>;

404

metadata?: Record<string, string>;

405

events?: ("completed" | "failed" | "page" | "started")[];

406

};

407

deduplicateSimilarURLs?: boolean;

408

ignoreQueryParameters?: boolean;

409

regexOnFullURL?: boolean;

410

delay?: number;

411

allowSubdomains?: boolean;

412

maxConcurrency?: number;

413

zeroDataRetention?: boolean;

414

}

415

416

// Deep research parameters

417

interface DeepResearchParams<LLMSchema extends ZodSchema> {

418

maxDepth?: number; // 1-10, default 7

419

timeLimit?: number; // 30-300 seconds, default 270

420

maxUrls?: number; // 1-1000, default 20

421

analysisPrompt?: string;

422

systemPrompt?: string;

423

formats?: ("markdown" | "json")[];

424

jsonOptions?: {

425

prompt?: string;

426

schema?: LLMSchema;

427

systemPrompt?: string;

428

};

429

}

430

431

// LLMs.txt generation parameters

432

interface GenerateLLMsTextParams {

433

maxUrls?: number; // 1-100, default 10

434

showFullText?: boolean; // default false

435

cache?: boolean; // default true

436

__experimental_stream?: boolean;

437

}

438

```

439

440

## V1 WebSocket Monitoring

441

442

```typescript { .api }

443

/**

444

* V1 WebSocket-based job watcher

445

*/

446

class CrawlWatcher extends TypedEventTarget<CrawlWatcherEvents> {

447

constructor(id: string, app: FirecrawlApp);

448

449

// Event listeners

450

on(event: 'document', listener: (e: CustomEvent<FirecrawlDocument>) => void): void;

451

on(event: 'done', listener: (e: CustomEvent<{

452

status: string;

453

data: FirecrawlDocument[];

454

}>) => void): void;

455

on(event: 'error', listener: (e: CustomEvent<{

456

status: string;

457

data: FirecrawlDocument[];

458

error: string;

459

}>) => void): void;

460

461

close(): void;

462

}

463

```

464

465

## Usage Examples

466

467

### V1 Deep Research

468

469

```typescript

470

const v1Client = app.v1;

471

472

// Perform comprehensive research with real-time updates

473

const researchResult = await v1Client.deepResearch(

474

'artificial intelligence safety research 2024',

475

{

476

maxDepth: 5,

477

timeLimit: 180, // 3 minutes

478

maxUrls: 30,

479

analysisPrompt: 'Analyze the current state of AI safety research, key developments, and future challenges',

480

formats: ['markdown', 'json'],

481

jsonOptions: {

482

schema: {

483

type: 'object',

484

properties: {

485

keyFindings: { type: 'array', items: { type: 'string' } },

486

researchers: { type: 'array', items: { type: 'string' } },

487

developments: { type: 'array', items: { type: 'object' } },

488

challenges: { type: 'array', items: { type: 'string' } },

489

recommendations: { type: 'array', items: { type: 'string' } }

490

}

491

}

492

}

493

},

494

// Activity callback

495

(activity) => {

496

console.log(`Research activity: ${activity.message} (depth: ${activity.depth})`);

497

},

498

// Source callback

499

(source) => {

500

console.log(`Found source: ${source.title} - ${source.url}`);

501

}

502

);

503

504

console.log('Research completed:', researchResult.data);

505

```

506

507

### V1 LLMs.txt Generation

508

509

```typescript

510

const v1Client = app.v1;

511

512

// Generate LLMs.txt for a website

513

const llmsResult = await v1Client.generateLLMsText('https://docs.example.com', {

514

maxUrls: 50,

515

showFullText: true,

516

cache: true

517

});

518

519

console.log('LLMs.txt generated:');

520

console.log(llmsResult.data.llmstxt);

521

522

if (llmsResult.data.llmsfulltxt) {

523

console.log('\nFull text version available');

524

}

525

```

526

527

### V1 Advanced Scraping with Actions

528

529

```typescript

530

const v1Client = app.v1;

531

532

// Scrape with browser automation

533

const scrapeResult = await v1Client.scrapeUrl('https://app.example.com', {

534

formats: ['markdown', 'json'],

535

actions: [

536

{ type: 'wait', selector: '#content' },

537

{ type: 'click', selector: '.load-more-button' },

538

{ type: 'wait', milliseconds: 3000 },

539

{ type: 'screenshot', fullPage: true },

540

{ type: 'scrape' }

541

],

542

jsonOptions: {

543

prompt: 'Extract product information including names, prices, and descriptions',

544

schema: {

545

type: 'object',

546

properties: {

547

products: {

548

type: 'array',

549

items: {

550

type: 'object',

551

properties: {

552

name: { type: 'string' },

553

price: { type: 'number' },

554

description: { type: 'string' }

555

}

556

}

557

}

558

}

559

}

560

}

561

});

562

563

console.log('Scraped data:', scrapeResult.data);

564

console.log('Actions performed:', scrapeResult.actions);

565

```

566

567

### V1 Crawl with WebSocket Monitoring

568

569

```typescript

570

const v1Client = app.v1;

571

572

// Start crawl with WebSocket monitoring

573

const watcher = await v1Client.crawlUrlAndWatch('https://example.com', {

574

limit: 100,

575

scrapeOptions: {

576

formats: ['markdown'],

577

onlyMainContent: true

578

}

579

});

580

581

// Listen for real-time updates

582

watcher.addEventListener('document', (event) => {

583

const document = event.detail;

584

console.log(`New document: ${document.url}`);

585

});

586

587

watcher.addEventListener('done', (event) => {

588

const { status, data } = event.detail;

589

console.log(`Crawl ${status}! Got ${data.length} documents`);

590

watcher.close();

591

});

592

593

watcher.addEventListener('error', (event) => {

594

const { error } = event.detail;

595

console.error(`Crawl error: ${error}`);

596

watcher.close();

597

});

598

```

599

600

### V1 Usage Analytics

601

602

```typescript

603

const v1Client = app.v1;

604

605

// Get v1 usage information (different format from v2)

606

const [creditUsage, tokenUsage, queueStatus] = await Promise.all([

607

v1Client.getCreditUsage(),

608

v1Client.getTokenUsage(),

609

v1Client.getQueueStatus()

610

]);

611

612

console.log('V1 Credit Usage:', {

613

remaining: creditUsage.data.remaining_credits,

614

plan: creditUsage.data.plan_credits,

615

billingStart: creditUsage.data.billing_period_start,

616

billingEnd: creditUsage.data.billing_period_end

617

});

618

619

console.log('V1 Token Usage:', {

620

remaining: tokenUsage.data.remaining_tokens,

621

plan: tokenUsage.data.plan_tokens

622

});

623

624

console.log('Queue Status:', queueStatus);

625

```

626

627

## Migration from V1 to V2

628

629

When migrating from v1 to v2 API, note these key differences:

630

631

1. **Naming conventions**: v2 uses camelCase consistently

632

2. **Response formats**: v2 has simplified response structures

633

3. **Type safety**: v2 provides better TypeScript integration

634

4. **Async patterns**: v2 uses modern async/await patterns throughout

635

5. **Missing features**: Deep research and LLMs.txt are v1-only

636

6. **WebSocket handling**: v2 uses EventEmitter-based watchers

637

638

For maximum compatibility, use the unified `Firecrawl` client which provides both APIs.