feat(firecrawl): add Keyless (no-API-key) mode via lightweight HTTP transport - #57151
feat(firecrawl): add Keyless (no-API-key) mode via lightweight HTTP transport#57151luxles wants to merge 1 commit into
Conversation
…ransport Firecrawl launched Keyless mode in June 2026, allowing search and scrape calls without an API key — no account needed, 1,000 credits/month free. The cloud API accepts unauthenticated requests at the same endpoints. The Firecrawl Python SDK unconditionally requires api_key at construction, making it unsuitable for this mode. Rather than forking the SDK or adding a stub key, this PR introduces a thin HTTP client that mirrors the SDK's method signatures so the existing extract loop works unchanged. Changes in plugins/web/firecrawl/provider.py (+56 lines): 1. _KeylessFirecrawlClient — httpx-based transport calling POST /v1/search and POST /v1/scrape. Implements search(query, limit) -> dict and scrape(url, formats) -> dict, matching the SDK surface. 2. _get_firecrawl_client() dispatch — when resolved kwargs contain no api_key (FIRECRAWL_API_URL set without FIRECRAWL_API_KEY), returns a _KeylessFirecrawlClient instead of constructing an SDK client. No changes to _get_direct_firecrawl_config / check_firecrawl_api_key / is_available — all three already accept the FIRECRAWL_API_URL-only config as valid.
Competing with #50659 for issue #49912 (Firecrawl keyless mode). Both add a |
Relationship to #50659This PR and #50659 (by @LeonSGP43) both add a
The ideal resolution combines both triggers in
Minor technical difference: #50659 uses Happy to close this PR in favor of a combined approach if the maintainer prefers. Leaving both open for maintainer pickup. |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for isolating a raw HTTP transport from the keyed SDK path.
Problems
- The added branch only runs after
_get_direct_firecrawl_config()produces URL-only kwargs. On current main, no-key/no-URL returnsNoneatplugins/web/firecrawl/provider.py:130, andcheck_firecrawl_api_key()stays unavailable at line 176. This PR therefore does not reach the no-setup cloud-keyless flow described in issue #49912; it covers only the URL-only case. The discussion correctly identifies #50659 as the complementary explicit-selection path. - The diff has no tests for the new transport or dispatch. Existing URL-only availability coverage is at
tests/tools/test_web_tools_config.py:600-603, but it does not verify construction or HTTP behavior. plugins/web/firecrawl/plugin.yaml:3andprovider.py:605-615still describe URL-only use as self-hosted/paid rather than keyless cloud.
Suggested changes
- Combine the URL-only branch with an explicit Firecrawl-selection keyless path, or explicitly narrow the PR's scope.
- Add transport/selection tests and align setup metadata.
Automated hermes-sweeper review.
| # Keyless mode: when no api_key is provided, use raw HTTP instead of SDK | ||
| # (the Firecrawl SDK requires an api_key, but the cloud API supports | ||
| # unauthenticated requests since Firecrawl Keyless launch, June 2026). | ||
| if "api_key" not in kwargs: |
There was a problem hiding this comment.
This condition is only reachable when _get_direct_firecrawl_config() already returned URL-only kwargs. With no key and no URL, current main returns None at provider.py:130 and raises through the gateway path, so this does not implement no-setup keyless cloud use. Please combine this with the explicit Firecrawl-selection trigger discussed for #50659, or narrow the stated scope and add coverage for the URL-only behavior.
Summary
Firecrawl launched Keyless mode in June 2026,
allowing search and scrape calls without an API key — no account needed,
1,000 credits/month free. The cloud API accepts unauthenticated requests at the
same endpoints.
The Firecrawl Python SDK unconditionally requires
api_keyat construction,making it unsuitable for this mode. Rather than forking the SDK or adding a
stub key, this PR introduces a lightweight HTTP transport (
_KeylessFirecrawlClient)that mirrors the SDK's method signatures so the existing extract loop works
unchanged.
This builds on two recent Firecrawl provider improvements that this Keyless
client inherits naturally:
Firecrawl's clean markdown now goes straight to cache.
same extract path our Keyless client shares (salvage fix(web): re-check Firecrawl final URLs for SSRF #35840 by @zapabob).
With these in place, the missing piece for a true zero-setup experience is a
transport that works without credentials — which this PR adds.
Changes
plugins/web/firecrawl/provider.py— +56 lines1.
_KeylessFirecrawlClient(lines 77–121)httpx-based transport that calls
POST /v1/searchandPOST /v1/scrape.Implements
search(query, limit) -> dict/scrape(url, formats) -> dictwith the same surface as the SDK client, so the existing extract loop
(including the SSRF re-check from #56143) works unchanged.
2. Dispatch in
_get_firecrawl_client()(lines 305–313)When resolved kwargs contain no
api_key(i.e.FIRECRAWL_API_URLis setwithout
FIRECRAWL_API_KEY), returns a_KeylessFirecrawlClientinstead ofconstructing an SDK client.
No other changes required
_get_direct_firecrawl_config,check_firecrawl_api_key, andis_availableall already accept the
FIRECRAWL_API_URL-only config as valid — nomodifications needed.
Usage
Test Plan
taken when
api_keyis absent from kwargs; all existing configs withFIRECRAWL_API_KEYcontinue using the SDK path.Notes for Reviewers
api_keyat theconstructor level. Adding keyless support there would require an upstream
change in
firecrawl-py. This keeps the integration self-contained: ~45lines of transport code that can be cleanly removed if the SDK later
supports keyless natively.
httpx, which Hermes already depends on._KeylessFirecrawlClientfeeds into the same
_extract_scrape_payload/is_safe_url(final_url)pipeline.