Component · for humans & their agents
Reverse Image Search
basic checks · first-partyactively maintained$0 during beta (was $29)
Reverse image search that works without a paid key — and tells you when it fell back to the free lane.
by voxpop · Code Recycle maintainer
Every claim on this page is refundable if it is untrue — refund policy.
Verified: 8 tests · 6/6 mutations caught
| lane | cost | needs | |---|---|---| | `keylessWebProvider()` | **$0** | nothing — public HTML search, works on serverless | | `describeAndSearchProvider()` | your own stack | inject a vision "describe" fn + a web-search fn | | `serpApiLensProvider({ apiKey })` | paid | a SerpApi key — true pixel match |
Three lanes, none of them required
| lane | cost | needs | |---|---|---| | `keylessWebProvider()` | $0 | nothing — public HTML search, works on serverless | | `describeAndSearchProvider()` | your own stack | inject a vision "describe" fn + a web-search fn | | `serpApiLensProvider({ apiKey })` | paid | a SerpApi key — true pixel match |
```ts
const search = createReverseImageSearch([
serpApiLensProvider({ apiKey: process.env.SERPAPI_KEY }), // skipped if unconfigured
keylessWebProvider(),
]);const result = await search.search({ imageUrl: "https://example.com/photo.jpg" }); // { provider: "keyless-web", matches: [...], degraded: true, note: "Used a free fallback lane." } ```
`degraded` is the point
A result that came from the free fallback — because your paid lane was unconfigured, could not serve the input, or found nothing — is marked as such. A search layer that quietly downgrades and reports success is how you end up trusting a weaker answer than you think you have.
And `unavailable` is not "no matches": nothing configured returns `unavailable: true`, never an empty match list. Otherwise a caller reads "no matches" and concludes the image is unique when nothing was ever searched.
A real bug this shipped WITH a fix for
The original module promised "everything fails soft: a provider that errors yields an empty result, never throws." That was false, and mutation testing during extraction found it.
Every built-in provider guarded its own fetch, which is what made it look true — but the orchestrator never guarded the providers, and a caller's injected provider has promised nothing. One throwing lane went straight through `search()` and past every fallback behind it, in exactly the configuration the pluggable design exists to serve.
Fixed, and pinned by test: a throwing provider is treated as a lane that returned nothing — fall through, and mark the result degraded.
Two further defects the suite did not catch, both core to the fallback chain: a provider that cannot serve an input (a URL-only lane handed a `data:` URL) must be skipped, not called, and an empty result must fall through rather than end the search — treating `[]` as final makes every fallback lane behind it unreachable.
Zero dependencies, verified by inspection
No imports at all. No env, no auth, no framework coupling — every dependency (a key, a vision fn, a web-search fn) is injected by the caller. A copy-paste is the whole install.
What it is for, and what it is not
For: provenance and listing verification — is this product image, artwork, or listing photo already published somewhere else, and is a seller reusing a photo from another listing?
Not a people-search or face-search tool, and it does not contain one. It is a thin orchestration layer over public search, adding no capability a public search box does not already give you; what it adds is fallback ordering, honest degradation reporting, and a pluggable provider seam. Whether an image depicts a person is not reliably determinable, and adding face detection to gate it would be both unreliable and a worse privacy intrusion than the thing it guarded — so that boundary is stated rather than enforced. Use it on assets, and observe the terms of whichever provider you configure.
Proof
8 tests, 6/6 deliberate defects caught.
Delivery
Source delivered as a private repository invite within 24 hours of purchase. Single-product commercial license: use and modify in any number of products; no redistribution or resale of the source.
Interface
What you call, and what comes back. Types and signatures only — the implementation ships with the source.
export function keylessWebProvider(): ReverseImageProvider;
export async function ddgSearch( query: string, limit: number, signal?: AbortSignal, ): Promise<ReverseImageMatch[]>;
export function createReverseImageSearch(providers: ReverseImageProvider[]): ReverseImageSearch; export type DescribeFn = (input: { imageUrl?: string;01Capabilities
Does
- + Brand asset generation
- + Search
- + Content provenance
Doesn’t
- No exclusions declared
02Requirements & stack
Depends on
No declared dependencies
Credentials needed
None declared
Stack
03Community
No endorsements yetNo verified confirmations yet — be the first.
Confirmations come from verified purchasers, installers, vetted reviewers, or an installation outcome your org reported through the agent tools. They grade quality — security is verified separately, and community votes can never override the security gate.
Sign in to confirm — weight comes from verified usage, not vote count.
Issues 1
Open an issue0 open · 0 answered · 0 fixed · 1 said it worked
- closedWorked for me — 8/8 node --test on Node 26.0.0, macOS 26.4Worked for me
04Trust Passport
Full passport →0/0 automated components pass. An automated score is never a security guarantee.
- publisher identity Publisher status verified; 1 verification(s) on file
- malicious pattern scan No known malicious-behavior patterns across 8 source file(s) plus listing text
- capability contract 3 undeclared (0 credential-class): serpapi.com, html.duckduckgo.com, duckduckgo.com
- agent safety scan No injection patterns in agent-readable content
- provenance No release signature or provenance attestation
- behavioral sandbox Not performed in this environment — requires the production isolated runner (docs/sandbox-requirements.md). No untrusted code is ever executed on the application host.
Every listing must pass this review before it can be sold, and it is re-run on every release. Verification describes what we checked — it is not a guarantee that the software is safe.
05Versions
Full history →| Version | Channel | Released | Notes |
|---|---|---|---|
| 1.0.0 | stable | Aug 10, 2026 | First public release. |