yandex-reverse-image-api
v0.0.1
Published
Yandex reverse image search API client: source pages, similar images, product matches and image OCR via ScrapingBee.
Maintainers
Readme
yandex-reverse-image-api
Yandex reverse image search for Node. Find where an image appears, what it looks like elsewhere, and what text is inside it.
npm install yandex-reverse-image-apiNode 16 or newer. One dependency, axios.
const { YandexReverseImage } = require('yandex-reverse-image-api');
const bee = new YandexReverseImage(process.env.SCRAPINGBEE_API_KEY);Key with 1,000 free credits: scrapingbee.com.
Run live on 2026-09-10 against two real images. Numbers below are recorded results.
Budget first: 75 credits a lookup
There is no cheap version of this. A 1 credit fetch of a reverse image URL comes back HTTP 200 with a 14,885 byte page titled Are you not a robot?, carrying Yandex SmartCaptcha. The status code says success. The stealth tier clears it and there is nothing usable in between, so plan on 75 credits per image, which is about 3,300 lookups on a 250,000 credit plan.
The API does no caching, and reverse image results for a fixed image barely move, so cache them on your side.
"Where else is this image being used?"
The job most people are here for.
const img = 'https://upload.wikimedia.org/wikipedia/commons/3/3c/Shaki_waterfall.jpg';
const matches = await bee.sites(img);
matches.length; // 37
matches[0];
// { domain: 'en.wikipedia.org',
// title: 'Shaki Waterfall - Wikipedia',
// description: 'Shaki Waterfall. ',
// url: 'https://en.wikipedia.org/wiki/Shaki_Waterfall?utm_medium=organic&utm_source=yandexsmartcamera',
// clean_url: 'https://en.wikipedia.org/wiki/Shaki_Waterfall',
// thumb: 'https://avatars.mds.yandex.net/i?id=eb74556e...',
// width: 960,
// height: 719,
// original_image: 'https://upload.wikimedia.org/.../960px-Shaki_waterfall.jpg' }Use clean_url, not url. Yandex bolts ?utm_medium=organic&utm_source=yandexsmartcamera onto every result, which wrecks deduplication if you compare raw strings. The client strips it and also makes thumb absolute, since Yandex hands it back protocol relative with a leading double slash.
width and height describe the copy hosted on that page rather than your input, so this is also how you locate the highest resolution version of an image in the wild.
"Which sites use it most?"
await bee.domains(img);
// { 'bestofarmenia.com': 2, 'armeniantrip.com': 2, 'yandex.ru': 2,
// 'hotel.am': 2, 'eastroute.com': 2, 'ug-ideal.ru': 2, ... }Deduplicated on clean_url first. This is usually the shape brand protection and counterfeit work actually needs.
"Is this image being reused with edits?"
(await bee.similar(img)).length; // 40 visually similar images
await bee.otherSizes(img); // { small_dups: [6], medium_dups: [6], large_dups: [6] }otherSizes groups the same image at other resolutions. similar is Yandex's visual neighbourhood, which is where crops and recolours show up.
"Is someone selling something with my image on it?"
(await bee.products(img)).length; // 0Zero on that test image, and correctly so: a landscape photograph has no shopping match. Product photos return real entries.
"What does the text in this image say?"
const o = await bee.ocr(img);
o.hasText; // false
o.plainText; // ''
o.blocks; // []
o.entities; // []hasText was false because a waterfall has no writing on it. The right answer, not a failure.
This is free on top of the search. OCR arrives in the same response as the default tab, so one 75 credit call gets you the matches and the text inside the image with no second step and no AI parameter.
"I got zero matches. Is that real?"
Run this before you believe a negative.
await bee.checkImage(img);
// { expired: false, width: 1024, height: 767, usable: true }Yandex downloads your image from the URL you pass before it searches anything. If its crawler cannot fetch the file, or the URL is a short lived derivative, you get a perfectly valid page with an empty result list and no error of any kind.
Three images, one configuration:
| Input | checkImage | Result |
|---|---|---|
| Wikimedia Commons full size JPEG | expired: false, 1024x767 | 37 sites, 40 similar, 5 tags |
| A Wikimedia thumb/ URL | expired: true | nothing |
| A nasa.gov PNG | expired: true, width 0 | nothing, pageSize: 0 |
usable: false with an empty list means the image never got searched. usable: true with an empty list means it genuinely has no matches. Skip the check and you cannot tell those apart, and you will file "no matches" against images Yandex never looked at.
Give it a stable, directly reachable, full size URL.
"How do the tabs work?"
Everything is one URL with one parameter swapped. The forms come from the live page's own navigation object, not from guesswork.
YandexReverseImage.tabUrl(img); // default tab
YandexReverseImage.tabUrl(img, 'similar');
YandexReverseImage.tabUrl(img, 'sites');
YandexReverseImage.tabUrl(img, 'products');Free, no request. Note the encoding is nested: your image URL is percent encoded inside the Yandex URL, which then goes into the API's own url parameter. That double layer is where hand written versions usually break.
"Can I just use CSS selectors?"
No, and this is worth knowing before you try. Yandex builds its result grid on the client and ships the payload inside data-state attributes as HTML escaped JSON. There are no result nodes in the delivered markup, so selectors and extraction rules both match nothing. This client finds those attributes, unescapes them, parses the JSON and reads the slice you asked for.
Yandex names every slice after CBIR, its term for content based image retrieval, which is why the internals are full of cbirSites, cbirOcr and cbirMarketProducts.
Cost
await bee.sites(img);
bee.lastCost; // 75
await bee.usage(); // free| Configuration | Credits | What you get | |---|---|---| | Auto mode | 1 | a CAPTCHA page | | Stealth proxy | 75 | actual results | | Validation error | 0 | nothing billed |
Stealth forces JavaScript rendering and cannot be combined with auto mode. Sending both returns HTTP 400 at no charge, which fails silently.
Each method is its own call, so nine methods on one image is 675 credits. ocr, tags, otherSizes and checkImage all read the default tab, so if you want several of those, fetch once and parse the slices locally for a single charge.
Elsewhere
Other visual search pages: Yandex images API, Yandex search API, Google reverse image API, Google Lens API, Bing reverse image search API, Bing images API, eBay image search API, Naver images API, Yahoo images API, Getty images scraper API, Google image scraper, website image API.
Features: JavaScript scenario for driving the upload widget instead of passing a URL, AI web scraping, screenshots, markdown scraper.
Tab by tab guide with the full state map: github.com/ScrapingBee/yandex-reverse-image-api.
License
MIT
