R Client for the 'VirusTotal' API
Overview
Provides a comprehensive R interface to the 'VirusTotal' API v3.0 https://docs.virustotal.com/, a Google service that analyzes files and URLs for viruses, worms, trojans and other malware. Features include file/URL scanning, domain categorization, passive DNS information, IP reputation analysis, IoC relationships, sandbox analysis, and comment/voting systems. Implements rate limiting, error handling, and response validation for robust security analysis workflows.
Breaking changes
- The HTTP layer moved from httr to httr2. Extra arguments (
...) to API functions are no longer forwarded tohttr::GET()/httr::POST()— they are ignored. Configure requests with options instead:virustotal.timeout(seconds, default 60),virustotal.max_tries(default 3),virustotal.requests_per_minute(default 4) andvirustotal.throttle(defaultTRUE). - Error conditions now carry an httr2 response object in
$responseinstead of an httr one. The condition classes themselves are unchanged. - Requires R >= 4.1.0. Dependencies httr, dplyr and base64enc were dropped; httr2, curl and openssl were added.
- Loading the package no longer copies
VIRUSTOTAL_API_KEYintoVirustotalToken. Both variables still work for this package, andset_key()sets both. But code that readsVirustotalTokendirectly no longer sees a key set only under the canonical name — includingrdomains::virustotal_cat(), which reports "VirusTotal API key not found" in that case. SettingVirustotalToken, or passing the key to that function directly, works as before.
Show all changes in 0.7.0Hide the rest of the changes in 0.7.0
New features
- Requests identify the package with a user agent, time out after a configurable limit, and retry transient failures (HTTP 429/503) honoring the server's
Retry-Afterheader. - Rate limiting moved from a hand-rolled sliding window that slept in-process to
httr2::req_throttle(); the "Rate limit reached. Waiting..." message is gone (httr2 waits silently), and premium keys can finally raise the pace viaoptions(virustotal.requests_per_minute=). download_file(),get_behaviour_html(),get_behaviour_evtx(),get_behaviour_pcap()andget_behaviour_memdump()now go through the shared HTTP core: they gain rate limiting, retries and the package's error classes, none of which applied to them before.- The API key is resolved lazily at call time.
VIRUSTOTAL_API_KEYis the canonical environment variable and wins when both are set;VirustotalTokenremains honored, andset_key()sets both. Loading the package no longer mutates environment variables. - A missing key now raises a
virustotal_auth_errorinstead of a barestop().
Bug fixes
- Network failures (DNS, refused connections, timeouts) now raise a
virustotal_errorinstead of escaping as a raw httr2 condition, sotryCatch(virustotal_error = )covers them as documented. - A 200 response with an empty or non-JSON body (a CDN interstitial during an incident, say) raises a
virustotal_errorcarrying the status code, rather than a bare jsonlite parse error. - A server's
Retry-Afteris capped at 60 seconds by default (options(virustotal.max_retry_wait=)). ARetry-After: 3600would otherwise have blocked the session for an hour before raising. - Extra arguments passed to API functions now warn instead of vanishing silently, so a typo such as
cursors =cannot leave a caller paginating the first page forever. virustotal_info()reports usage against the configured pace; it showed "used 10/4, remaining -6" for anyone who raisedvirustotal.requests_per_minute. Requests that reached the API and failed (404, 429) are now counted, since they spend quota.print()on a domain report showed the *vendors* who categorized the domain under the heading "Categories" —google.comreported "Categories: BitDefender, Forcepoint ThreatSeeker, Sophos, ..." The API keys that field by vendor and stores the category as the value, so it now prints the distinct categories ("search engines", ...), capped at five.
Housekeeping
- Removed the stale
CRAN-RELEASE/CRAN-SUBMISSIONfiles, a Travis-era encrypted API key with no decryption code, covrpage leftovers that shipped in the tarball, and a permanently-skipped integration test (replaced by one gated onVT_INTEGRATION=true). inst/CITATIONno longer reads aDatefield the DESCRIPTION never had.- Internal helpers no longer emit
message()/warning()chatter during normal operation.
From NEWS.md in the release
Install
Health
- OK13 OK2026-08-04
- NOTE12 OK, 1 NOTE2026-08-01
- OK13 OK2026-06-09
- WARNING12 OK, 1 WARNING2026-06-08
- OK14 OK2026-03-10
Documentation
- Help pages
- 91 (45 internal)includes a package overview page
- Examples that run
- 0%44 never run
- Exported functions with examples
- 79%
- Documented parameters
- 100%
- Return-value docs
- 100%
- Help pages citing references
- 48%
Downloads
Repository
- PRs merged (all time)
- 100%
- Median days to close, 50 most recently updated closed issues
- 0
- Median days to close, 50 most recently updated closed PRs
- 0
Stars over time
Forks over time
Releases over time
Issues over time
Commits over time
10 development-tooling and community-health practices detected across 7 families in the upstream repository
Checks run against github.com/themains/virustotal on 2026-10-11.
Show all practicesHide 3 practices
This repository shows signs of AI coding tools.
- Claude Codefirst seen 2025-09-02Seen in the repository: CLAUDE.mdNamed in .Rbuildignore: .claude, CLAUDE.mdPull request it wrote: opened by a project memberCommits: at least 4 crediting it in the message
- Claude Opus 53 commits · Aug 2026
- Claude Opus 5.51 commit · Sep 2026
Dependencies
Installing virustotal adds 16 packages (12 with compiled code, 6.4 MB of source tarballs). Heaviest: openssl 1.1 MB, jsonlite 1.0 MB, vctrs 1.0 MB.
Code & Tests
People & History
Pick two releases to compare their code metrics.
- RR 4.6.0 released · 2026-04-24
- 0.7.0Latest
- 0.6.02026-04-13 · diff ↗ ·
removed 1 export
add_commentsadded 12 exports
get_analysis, get_behaviour_evtx, get_behaviour_html, get_behaviour_memdump, get_behaviour_pcap, get_behaviour_report, get_file_behaviour_mitre_trees, get_file_behaviour_summary, get_file_behaviours, rescan_domain, rescan_ip, rescan_url - 0.5.02025-12-16 · diff ↗ ·
added 12 exports
is_api_key_configured, virustotal_auth_error, virustotal_domain_report, virustotal_error, virustotal_file_report, virustotal_file_scan, virustotal_info, virustotal_ip_report, virustotal_rate_limit_error, virustotal_url_scan, virustotal_validation_error, virustotal_version - 0.3.02025-09-03 · diff ↗ ·
added 13 exports
download_file, get_file_comments, get_file_download_url, get_file_relationships, get_file_upload_url, get_file_votes, get_url_comments, get_url_relationships, get_url_votes, post_file_comments, post_file_votes, post_url_comments, post_url_votes - RR 4.5.0 released · 2025-04-11
- RR 4.4.0 released · 2024-04-24
- RR 4.3.0 released · 2023-04-21
- RR 4.2.0 released · 2022-04-22
- 0.2.22021-11-04 · diff ↗ ·
added 11 exports
get_domain_comments, get_domain_info, get_domain_relationship, get_domain_votes, get_ip_comments, get_ip_info, get_ip_votes, post_domain_comments, post_domain_votes, post_ip_comments, post_ip_votes - RR 4.1.0 released · 2021-05-18
- RR 4.0.0 released · 2020-04-24
- RR 3.6.0 released · 2019-04-26
- RR 3.5.0 released · 2018-04-23
- 0.2.12017-05-01 · diff ↗
- RR 3.4.0 released · 2017-04-21
Package metadata
- First published
- 2016-06-02
- Total releases
- 8 / 10 yrs
- License
- MIT + file LICENSE OSI
- Minimum R
- ≥ 4.1.0
- Download size
- 269 KB
Cite
Cite this package
Run in R for the authors' preferred citation:
citation("virustotal")The package provides a citation file that builds its entry when R runs it. Run citation() to see it.
The repository also keeps a CITATION.cff.
Cite the R Observatory
For a number measured here: a download total, a coverage figure, an archival date.
From data release v2026-10-19, which the citation names so these numbers can be found later. More on citing and the projects behind them.