curl -sSL …/hasdata-cli/main/install.sh | sh

Web scraping from
the command line

No model in the loop, just a command you call from a shell, a cron line or a CI step. It returns JSON and an exit code, and gets out of the way.

1,000 free credits. No credit card required.

57 data commands·free binary, no runtime·JSON or markdown out
bash — hasdata
$ hasdata google-maps --q "coffee shop" --ll "@30.2672,-97.7431,13z"
20 local results · 5 credits
Stouthaus Coffee - Sunset Valley(512) 721-00304.6 (772)
Terrible Love4.9 (417)
Hometown Coffee - East Austin4.9 (77)
$ echo $?
0
ClientsClients

Install one file. Set one key.

Every HasData API is a subcommand of one static binary, and the flags come from that API’s own schema, so there is no CLI dialect to learn. Each command answers on stdout in JSON, so a shell script or any other language reads it directly.

HasData/hasdata-cli
$ curl -sSL https://raw.githubusercontent.com/HasData/hasdata-cli/main/install.sh | sh
$ brew tap HasData/hasdata && brew install hasdata
Verifies SHA-256, detects OS and architecture itself.
$ hasdata configure # key → ~/.hasdata/config.yaml
$ hasdata google-serp --q "langchain vs llamaindex" --gl us --pretty
pretty JSON on a TTY, raw JSON in a pipe ~9 MB · no dependencies
WHERE THE KEY LIVES
1--api-key <key> a single call
2HASDATA_API_KEY CI
3~/.hasdata/config.yaml your machine
HOW IT EXITS
$ hasdata google-maps
error: required flag(s) "q" not set
$ echo $?
1
0 success1 user error2 network3 API 4xx4 API 5xx
Errors print to stderr with an error: prefix, so stdout stays clean JSON.
common flags
--api-keyOverride the configured API key
--pretty / --rawForce output formatting
-o, --output FILEWrite the response to a file
--verbosePrint request URL and rate-limit headers to stderr
--timeout, --retriesPer-request controls
--helpPer-command schema, endpoint and price
web-scraping · AI extraction
hasdata web-scraping \
--url "https://news.ycombinator.com" \
--ai-extract-rules-json '{"top_story":{"type":"string"}}'
...
"aiResponse": { "top_story": "llama.cpp" }
...
The -json variant takes a JSON string, a file path, or stdin.
zillow-listing
hasdata zillow-listing \
--keyword "Austin, TX" --type forSale \
--price-min 250000 --price-max 500000 \
--beds-min 3 --sort priceLowToHigh
Rich filters are just more flags, every one from the API's own schema.

The site changes. The command doesn't.

The flags are generated from each API's own parameters, so there is no CLI dialect to learn on top.

jqgoogle-maps
$ hasdata google-maps | jq -r '.localResults[] | [.title, .phone, .rating, .reviews] | @tsv'
Stouthaus Coffee - Sunset Valley(512) 721-00304.6772
Terrible Love4.9417
Hometown Coffee - East Austin4.977
Two shops list no phone in Maps, so it comes back as null, and the blank column is real, not dropped.
JSONstdout
{ "localResults": [ { "title": "Stouthaus Coffee - Sunset Valley", "phone": "(512) 721-0030", "rating": 4.6, "reviews": 772 }, { "title": "Terrible Love", "phone": null, "rating": 4.9, "reviews": 417 }, … 18 more ] }

Search, retail, property, jobs. One CLI for all of it.

Run hasdata --help and the whole list prints in your terminal. Each command's help carries its endpoint and the price of one call in credits.

All Scraper APIs
Search

Search, every surface of it

The Google results page, Light SERP, AI Mode, AI Overview, News, Shopping, Images, Events and short videos. Plus Bing and Trends.

positiontitlelinksnippet
Local & leads

Businesses, phone included

Google Maps places, reviews, author reviews, photos and posts. Plus Yelp and YellowPages.

phonewebsiteratingaddress
Listings & stays

Homes, stays and fares

Zillow, Redfin, Airbnb, Booking, Google Hotels, Google Flights.

pricebedsareadaysOnZillow
Commerce

Products and their sellers

Amazon search, product, seller and seller inventory. Plus Shopify.

currentPricebeforePrice
Video & social

Channels, posts and transcripts

YouTube search, video, channel and transcript. TikTok profile, posts and keyword search. Instagram.

