A small Shodan API client and CLI built with Go's standard http.Client. It covers Internet search, host enrichment, DNS and certificate intelligence, vulnerability and exploit data, on-demand scanning, historical trends, and GeoNet measurements.
- Go 1.26.5 or later
- A Shodan API key in
SHODAN_API_KEY - The Shodan plan required by the endpoint you call
The client reads the API key when shodan.NewClient is created. Authenticated Shodan APIs receive it through the required key query parameter. Public APIs such as Certificate Transparency, CVEDB, and GeoNet do not receive the key, although the current shared client constructor still requires the environment variable.
$env:SHODAN_API_KEY = "your-api-key"
go install github.com/snowmerak/shodan/cmd/shodan@latest
shodan helpexport SHODAN_API_KEY="your-api-key"
go install github.com/snowmerak/shodan/cmd/shodan@latest
shodan helpMake sure the Go binary directory is in PATH. It is normally $(go env GOPATH)/bin on Linux and macOS, and $(go env GOPATH)\bin on Windows.
When working from a local clone, install the current checkout instead:
go install ./cmd/shodanYou can also run the CLI without installing it:
go run ./cmd/shodan help
go run ./cmd/shodan host "8.8.8.8"The main Shodan REST API searches service banners already collected by Shodan. A normal search does not connect to or scan the target.
Searchreturns matching service banners, up to 100 per page.Countreturns the total and facet summaries without banners or query-credit usage.HostInforeturns services and enrichment data observed for an IP.SearchFilters,SearchFacets, andSearchTokenshelp build and validate queries.Inforeturns plan and remaining-credit information.
Filtered searches and pages after the first can consume query credits. Use Count first when you only need to estimate result size.
shodan search -count "product:nginx country:KR"
shodan search "product:nginx country:KR"
shodan host "8.8.8.8"
shodan host -minify "8.8.8.8"
shodan host -history "8.8.8.8"Host lookups do not consume query credits, but the main API requires at least a Shodan Membership for IP lookups. Corporate plans can enrich up to 100 IPs in one request through the library:
hosts, err := client.HostInfoBulk(
ctx,
[]string{"8.8.8.8", "1.1.1.1"},
shodan.HostOptions{Minify: true},
)Domain DNSDB results cost one query credit per page. Forward and reverse DNS utilities use the same authenticated main API.
shodan dns domain "example.com"
shodan dns domain -type MX "example.com"
shodan dns domain -history -page 2 "example.com"
shodan dns resolve "example.com" "www.example.com"
shodan dns reverse "8.8.8.8" "1.1.1.1"The public Certificate Transparency API is hosted at ctl.shodan.io. These requests do not include the Shodan API key.
shodan certificate domain "example.com"
shodan certificate hostnames "example.com"
shodan certificate sha256 "e5e217863ae00d4f5cba5ef0b1714d652f7bc8ab6dd41ddbd5724d7a806f1642"To find Internet services on which a CT certificate was observed, use its SHA-256 fingerprint with the main search API:
result, err := client.Search(ctx, shodan.SearchOptions{
Query: `ssl.cert.fingerprint:"SHA256-FINGERPRINT"`,
Fields: []string{"ip_str", "port", "hostnames", "ssl.cert.subject", "ssl.cert.issuer"},
})CVEDB is a public API hosted at cvedb.shodan.io. It provides CVSS and EPSS data, CISA KEV status, affected CPEs, and EUVD references. The API key is not sent. Non-commercial use is free; commercial use requires an Enterprise license.
shodan vulnerability cve "CVE-2024-0204"
shodan vulnerability euvd "EUVD-2024-16003"
shodan vulnerability search -product "php" -kev -sort-epss -limit 10
shodan vulnerability search -cpe "cpe:2.3:a:php:php:8.0" -limit 10
shodan vulnerability count -product "php"
shodan vulnerability cpes -product "php" -limit 10The authenticated Exploits API at exploits.shodan.io/api searches integrated CVE, ExploitDB, and Metasploit data.
shodan exploit search -facets "source,type" "cve:CVE-2024-0204"
shodan exploit count -facets "platform,type" "platform:linux"The scanning API asks Shodan's crawlers to actively scan a public IP or CIDR. Each target IP consumes one scan credit. Only scan systems you own or have explicit permission to test.
Read-only commands:
shodan scan ports
shodan scan protocols
shodan scan list
shodan scan list -page 2
shodan scan status "<scan-id>"Submission commands require -execute to reduce accidental scans. Replace the documentation-only address below with a public target you are authorized to scan.
shodan scan submit -execute "198.51.100.10"
shodan scan service -execute `
-service "53:dns-udp" `
-service "443:https" `
"198.51.100.10"shodan scan submit -execute "198.51.100.10"
shodan scan service -execute \
-service "53:dns-udp" \
-service "443:https" \
"198.51.100.10"Scans are asynchronous. Use the returned ID with shodan scan status, then query HostInfo, Search, or the Streaming API after completion. This client intentionally does not expose the Internet-wide scan endpoint, which is limited to Enterprise Data customers and approved researchers.
The Enterprise Historical Data API at trends.shodan.io returns month-to-month search counts and optional monthly facet distributions. It does not return raw historical service banners.
shodan trends filters
shodan trends facets
shodan trends search -facets "country:10,org:5" "product:nginx"SearchTrends stores the month/count time series in Matches and the monthly top values in Facets. All three Trends endpoints require Enterprise access and authenticate with SHODAN_API_KEY.
The public GeoNet API at geonet.shodan.io runs DNS lookups or ICMP pings from Shodan nodes in multiple geographic regions. Requests do not include the API key. Non-commercial use is free, with a default public rate limit of one request per second.
shodan geonet dns "example.com"
shodan geonet dns -type AAAA "example.com"
shodan geonet ping "8.8.8.8"
shodan geonet ping "example.com"GeoDNS returns DNS answers and the measurement-node location for each region. GeoPing returns regional RTT, packet loss, and reachability. Unlike the main DNSDB API, GeoNet performs a current distributed measurement and does not search stored DNS history.
package main
import (
"context"
"log"
"time"
"github.com/snowmerak/shodan"
)
func main() {
client, err := shodan.NewClient()
if err != nil {
log.Fatal(err)
}
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
result, err := client.Search(ctx, shodan.SearchOptions{
Query: "product:nginx country:KR",
Facets: []string{"country", "org:10"},
Fields: []string{"ip_str", "port", "transport", "product", "org"},
})
if err != nil {
log.Fatal(err)
}
log.Printf("matches: %d", result.Total)
}The test suite uses local mock HTTP servers. It does not call live Shodan APIs or require a real API key.
go test ./...
go vet ./...