Skip to main content
A stealer log is what info-stealer malware takes from a machine it infects: saved browser passwords, cookies, autofill data, a system fingerprint and often screenshots. DarknetSearch indexes these captures with the rest of the leak corpus. Stealer-log lines carry a link to the infected machine’s full bot record on 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:
Plans and quotas explains license status.

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 smith matches a line that holds john smith, not a line that holds john and smith apart. Quotes, wildcards (*, ?) and prefixes for other fields are matched as literal text, so "john smith" and acme* 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 NOT or - 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.
1

Start the search

stealer_logs_search takes one field, query.
The call returns 201 with the search task:
Keep the 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 a botid.darknetsearch.com link, counted before line matching.
  • total_results: the entries you can read.
Poll every 10 seconds or slower. Each poll is one API call.
3

Read the results

Call stealer_logs_search_results with the task id as search_id.
  • search_id is required. It is the integer task id from step 1.
  • page is 1-based. size defaults to 100, max 1000.
  • Entries come back in the order they were saved, not by date.
  • Raise page until next is null. The next and previous URLs point at an internal service, not at client-api.leak.center, so don’t call them.
Until the search is ready or incomplete_ready, the call returns only the status and an empty list. A failed search keeps returning this shape:
Once the status is 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 one botid_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 form https://botid.darknetsearch.com/botid/<path>.json. It is the first such link in content, and null when content holds no complete link.
  • stealer_pics_urls: the screenshot links found in content, without duplicates. Each has the form https://stealerpics.darknetsearch.com/pics/<file> and ends in .jpg, .jpeg, .png, .gif or .webp. The list can be empty.
  • item_id: the leak entry. It appears once per search.
  • file_name and file_extension: the file inside the leak that holds the entry.
  • leak_id, leak_name, leak_source, leak_size, leak_tags and cvss_score: the source leak.
  • leak_publish_date, leak_discover_date and item_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 behind botid_url and stealer_pics_urls, and you fetch each link yourself with a plain GET.
Never send your API key to the capture hosts. botid.darknetsearch.com and stealerpics.darknetsearch.com take no credentials. DarknetSearch fetches them with a plain GET. Send X-API-Key only to client-api.leak.center. Before you fetch a link, check that it starts with https://botid.darknetsearch.com/botid/ or https://stealerpics.darknetsearch.com/pics/.
The bot record. GET the botid_url as the entry returned it. The response is JSON.
A bot record describes the whole machine, not just the line that matched. Its contents vary by stealer family, and any key can be missing. DarknetSearch reads these keys: 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.
What the file holds:
  • One row per machine. Each distinct botid_url whose bot record DarknetSearch could fetch becomes one row. Entries without a botid_url are 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 as botidUrl, the full bot record as stealerLogData, and the screenshot links in that newest entry as screenshotUrls. Links that appear only in the machine’s older entries are not included. For the full set, read stealer_pics_urls on 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_at and file_extension. List values are joined with ; . In passwords, usernames, credential_urls, tokens, cookie_domains and session_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_urls holds the same links as screenshotUrls in 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: Find leaked credentials compares all of them.

Endpoints