viewslikesfollowersCounthashtags
Jobs

Openings and employers

Indeed for the openings, Glassdoor for the employers behind them.

companylocationsalarybenefits
Universal

Anything with a URL

Any public URL through the web-scraping command. Markdown for reading, or name the fields and get typed JSON. A site we don't parse out of the box is a custom scraper away.

markdowntextemailslinks

1,000 free credits is a finished job.

100 SERPs
the parsed page of Google, position to snippet
100 × 10 credits, the free tier exactly
~4,000 rows
Maps businesses, phones where Maps has them
200 pages × 5 credits · 20 per page
1,000 pages
read as clean markdown
1 credit each once you pass --js-rendering=false on a datacenter proxy
Free
$0 /mo
One-time free trial
1,000 credits to start
1,000 credits, one time
1 concurrent request
Pay only for successful requests
One balance across CLI and REST
Start free
Startup
$49 /mo
$0.24 / 1k credits
200K credits / month
200K credits / month
15 concurrent requests
Pay only for successful requests
One balance across CLI and REST
Get started
Business
Recommended
$99 /mo
$0.10 / 1k credits
1M credits / month
1M credits / month
30 concurrent requests
Pay only for successful requests
One balance across CLI and REST
Get started
Growth
$249 /mo
$0.08 / 1k credits
3M credits / month
50 concurrent requests
Pay only for successful requests
One balance across CLI and REST
Get started
Monthly credit volume
Free 1M 5M 20M 60M 100M
Best fit
Business
credits / mo
1M
Concurrency
30
$ / 1k credits
$0.10
$99 /mo
Get Started
Enterprise
Custom price based on required volume

Past 100M credits a month, or terms the self-serve plans do not cover. We shape the contract around your workload.

Credits rollover
Unused credits carry into the next billing period.
Concurrency 2000+
Parallel request limits set to your peak load.
#1 request priority
Highest speed, always first in the queue.
Personal manager
A direct line to the founding team.
SSO
SAML single sign-on for the whole team.
SOC-2 compliance
Security review, DPA, and audit reports.
Talk to sales Quote within one business day

Frequently asked
questions.

The short answers. Everything longer lives in the docs and on Discord.

How do I scrape a website from the command line?

Install the binary with curl -sSL .../install.sh | sh or brew install hasdata, run hasdata configure once to store the key, then call the command for the source you need. hasdata google-maps --q "coffee shop" --ll "@30.2672,-97.7431,13z" prints parsed JSON on stdout, so jq or any script reads it straight from the pipe. Proxies, rendering and parsing run on HasData’s side.

Is the binary free?

Yes. The tool costs nothing. Install it, read the source, script against it. Credits only start moving when a command fetches data, and you start with 1,000 free, no card.

What does a call cost?

Each command prints its own price. hasdata google-maps --help reads Cost: 5 credits per call. Web scraping is the one worth reading twice, because its help shows 10 for a rendered page while a plain read with no JS and a datacenter proxy costs 1. Specialized endpoints run up to 15, at the same rates as calling the API directly.

How many calls can I run in parallel?

One on the free tier, so a loop over a file runs sequentially. Paid plans start at 15 concurrent requests. Past your limit the API answers 429, and the CLI retries twice by default before it gives up. Failed calls are never charged.

Does the key have to sit in a file?

No. hasdata configure writes it to ~/.hasdata/config.yaml with 0600 permissions, but a flag beats the environment and the environment beats the file, so CI never needs the file at all. With no key anywhere the CLI stops before the network with error: no API key configured and exit code 1. A wrong key gets you 401 and exit code 3.

Can a script tell a refusal from a mistake?

The exit code says which. 1 means your flags are wrong, 3 means the API refused the call. Failed calls are never charged, so a script that exits 3 has spent nothing.

Does it update itself?

Only when you say so. hasdata update --check looks for a new release, hasdata update installs it. The CLI checks daily and notifies via stderr. It never updates without your consent.

When would I want the MCP server instead?

When a model should pick the tool. The CLI is for the opposite case, where you already know the call, and it runs from a shell, cron or CI with no model in the loop. Same endpoints, same balance either way.

One command away.

Web scraping from the command line, minus the infrastructure. No headless browsers, no proxy pools, no parsers to maintain, just JSON on stdout.

Get started → Documentation

One binary · 1,000 free credits · no card