Prerequisites#
- Laravel 10+ project
- A Firecrawl API key — get one free
Configuration#
Add your API key to .env:
FIRECRAWL_API_KEY=fc-YOUR-API-KEYAdd the config entry to config/services.php:
'firecrawl' => [ 'api_key' => env('FIRECRAWL_API_KEY'), 'base_url' => env('FIRECRAWL_API_URL', 'https://api.firecrawl.dev/v2'),],Create a service class#
Create app/Services/FirecrawlService.php:
<?phpnamespace App\Services;use Illuminate\Support\Facades\Http;class FirecrawlService{ private string $apiKey; private string $baseUrl; public function __construct() { $this->apiKey = config('services.firecrawl.api_key'); $this->baseUrl = config('services.firecrawl.base_url'); } public function search(string $query, int $limit = 5): array { $response = Http::withToken($this->apiKey) ->post("{$this->baseUrl}/search", [ 'query' => $query, 'limit' => $limit, ]); return $response->json(); } public function scrape(string $url, array $options = []): array { $response = Http::withToken($this->apiKey) ->post("{$this->baseUrl}/scrape", array_merge(['url' => $url], $options)); return $response->json(); } public function interact(string $url, string $prompt, ?string $followUp = null): array { // 1. Scrape to open a browser session $scrapeResult = $this->scrape($url, ['formats' => ['markdown']]); $scrapeId = $scrapeResult['data']['metadata']['scrapeId']; // 2. Send first prompt Http::withToken($this->apiKey) ->post("{$this->baseUrl}/scrape/{$scrapeId}/interact", [ 'prompt' => $prompt, ]); // 3. Send follow-up prompt $result = null; if ($followUp) { $result = Http::withToken($this->apiKey) ->post("{$this->baseUrl}/scrape/{$scrapeId}/interact", [ 'prompt' => $followUp, ])->json(); } // 4. Close the session Http::withToken($this->apiKey) ->delete("{$this->baseUrl}/scrape/{$scrapeId}/interact"); return $result ?? $scrapeResult; }}Create a controller#
Create app/Http/Controllers/FirecrawlController.php:
<?phpnamespace App\Http\Controllers;use App\Services\FirecrawlService;use Illuminate\Http\Request;class FirecrawlController extends Controller{ public function __construct(private FirecrawlService $firecrawl) {} public function search(Request $request) { $validated = $request->validate(['query' => 'required|string']); return response()->json( $this->firecrawl->search($validated['query'], $request->input('limit', 5)) ); } public function scrape(Request $request) { $validated = $request->validate(['url' => 'required|url']); return response()->json($this->firecrawl->scrape($validated['url'])); } public function interact(Request $request) { $validated = $request->validate([ 'url' => 'required|url', 'prompt' => 'required|string', ]); return response()->json( $this->firecrawl->interact( $validated['url'], $validated['prompt'], $request->input('followUp') ) ); }}Register routes#
In routes/api.php:
use App\Http\Controllers\FirecrawlController;Route::post('/search', [FirecrawlController::class, 'search']);Route::post('/scrape', [FirecrawlController::class, 'scrape']);Route::post('/interact', [FirecrawlController::class, 'interact']);Test it#
php artisan serve# Search the webcurl -X POST http://localhost:8000/api/search \ -H "Content-Type: application/json" \ -d '{"query": "firecrawl web scraping"}'# Scrape a pagecurl -X POST http://localhost:8000/api/scrape \ -H "Content-Type: application/json" \ -d '{"url": "https://example.com"}'# Interact with a pagecurl -X POST http://localhost:8000/api/interact \ -H "Content-Type: application/json" \ -d '{"url": "https://www.amazon.com", "prompt": "Search for iPhone 16 Pro Max", "followUp": "Click on the first result and tell me the price"}'
