botid.darknetsearch.com, and the search uses that link to tell them apart from every other kind of leak.
The stealer-log search keeps only that content. It returns the leak entries whose stealer-log lines match your query. Each entry hands you the link to the bot record and any screenshot links next to it. You fetch those yourself, or export the resolved bot records as one file.
The other approaches read the same corpus differently. Raw Data shows stealer-log lines as raw content, mixed with every other kind of leak. The ULP feed and Filtered credentials flatten credentials into one row per account: a login or username, a password, and the website or server it was used on. In the dashboard, the Stealer Logs tile in Search → Search by Source runs this search for a domain. On Raw Data results, the Infected machines view counts and lists the same captures for a domain search.
Availability: every plan with a license in force.
Cost: no metered allowance. Each call made with an API key uses 1 call from your monthly API Calls allowance, and that includes every status poll and every results page. A call that does not return 2xx is refunded. See Rate limits.
Without a license in force, every endpoint on this page returns 403:
How it works
The search is asynchronous. You start it, poll it until it finishes, then read the results. Searches belong to the organization your API key acts as. Its task list and results are visible to that organization only. The query itself is not limited to domains you own: you can search for any domain, address or term. All four search endpoints are in the Leaks tag of the API reference.Write the query
query takes the same Lucene syntax as Raw Data, 3 to 1,024 characters. The default field is content. You can add clauses on createdAt, leakId, fileName and fileExtension, combine them with AND, OR and NOT, exclude a term with -, and give ranges as [from TO to].
The search reads only the lines that carry a
botid.darknetsearch.com link. Three rules decide which leak entries come back:
- A plain query must appear as written. With no field, operator or
-, the whole query must appear on one stealer-log line, ignoring case.john smithmatches a line that holdsjohn smith, not a line that holdsjohnandsmithapart. Quotes, wildcards (*,?) and prefixes for other fields are matched as literal text, so"john smith"andacme*return no entries. Write a phrase without quotes, or add a field clause or an operator so that word matching applies. - With fields or operators, any one word is enough. The full query selects the leak records. An entry is kept when at least one of the query’s free-text words appears on one of its stealer-log lines. Words after
NOTor-are not matched against lines. - Field clauses alone keep every stealer-log line. A query such as
createdAt:[2026-01-01 TO *]returns every entry with a stealer-log line in the records it selects.
Run a search
1
Start the search
stealer_logs_search takes one field, query.201 with the search task:id. org is your organization’s ID, returned as a string.2
Poll until it finishes
Fetch the task with
stealer_logs_search_task, passing its id in the path.status takes five values:The task carries two counts. Both read
0 until the search finishes:total_matched_records: the leak records that match your query and contain abotid.darknetsearch.comlink, counted before line matching.total_results: the entries you can read.
3
Read the results
Call Once the status is
stealer_logs_search_results with the task id as search_id.search_idis required. It is the integer taskidfrom step 1.pageis 1-based.sizedefaults to100, max1000.- Entries come back in the order they were saved, not by date.
- Raise
pageuntilnextisnull. ThenextandpreviousURLs point at an internal service, not atclient-api.leak.center, so don’t call them.
ready or incomplete_ready, the call returns only the status and an empty list. A failed search keeps returning this shape:ready or incomplete_ready, the entries sit one level deeper, at results.results:count is the number of entries across all pages.What each entry gives you
Each result is one leak entry, not one machine. Both entries above come from the same infected machine: they share onebotid_url. Group or de-duplicate by botid_url to count machines.
content: up to 1,000 characters of the entry, including the stealer-log lines that matched. Matched terms can be wrapped in<kaduu:h>and</kaduu:h>highlight tags.botid_url: the link to the machine’s full bot record, always in the formhttps://botid.darknetsearch.com/botid/<path>.json. It is the first such link incontent, andnullwhencontentholds no complete link.stealer_pics_urls: the screenshot links found incontent, without duplicates. Each has the formhttps://stealerpics.darknetsearch.com/pics/<file>and ends in.jpg,.jpeg,.png,.gifor.webp. The list can be empty.item_id: the leak entry. It appears once per search.file_nameandfile_extension: the file inside the leak that holds the entry.leak_id,leak_name,leak_source,leak_size,leak_tagsandcvss_score: the source leak.leak_publish_date,leak_discover_dateanditem_created_at: the leak’s publish and discovery dates, and when the entry was indexed. All three are strings.
Fetch the capture
The entry is an index row. The capture itself sits behindbotid_url and stealer_pics_urls, and you fetch each link yourself with a plain GET.
The bot record. GET the botid_url as the entry returned it. The response is JSON.
The screenshots.
GET each entry in stealer_pics_urls the same way.
A bot record holds plaintext passwords, session cookies and tokens. Show it only to the people who investigate, and keep it out of logs.
Export the captures
The StealerLogs export builds one file from a finished search. DarknetSearch fetches every bot record for you, so the file holds the full records, not the index entries. The export flow is the same for every service. Export result sets walks through it.1
Wait for the search to finish
Export only a search whose status is
ready or incomplete_ready. An export of a search that is still running ends FAILED.2
Find the service
list_export_services returns the catalog. Match the entry whose name is StealerLogs, and read its id. Service IDs differ between environments, so look the ID up rather than hard-coding it. The entry takes one argument, search_id, and the formats json, csv and xlsx.3
Create the export
create_export takes the service id, a type and the search’s search_id.4
Poll and download
Poll
get_export with the export id until status is COMPLETE, then fetch the file with download_export.-
One row per machine. Each distinct
botid_urlwhose bot record DarknetSearch could fetch becomes one row. Entries without abotid_urlare left out, and so are machines whose bot record could not be fetched. -
JSON rows carry the newest entry for the machine as
source, the link asbotidUrl, the full bot record asstealerLogData, and the screenshot links in that newest entry asscreenshotUrls. Links that appear only in the machine’s older entries are not included. For the full set, readstealer_pics_urlson each entry in the results. This row is shortened: -
CSV and XLSX flatten each bot record into these columns:
ip_address,hostname,username,os_version,domain,country,stealer_type,infection_path,install_date,malware_build,infected_pc_dir,extracted_at,malware_family,cloud_brand,stealer_confidence,file_count,file_total_bytes,credentials_total,passwords,usernames,credential_urls,credit_cards,tokens,cookie_domains,session_cookies,autofill,screenshot_urls,leak_id,leak_name,botid_url,created_atandfile_extension. List values are joined with;. Inpasswords,usernames,credential_urls,tokens,cookie_domainsandsession_cookies, a long list stops once its cell nears 32,000 characters and ends with the total count, as in... (840 total). The other list columns have no cap.screenshot_urlsholds the same links asscreenshotUrlsin JSON. -
A search with nothing to export gives a file with one row:
{"message": "No records found"}.
list_exports lists your export jobs. Filter it by status, type, services (comma-separated service IDs), from_date and to_date.
List past searches
stealer_logs_search_tasks returns your organization’s searches, newest first. Use it to pick up a search_id without running the search again.
page is 1-based. size defaults to 100, max 1000. Page it the same way as the results: raise page until next is null.
Errors
Handle API errors lists every error the API returns.
When to reach for it
Use stealer logs when the infected machine is what you need: its full bot record, its screenshots and everything else it held. When you need only the credentials, the other approaches are faster:- Check one credential from your own sign-up or login flow with Credential Check.
- Look up an identity or a website in the ULP feed.
- Track the domains your organization owns with Filtered credentials.
- Read the raw leaked text with Raw Data.